sandbox/Antoonvh/readxyz.h

    Read X-Y-Z formatted binary data.

    This function reades thee-dimensional (cubic N^3) data in file fname at level dlev (N = 2^{\mathrm{dlev}}) into the scalar field s.

    It works well and fast for large data sets and is compatible with MPI or OpenMP on Multigrid or full octrees Unfortuantely, it is limited to run on a single node. (use dump()->restore())

    The first function reads in data stored in so-called single precision

    int read_xyz_float(char * fname, scalar s, int dlev){
      unsigned long long int size = (1 << (dimension*dlev));

    The MPI parallel strategy requires special attention. We use the marvalous shared-memory functionality that is facilitated by modern MPI implementations.

    #if _MPI 
      MPI_Win win;
      float * a;

    The root allocated an array and a MPI window is created for the other ranks.

      if (pid() == 0){
        MPI_Win_allocate_shared (size*sizeof(float), sizeof(float), MPI_INFO_NULL,
    			    MPI_COMM_WORLD, &a, &win);
      }
      else{ // Slaves obtain the location of the pid()=0 allocated array    
        int disp_unit;
        MPI_Aint  ssize; 
        MPI_Win_allocate_shared (0, sizeof(float), MPI_INFO_NULL,
    			    MPI_COMM_WORLD, &a, &win);
        MPI_Win_shared_query (win, 0, &ssize, &disp_unit, &a);
      }
      MPI_Barrier (MPI_COMM_WORLD);

    The root is also tasked with reading all the data. Notice that this is quite fast because it reads contiguous data and true parallel IO is, well…

      if (pid() == 0){ 
        MPI_Win_lock (MPI_LOCK_EXCLUSIVE, 0, MPI_MODE_NOCHECK, win);
        FILE * fp = fopen (fname, "rb");
        fread (a, sizeof(float), size,fp);
        MPI_Win_unlock (0, win);
      }
      MPI_Barrier (MPI_COMM_WORLD);

    In serial, life is a bit easier.

    #else 
      float * a = (float*) malloc (sizeof(float)*size);
      FILE * fp = fopen (fname, "rb");
      fread (a, sizeof(float), size, fp);
    #endif

    We may need to take case of some specifics of MG parralelism and work with an offset.

    #if MULTIGRID_MPI 
      int nz = pid() % (mpi_dims[2]); 
      int ny = (pid()/mpi_dims[2]) % (mpi_dims[1]);
      int nx = pid()/(mpi_dims[2]*mpi_dims[1]);
      int nxoffset = ((1 << depth())*nx);
      int nyoffset = ((1 << depth())*ny);
      int nzoffset = ((1 << depth())*nz);
    #else // Non MG-MPI, no offset 
      int nxoffset = 0;
      int nyoffset = 0;
      int nzoffset = 0;
    #endif
      unsigned long long int CR = (1 << dlev);
      int o = -BGHOSTS - 1;
      unsigned long long int index;

    Loading the data itself is now straightforward

      foreach(){
        index = ((nxoffset + point.i + o) + (CR*(nyoffset + point.j + o)) + (sq(CR)*(nzoffset + point.k + o)));
        s[] = (double)a[index];
      }
      return 0;
    }

    This simular function reads double-precision data:

    int read_xyz_double (char * fname,scalar s,int dlev){
      unsigned long long int size= (1<<(dimension*dlev));
    #if _MPI
      MPI_Win win;
      double * a;
      if (pid() == 0){
        MPI_Win_allocate_shared(size*sizeof(double), sizeof(double), MPI_INFO_NULL,
    			    MPI_COMM_WORLD, &a, &win);
      }
      else{ // Slave    
        int disp_unit;
        MPI_Aint  ssize; 
        MPI_Win_allocate_shared(0, sizeof(double), MPI_INFO_NULL,
    			    MPI_COMM_WORLD, &a, &win);
        MPI_Win_shared_query(win, 0, &ssize, &disp_unit, &a);
      }
      MPI_Barrier(MPI_COMM_WORLD);
      if (pid() == 0){
        MPI_Win_lock(MPI_LOCK_EXCLUSIVE, 0, MPI_MODE_NOCHECK, win);
        FILE * fp = fopen(fname,"rb");
        fread(a,sizeof(double),size,fp);
        MPI_Win_unlock(0,win);
      }
      MPI_Barrier(MPI_COMM_WORLD);
    #else //not _MPI, life is easier
      double * a= (double*) malloc(sizeof(double)*size);
      FILE * fp = fopen(fname,"rb");
      fread(a,sizeof(double),size,fp);
    #endif
      
    #if MULTIGRID_MPI
      int nz = pid() % (mpi_dims[2]);
      int ny = (pid()/mpi_dims[2]) % (mpi_dims[1]);
      int nx = pid()/(mpi_dims[2]*mpi_dims[1]);
      unsigned long long int nxoffset = ((1<<depth())*nx);
      unsigned long long int nyoffset = ((1<<depth())*ny);
      unsigned long long int nzoffset = ((1<<depth())*nz);
    #else // Non MG-MPI, no offsets 
      int nxoffset = 0;
      int nyoffset = 0;
      int nzoffset = 0;
    #endif
      unsigned long long int CR = (1<<dlev);
      int o = -BGHOSTS-1;
      unsigned long long int ind;
      
      foreach(){
        ind =((nxoffset+point.i+o)+(CR*(nyoffset+point.j+o)) + (sq(CR)*(nzoffset+point.k+o)));
        s[]=a[ind];
      }
      return 0;
    }