openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
SF_abstract_vector.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #ifndef _SF_ABSTRACT_VECTOR_H
5 #define _SF_ABSTRACT_VECTOR_H
6 
7 #include <mpi.h>
8 
9 #include <petscvec.h> // TODO: For scattering, VecScatter and friends
10 #include <petscis.h>
11 #include <petscsys.h> // TODO: For PETSC_COMM_WORLD
12 
13 #include "SF_container.h"
14 #include "SF_globals.h"
15 #include "SF_parallel_layout.h"
16 #include "SF_parallel_utils.h"
17 #include "mpi_utils.h"
18 #include "petsc_utils.h"
19 
20 #include "hashmap.hpp"
21 
22 namespace SF {
23 
24 // Forward declare the scattering class
25 class scattering;
26 
40 template<class T, class S>
42 
43  public:
44 
47 
49  int dpn = 0;
51 
53  virtual ~abstract_vector() = default;
54 
62  virtual void init(const meshdata<mesh_int_t, mesh_real_t>& imesh,
63  int idpn,
64  ltype inp_layout) = 0;
65 
71  virtual void init(const abstract_vector<T, S>& vec) = 0;
72 
81  virtual void init(T igsize, T ilsize, int idpn = 1, ltype ilayout = unset) = 0;
82 
92  inline std::tuple<T, T> init_common(const meshdata<mesh_int_t, mesh_real_t>& imesh,
93  int idpn,
94  ltype inp_layout)
95  {
96  mesh = &imesh;
97  dpn = idpn;
98  T N = 0, n = 0;
99 
100  switch(inp_layout) {
101  case algebraic:
102  N = static_cast<T>(mesh->pl.num_global_idx()) * static_cast<T>(dpn);
103  n = static_cast<T>(mesh->pl.num_algebraic_idx()) * static_cast<T>(dpn);
104  layout = algebraic;
105  break;
106 
107  case nodal:
108  N = static_cast<T>(mesh->l_numpts) * static_cast<T>(dpn);
109  MPI_Allreduce(MPI_IN_PLACE, &N, 1, opencarp::mpi_datatype<T>(), MPI_SUM, mesh->comm);
110  n = static_cast<T>(mesh->l_numpts) * static_cast<T>(dpn);
111  layout = nodal;
112  break;
113 
114  case elemwise:
115  N = static_cast<T>(mesh->g_numelem*dpn);
116  n = static_cast<T>(mesh->l_numelem*dpn);
117  layout = elemwise;
118  break;
119 
120  default: break;
121  }
122 
123  return std::tuple<T, T>(N, n);
124  }
125 
134  virtual void set(const vector<T>& idx, const vector<S>& vals, const bool additive = false, const bool local = false) = 0;
135 
144  virtual void set(const vector<T>& idx, const S val, const bool additive = false, const bool local = false) = 0;
145 
151  virtual void set(const S val) = 0;
152 
161  virtual void set(const T idx, const S val) = 0;
162 
170  virtual void get(const vector<T> & idx, S *out) = 0;
171 
179  virtual S get(const T idx) = 0;
180 
186  virtual void operator*=(const S sca) = 0;
187 
193  virtual void operator /= (const S sca) = 0;
194 
200  virtual void operator*=(const abstract_vector<T, S>& vec) = 0;
201 
208  virtual void add_scaled(const abstract_vector<T, S>& vec, S k) = 0;
209 
215  virtual void operator += (const abstract_vector<T,S> & vec) = 0;
216 
222  virtual void operator-=(const abstract_vector<T, S>& vec) = 0;
223 
229  virtual void operator+=(S c) = 0;
230 
236  virtual void operator=(const vector<S>& rhs) = 0;
237 
243  virtual void operator=(const abstract_vector<T, S>& rhs) = 0;
244 
252  virtual void shallow_copy(const abstract_vector<T, S>& v) = 0;
253 
261  virtual void deep_copy(const abstract_vector<T, S>& v) = 0;
262 
275  virtual void overshadow(const abstract_vector<T, S>& sub, bool member, int offset, int sz, bool share) = 0;
276 
282  virtual T lsize() const = 0;
283 
289  virtual T gsize() const = 0;
290 
297  virtual void get_ownership_range(T& start, T& stop) const = 0;
298 
306  virtual S* ptr() = 0;
307 
316  virtual const S* const_ptr() const = 0;
317 
326  virtual S* device_ptr() = 0;
327 
335  virtual void release_ptr(S*& p) = 0;
336 
344  virtual void const_release_ptr(const S*& p) const = 0;
345 
353  virtual void release_device_ptr(S*& p) = 0;
354 
360  virtual S mag() const = 0;
361 
367  virtual S sum() const = 0;
368 
374  virtual S min() const = 0;
375 
383  virtual S dot(const abstract_vector<T, S>& v) const = 0;
384 
390  virtual bool is_init() const = 0;
391 
397  virtual std::string to_string() const = 0;
398 
404  virtual bool equals(const abstract_vector<T,S> & rhs) const = 0;
405 
409  virtual void finish_assembly() = 0;
410 
418  virtual void forward(abstract_vector<T, S>& out, scattering &sc, bool add = false) = 0;
419 
427  virtual void backward(abstract_vector<T,S> & out, scattering &sc, bool add = false) = 0;
428 
435  virtual void apply_scattering(scattering& sc, bool fwd) = 0;
436 
445  inline size_t write_ascii(const char* file, bool write_header)
446  {
447  int size, rank;
448  MPI_Comm comm = this->mesh != NULL ? this->mesh->comm : PETSC_COMM_WORLD;
449  MPI_Comm_rank(comm, &rank);
450  MPI_Comm_size(comm, &size);
451  const MPI_Datatype mpi_t = opencarp::mpi_datatype<T>();
452 
453  T glb_size = this->gsize();
454  T loc_size = this->lsize();
455 
456  int err = 0;
457  FILE* fd = NULL;
458  long int nwr = 0;
459 
460  if(rank == 0) {
461  fd = fopen(file, "w");
462  if(!fd) err = 1;
463  }
464 
465  MPI_Allreduce(MPI_IN_PLACE, &err, 1, MPI_INT, MPI_MAX, comm);
466  if(err) {
467  treat_file_open_error(file, __func__, errno, false, rank);
468  return nwr;
469  }
470 
471  S* p = this->ptr();
472 
473  if(rank == 0) {
474  if(write_header)
475  fprintf(fd, "%jd\n", opencarp::printable_int(glb_size));
476 
477  for(T i=0; i<loc_size/this->dpn; i++) {
478  for(int j=0; j<this->dpn; j++)
479  nwr += fprintf(fd, "%f ", p[i*this->dpn+j]);
480  nwr += fprintf(fd, "\n");
481  }
482 
483  vector<S> wbuff;
484  for(int pid=1; pid < size; pid++)
485  {
486  T rsize;
487  MPI_Status stat;
488 
489  MPI_Recv(&rsize, 1, mpi_t, pid, SF_MPITAG, comm, &stat);
490  wbuff.resize(rsize);
491  MPI_Recv(wbuff.data(), rsize*sizeof(S), MPI_BYTE, pid, SF_MPITAG, comm, &stat);
492 
493  for(T i=0; i<rsize/this->dpn; i++) {
494  for(int j=0; j<this->dpn; j++)
495  nwr += fprintf(fd, "%f ", wbuff[i*this->dpn+j]);
496  nwr += fprintf(fd, "\n");
497  }
498  }
499  fclose(fd);
500  }
501  else {
502  MPI_Send(&loc_size, 1, mpi_t, 0, SF_MPITAG, comm);
503  MPI_Send(p, loc_size*sizeof(S), MPI_BYTE, 0, SF_MPITAG, comm);
504  }
505 
506  this->release_ptr(p);
507  MPI_Bcast(&nwr, 1, MPI_LONG, 0, comm);
508 
509  return nwr;
510  }
511 
519  template<typename V>
520  inline size_t write_binary(FILE* fd)
521  {
522  int size, rank;
523  MPI_Comm comm = this->mesh != NULL ? this->mesh->comm : PETSC_COMM_WORLD;
524  MPI_Comm_rank(comm, &rank); MPI_Comm_size(comm, &size);
525 
526  long int loc_size = this->lsize();
527  S* p = this->ptr();
528 
529  vector<V> buff(loc_size);
530  for(long int i=0; i<loc_size; i++) buff[i] = p[i];
531 
532  long int nwr = root_write(fd, buff, comm);
533 
534  this->release_ptr(p);
535  return nwr;
536  }
537 
539  template<typename V>
540  inline size_t write_binary(std::string file)
541  {
542  size_t nwr = 0;
543  MPI_Comm comm = this->mesh != NULL ? this->mesh->comm : PETSC_COMM_WORLD;
544  int rank; MPI_Comm_rank(comm, &rank);
545 
546  FILE* fd = NULL;
547  int error = 0;
548 
549  if(rank == 0) {
550  fd = fopen(file.c_str(), "w");
551  if(fd == NULL)
552  error++;
553  }
554 
555  MPI_Allreduce(MPI_IN_PLACE, &error, 1, MPI_INT, MPI_SUM, comm);
556 
557  if(error == 0) {
558  nwr = this->write_binary<V>(fd);
559  if(fd) fclose(fd);
560  }
561  else {
562  treat_file_open_error(file.c_str(), __func__, errno, false, rank);
563  }
564 
565  return nwr;
566  }
567 
568  template<typename V>
569  inline size_t read_binary(FILE* fd)
570  {
571  MPI_Comm comm = this->mesh != NULL ? this->mesh->comm : PETSC_COMM_WORLD;
572 
573  size_t loc_size = this->lsize();
574  S* p = this->ptr();
575  vector<V> buff(loc_size);
576 
577  size_t nrd = root_read(fd, buff, comm);
578 
579  for(size_t i=0; i<loc_size; i++)
580  p[i] = buff[i];
581 
582  this->release_ptr(p);
583 
584  return nrd;
585  }
586 
587  template<typename V>
588  inline size_t read_binary(std::string file)
589  {
590  MPI_Comm comm = mesh != NULL ? mesh->comm : PETSC_COMM_WORLD;
591 
592  size_t nrd = 0;
593  int rank; MPI_Comm_rank(comm, &rank);
594 
595  FILE* fd = NULL;
596  int error = 0;
597 
598  if(rank == 0) {
599  fd = fopen(file.c_str(), "r");
600  if(fd == NULL)
601  error++;
602  }
603 
604  MPI_Allreduce(MPI_IN_PLACE, &error, 1, MPI_INT, MPI_SUM, comm);
605 
606  if(error == 0) {
607  nrd = read_binary<V>(fd);
608  if(fd) fclose(fd);
609  }
610  else {
611  treat_file_open_error(file.c_str(), __func__, errno, false, rank);
612  }
613 
614  return nrd;
615  }
616 
617  inline size_t read_ascii(FILE* fd)
618  {
619  MPI_Comm comm = this->mesh != NULL ? this->mesh->comm : PETSC_COMM_WORLD;
620 
621  size_t loc_size = this->lsize();
622  S* p = this->ptr();
623 
624  size_t nrd = root_read_ascii(fd, p, loc_size, comm, false);
625  this->release_ptr(p);
626  return nrd;
627  }
628 
629  inline size_t read_ascii(std::string file)
630  {
631  MPI_Comm comm = this->mesh != NULL ? this->mesh->comm : PETSC_COMM_WORLD;
632  int rank; MPI_Comm_rank(comm, &rank);
633 
634  size_t nrd = 0;
635 
636  FILE* fd = NULL;
637  int error = 0;
638 
639  if(rank == 0) {
640  fd = fopen(file.c_str(), "r");
641  if(fd == NULL)
642  error++;
643  }
644 
645  MPI_Allreduce(MPI_IN_PLACE, &error, 1, MPI_INT, MPI_SUM, comm);
646 
647  if(error == 0) {
648  nrd = read_ascii(fd);
649  if(fd) fclose(fd);
650  }
651  else {
652  treat_file_open_error(file.c_str(), __func__, errno, false, rank);
653  }
654 
655  return nrd;
656  }
657 };
658 
659 
662 template<class T, class S>
663 inline bool is_init(const abstract_vector<T,S>* v)
664 {
665  return (v && v->is_init());
666 }
667 
668 
669 // TODO: This is a type of Vector and can most likely be integrated into the
670 // `abstract_vector` type in some way. Everything here and also in
671 // `SF_parallel_layout.h` probably need to be abstracted away, or made less
672 // PETSc specific?
681 {
682  public:
683  Vec b_buff;
684  VecScatter vec_sc;
685 
687 
689  scattering() : b_buff(NULL), vec_sc(NULL)
690  {}
691 
694  {
695  if(b_buff) PETSC_CHECK(VecDestroy(&b_buff));
696  if(vec_sc) PETSC_CHECK(VecScatterDestroy(&vec_sc));
697  }
704  template<class T, class S>
705  inline void forward(abstract_vector<T,S> & in, abstract_vector<T,S> & out, bool add = false)
706  {
707  in.forward(out, *this, add);
708  }
709 
716  template<class T, class S>
717  inline void backward(abstract_vector<T,S> & in, abstract_vector<T,S> & out, bool add = false)
718  {
719  in.backward(out, *this, add);
720  }
721 
728  template<class T, class S>
729  inline void operator()(abstract_vector<T,S> & v, bool fwd)
730  {
731  v.apply_scattering(*this, fwd);
732  }
733 };
734 
744 {
745  private:
748 
749  public:
762  template<class T> inline scattering*
764  const vector<T> & nbr_a,
765  const vector<T> & nbr_b,
766  const size_t gsize_a,
767  const size_t gsize_b,
768  const short dpn)
769  {
770  assert(_registry.count(spec) == 0);
771 
772  scattering* sc = new scattering();
773  _registry[spec] = sc;
774 
775  IS is_a, is_b;
776  vector<SF_int> idx_a(nbr_a.size() * dpn);
777  vector<SF_int> idx_b(nbr_b.size() * dpn);
778 
779  // we copy indexing into new containers because of dpn and also
780  // because of the implicit typecast between T and SF_int
781  for(size_t i=0; i<nbr_a.size(); i++)
782  for(short j=0; j<dpn; j++) idx_a[i*dpn+j] = nbr_a[i]*dpn+j;
783 
784  for(size_t i=0; i<nbr_b.size(); i++)
785  for(short j=0; j<dpn; j++) idx_b[i*dpn+j] = nbr_b[i]*dpn+j;
786 
787  PETSC_CHECK(ISCreateGeneral(PETSC_COMM_WORLD, idx_a.size(), idx_a.data(), PETSC_COPY_VALUES, &is_a));
788  PETSC_CHECK(ISCreateGeneral(PETSC_COMM_WORLD, idx_b.size(), idx_b.data(), PETSC_COPY_VALUES, &is_b));
789 
790  PETSC_CHECK(ISSetPermutation(is_b));
791 
792  Vec a;
793  PETSC_CHECK(VecCreateMPI(PETSC_COMM_WORLD, idx_a.size(), gsize_a*dpn, &a));
794  PETSC_CHECK(VecCreateMPI(PETSC_COMM_WORLD, idx_b.size(), gsize_b*dpn, &sc->b_buff));
795  PETSC_CHECK(VecSetFromOptions(a));
796  PETSC_CHECK(VecSetFromOptions(sc->b_buff));
797 
798  PETSC_CHECK(VecScatterCreate(a, is_a, sc->b_buff, is_b, &sc->vec_sc));
799 
800  PETSC_CHECK(VecDestroy(&a));
801  PETSC_CHECK(ISDestroy (&is_a));
802  PETSC_CHECK(ISDestroy (&is_b));
803 
804  sc->idx_a.assign(idx_a.begin(), idx_a.end());
805  sc->idx_b.assign(idx_b.begin(), idx_b.end());
806 
807  return sc;
808  }
809 
810 
816  template<class T> inline scattering*
818  const vector<T> & layout_a,
819  const vector<T> & layout_b,
820  const vector<T> & idx_a,
821  const vector<T> & idx_b,
822  const int rank,
823  const int dpn)
824  {
825  // scattering spec must not exist yet
826  assert(_registry.count(spec) == 0);
827 
828  // the local index sets have to be of equal size.
829  assert(idx_a.size() == idx_b.size());
830 
831  scattering* sc = new scattering();
832  _registry[spec] = sc;
833 
834  IS is_a, is_b;
835  Vec a;
836  vector<SF_int> sidx_a(idx_a.size() * dpn);
837  vector<SF_int> sidx_b(idx_b.size() * dpn);
838 
839  T lsize_a = layout_a[rank+1] - layout_a[rank];
840  T lsize_b = layout_b[rank+1] - layout_b[rank];
841  T gsize_a = layout_a[layout_a.size()-1];
842  T gsize_b = layout_b[layout_a.size()-1];
843 
844  // we copy indexing into new containers because of dpn and also
845  // because of the implicit typecast between T and SF_int
846  for(size_t i=0; i<idx_a.size(); i++)
847  for(short j=0; j<dpn; j++) sidx_a[i*dpn+j] = idx_a[i]*dpn+j;
848 
849  for(size_t i=0; i<idx_b.size(); i++)
850  for(short j=0; j<dpn; j++) sidx_b[i*dpn+j] = idx_b[i]*dpn+j;
851 
852  PETSC_CHECK(ISCreateGeneral(PETSC_COMM_WORLD, sidx_a.size(), sidx_a.data(), PETSC_COPY_VALUES, &is_a));
853  PETSC_CHECK(ISCreateGeneral(PETSC_COMM_WORLD, sidx_b.size(), sidx_b.data(), PETSC_COPY_VALUES, &is_b));
854 
855  PETSC_CHECK(VecCreateMPI(PETSC_COMM_WORLD, lsize_a*dpn, gsize_a*dpn, &a));
856  PETSC_CHECK(VecCreateMPI(PETSC_COMM_WORLD, lsize_b*dpn, gsize_b*dpn, &sc->b_buff));
857  PETSC_CHECK(VecSetFromOptions(a));
858  PETSC_CHECK(VecSetFromOptions(sc->b_buff));
859 
860  PETSC_CHECK(VecScatterCreate(a, is_a, sc->b_buff, is_b, &sc->vec_sc));
861 
862  PETSC_CHECK(VecDestroy(&a));
863  PETSC_CHECK(ISDestroy (&is_a));
864  PETSC_CHECK(ISDestroy (&is_b));
865 
866  sc->idx_a.assign(idx_a.begin(), idx_a.end());
867  sc->idx_b.assign(idx_b.begin(), idx_b.end());
868 
869  return sc;
870  }
871 
883  {
884  scattering* ret = NULL;
885 
886  // scattering must be present
887  if(_registry.count(spec))
888  ret = _registry[spec];
889 
890  return ret;
891  }
892 
896  inline void free_scatterings()
897  {
898  typename hashmap::unordered_map<quadruple<int>,scattering*>::iterator it;
899  for(it = _registry.begin(); it != _registry.end(); ++it) {
900  if(it->second) {
901  delete it->second;
902  it->second = NULL;
903  }
904  }
905  }
906 };
907 
908 
909 } // namespace SF
910 
911 
912 #endif // _SF_ABSTRACT_VECTOR_H
Basic containers.
#define SF_MPITAG
the MPI tag when communicating
Definition: SF_globals.h:15
Classes and algorithms related to the layout of distributed meshes.
Simple utility functions for parallel data.
size_t read_ascii(FILE *fd)
size_t read_binary(std::string file)
virtual void get(const vector< T > &idx, S *out)=0
virtual void apply_scattering(scattering &sc, bool fwd)=0
virtual S mag() const =0
virtual S * ptr()=0
virtual void operator-=(const abstract_vector< T, S > &vec)=0
virtual void release_ptr(S *&p)=0
virtual std::string to_string() const =0
virtual S min() const =0
virtual void operator*=(const abstract_vector< T, S > &vec)=0
virtual S sum() const =0
virtual T gsize() const =0
size_t write_ascii(const char *file, bool write_header)
virtual void init(T igsize, T ilsize, int idpn=1, ltype ilayout=unset)=0
size_t read_binary(FILE *fd)
virtual void operator/=(const S sca)=0
virtual void forward(abstract_vector< T, S > &out, scattering &sc, bool add=false)=0
virtual bool is_init() const =0
ltype layout
used vector layout (nodal, algebraic, unset)
virtual S * device_ptr()=0
virtual bool equals(const abstract_vector< T, S > &rhs) const =0
virtual void const_release_ptr(const S *&p) const =0
size_t read_ascii(std::string file)
virtual void operator=(const abstract_vector< T, S > &rhs)=0
virtual void deep_copy(const abstract_vector< T, S > &v)=0
size_t write_binary(std::string file)
write binary. Open file descriptor myself.
virtual void get_ownership_range(T &start, T &stop) const =0
virtual S get(const T idx)=0
virtual void set(const vector< T > &idx, const S val, const bool additive=false, const bool local=false)=0
virtual void shallow_copy(const abstract_vector< T, S > &v)=0
std::tuple< T, T > init_common(const meshdata< mesh_int_t, mesh_real_t > &imesh, int idpn, ltype inp_layout)
virtual void add_scaled(const abstract_vector< T, S > &vec, S k)=0
virtual void overshadow(const abstract_vector< T, S > &sub, bool member, int offset, int sz, bool share)=0
virtual void release_device_ptr(S *&p)=0
virtual void set(const S val)=0
virtual ~abstract_vector()=default
virtual void operator+=(const abstract_vector< T, S > &vec)=0
virtual void operator=(const vector< S > &rhs)=0
virtual void set(const T idx, const S val)=0
size_t write_binary(FILE *fd)
Write a vector to HD in binary. File descriptor is already set up.
virtual void backward(abstract_vector< T, S > &out, scattering &sc, bool add=false)=0
virtual T lsize() const =0
virtual void init(const abstract_vector< T, S > &vec)=0
int dpn
d.o.f. per mesh vertex; data is stored node-major (index = node*dpn + component).
virtual const S * const_ptr() const =0
virtual void set(const vector< T > &idx, const vector< S > &vals, const bool additive=false, const bool local=false)=0
virtual void operator*=(const S sca)=0
virtual void finish_assembly()=0
virtual void init(const meshdata< mesh_int_t, mesh_real_t > &imesh, int idpn, ltype inp_layout)=0
const meshdata< mesh_int_t, mesh_real_t > * mesh
the connected mesh
virtual void operator+=(S c)=0
virtual S dot(const abstract_vector< T, S > &v) const =0
overlapping_layout< T > pl
nodal parallel layout
Definition: SF_container.h:414
size_t l_numelem
local number of elements
Definition: SF_container.h:384
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
MPI_Comm comm
the parallel mesh is defined on a MPI world
Definition: SF_container.h:389
The scatterer registry class.
void free_scatterings()
Free the registered scatterings.
scattering * register_scattering(const quadruple< int > spec, const vector< T > &layout_a, const vector< T > &layout_b, const vector< T > &idx_a, const vector< T > &idx_b, const int rank, const int dpn)
Register a scattering.
scattering * register_permutation(const quadruple< int > spec, const vector< T > &nbr_a, const vector< T > &nbr_b, const size_t gsize_a, const size_t gsize_b, const short dpn)
Register a permutation scattering.
scattering * get_scattering(const quadruple< int > spec)
Access an previously registered scattering.
Container for a PETSc VecScatter.
vector< SF_int > idx_a
~scattering()
Destructor.
vector< SF_int > idx_b
scattering()
Constructor.
Vec b_buff
A buffer vector which also defines the parallel layout of the "b" side.
void operator()(abstract_vector< T, S > &v, bool fwd)
Apply the scattering on a data vector.
void forward(abstract_vector< T, S > &in, abstract_vector< T, S > &out, bool add=false)
Forward scattering.
VecScatter vec_sc
The scatterer.
void backward(abstract_vector< T, S > &in, abstract_vector< T, S > &out, bool add=false)
Backward scattering.
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
const T * end() const
Pointer to the vector's end.
Definition: SF_vector.h:113
void assign(InputIterator s, InputIterator e)
Assign a memory range.
Definition: SF_vector.h:146
const T * begin() const
Pointer to the vector's start.
Definition: SF_vector.h:101
T * data()
Pointer to the vector's start.
Definition: SF_vector.h:76
hm_int count(const K &key) const
Check if key exists.
Definition: hashmap.hpp:612
Classes similar to unordered_set and unordered_map, but with better performance.
Definition: dense_mat.hpp:19
void treat_file_open_error(const char *file, const char *caller, const int errnum, const bool do_exit, int rank)
treat a file open error by displaying the errnum string interpretation and the caller
Definition: SF_io_base.h:86
bool is_init(const abstract_vector< T, S > *v)
size_t root_read(FILE *fd, vector< V > &vec, MPI_Comm comm)
Read binary data into a vector.
size_t root_read_ascii(FILE *fd, vector< V > &vec, MPI_Comm comm, bool int_data)
Read binary data into a vector.
size_t root_write(FILE *fd, const vector< V > &vec, MPI_Comm comm)
Write vector data binary to disk.
std::intmax_t printable_int(T value)
Definition: mpi_utils.h:115