sandbox/Cyprien_Lemarechal/output_vtu_foreach.h

    Changes

    This function is borrowed from acastillo’s sandbox : output_vtu_foreach.h

    The addition is a function “time_output_test()” that can be called during the run to write a time-series collection of files, either in squential or MPI. The output file is a *.pvd file that can be read right away in Paraview to diplay each timestep saved with “output_vtu()”.

    The header / footer will be missing in restart / brut stop.

    An example here.

    #include <stdint.h>
    
    /*
    This function writes one XML VTK file per PID process of type unstructured grid
    (*.vtu) which can be read using Paraview. File stores scalar and vector fields
    defined at the center points. Results are recorded on binary format. If one writes
    one *.vtu file per PID process this function may be combined with
    output_pvtu() above to read in parallel. Tested in (quad- and oct-)trees
    using MPI. Also works with solids (when not using MPI).
    */
    
    void output_vtu_pid (scalar * list, vector * vlist, char * subname)
    {
      char name[80];
      sprintf(name, "%s.vtu", subname);
      FILE * fp = fopen(name, "w");
    
    #if defined(_OPENMP)
      int num_omp = omp_get_max_threads();
      omp_set_num_threads(1);
    #endif
    
      // This is to match the number of points and vertices when using periodic conditions
      scalar per_mask[];
      foreach(){
        per_mask[] = 1.;
        if (((Period.x) & (x + Delta > X0 + L0)))
          per_mask[] = 0.;
    #if dimension > 1
        if (((Period.y) & (y + Delta > Y0 + L0)))
          per_mask[] = 0.;
    #endif
    #if dimension > 2
        if (((Period.z) & (z + Delta > Z0 + L0)))
          per_mask[] = 0.;
    #endif
      }
    
      vertex scalar marker[];
      uint64_t no_points = 0, no_cells=0 ;
      foreach_vertex(){
        marker[] = _k;
        if is_vertex(cell)
          no_points += 1;
      }
      foreach()
        if (per_mask[])
          no_cells += 1;
    
    
      fputs ("<?xml version=\"1.0\"?>\n"
      "<VTKFile type=\"UnstructuredGrid\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt64\">\n", fp);
      fputs ("\t <UnstructuredGrid>\n", fp);
      fprintf (fp,"\t\t <Piece NumberOfPoints=\"%ld\" NumberOfCells=\"%ld\">\n", no_points, no_cells);
      fputs ("\t\t\t <CellData Scalars=\"scalars\">\n", fp);
    
      uint64_t count = 0;
      for (scalar s in list) {
        fprintf (fp,"\t\t\t\t <DataArray type=\"Float64\" Name=\"%s\" format=\"appended\" offset=\"%ld\"/>\n", s.name, count);
        count += (no_cells * sizeof (double)) +  sizeof (uint64_t);
      }
      for (vector v in vlist) {
        fprintf (fp,"\t\t\t\t <DataArray type=\"Float64\" Name=\"%s\" NumberOfComponents=\"3\"  format=\"appended\" offset=\"%ld\"/>\n", v.x.name, count);
        count += (3 * no_cells * sizeof (double)) +  sizeof (uint64_t);
      }
      fputs ("\t\t\t </CellData>\n", fp);
      fputs ("\t\t\t <Points>\n", fp);
      fprintf (fp,"\t\t\t\t <DataArray type=\"Float64\" NumberOfComponents=\"3\"  format=\"appended\" offset=\"%ld\"/>\n",count);
      fputs ("\t\t\t </Points>\n", fp);
      fputs ("\t\t\t <Cells>\n", fp);
      count += (3 * no_points * sizeof (double)) +  sizeof (uint64_t);
    
      #if dimension == 2
        uint8_t type=9, noffset=4;
      #elif dimension == 3
        uint8_t type=12, noffset=8;
      #endif
      uint64_t offset, connectivity[noffset];
    
      fprintf (fp,"\t\t\t\t <DataArray type=\"UInt64\" Name=\"offsets\" format=\"appended\" offset=\"%ld\"/>\n", count);
      count +=  (no_cells * sizeof (uint64_t)) + sizeof (uint64_t);
    
      fprintf (fp,"\t\t\t\t <DataArray type=\"UInt8\" Name=\"types\" format=\"appended\" offset=\"%ld\"/>\n", count);
      count +=  (no_cells * sizeof (uint8_t)) + sizeof (uint64_t);
    
      fprintf (fp,"\t\t\t\t <DataArray type=\"UInt64\" Name=\"connectivity\" format=\"appended\" offset=\"%ld\"/>\n", count);
      count +=  (no_cells * noffset * sizeof (uint64_t)) + sizeof (uint64_t);
    
      fputs ("\t\t\t </Cells>\n", fp);
      fputs ("\t\t </Piece>\n", fp);
      fputs ("\t </UnstructuredGrid>\n", fp);
      fputs ("\t <AppendedData encoding=\"raw\">\n", fp);
      fputs ("_", fp);
    
      uint64_t block_len=no_cells*sizeof (double);
    #if dimension == 2
      double vz=0;
    #endif
      for (scalar s in list) {
        fwrite (&block_len, sizeof (uint64_t), 1, fp);
        foreach()
          if (per_mask[])
            fwrite (&val(s), sizeof (double), 1, fp);
      }
      block_len=no_cells*3*sizeof (double);
      for (vector v in vlist) {
        fwrite (&block_len, sizeof (uint64_t), 1, fp);
        foreach(){
          if (per_mask[]){
            fwrite (&val(v.x), sizeof (double), 1, fp);
            fwrite (&val(v.y), sizeof (double), 1, fp);
    #if dimension == 2
            fwrite (&vz, sizeof (double), 1, fp);
    #elif dimension == 3
            fwrite (&val(v.z), sizeof (double), 1, fp);
    #endif
          }
        }
      }
      block_len=no_points*3*sizeof (double);
      fwrite (&block_len, sizeof (uint64_t), 1, fp);
      foreach_vertex(){
        fwrite (&x, sizeof (double), 1, fp);
        fwrite (&y, sizeof (double), 1, fp);
        fwrite (&z, sizeof (double), 1, fp);
      }
    
      block_len=no_cells*1*sizeof(uint64_t);
      fwrite (&block_len, sizeof (uint64_t), 1, fp);
      for (int i = 0; i < no_cells; i++){
        offset = (i+1)*noffset;
        fwrite (&offset, sizeof (int64_t), 1, fp);
      }
    
      block_len=no_cells*1*sizeof(uint8_t);
      fwrite (&block_len, sizeof (uint64_t), 1, fp);
      for (int i = 0; i < no_cells; i++)
        fwrite (&type, sizeof (int8_t), 1, fp);
    
      block_len=no_cells*noffset*sizeof(uint64_t);
      fwrite (&block_len, sizeof (uint64_t), 1, fp);
      foreach(){
        if (per_mask[]){
          connectivity[0] = (uint64_t)marker[];
          connectivity[1] = (uint64_t)marker[1];
          connectivity[2] = (uint64_t)marker[1,1];
          connectivity[3] = (uint64_t)marker[0,1];
      #if dimension == 3
          connectivity[4] = (uint64_t)marker[0,0,1];
          connectivity[5] = (uint64_t)marker[1,0,1];
          connectivity[6] = (uint64_t)marker[1,1,1];
          connectivity[7] = (uint64_t)marker[0,1,1];
      #endif
          fwrite (&connectivity, sizeof (uint64_t), noffset, fp);
        }
      }
      fputs ("\t\n", fp);
      fputs ("\t </AppendedData>\n", fp);
      fputs ("</VTKFile>\n", fp);
      fflush (fp);
    #if defined(_OPENMP)
      omp_set_num_threads(num_omp);
    #endif
      fclose (fp);
    }
    
    /*
    This function writes one XML file which allows to read the *.vtu files generated
    by output_vtu() when used in MPI. Tested in (quad- and oct-)trees
    using MPI.
    */
    
    @if _MPI
    void output_pvtu (scalar * list, vector * vlist, char * subname)
    {
      char name[80];
      FILE * fp;
      if (pid() == 0) {
        sprintf(name, "%s.pvtu", subname);
        fp = fopen(name, "w");
    
        fputs ("<?xml version=\"1.0\"?>\n"
        "<VTKFile type=\"PUnstructuredGrid\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt64\">\n", fp);
        fputs ("\t <PUnstructuredGrid GhostLevel=\"0\">\n", fp);
        fputs ("\t\t\t <PCellData Scalars=\"scalars\">\n", fp);
        for (scalar s in list) {
          fprintf (fp,"\t\t\t\t <PDataArray type=\"Float64\" Name=\"%s\" format=\"appended\">\n", s.name);
          fputs ("\t\t\t\t </PDataArray>\n", fp);
        }
        for (vector v in vlist) {
          fprintf (fp,"\t\t\t\t <PDataArray type=\"Float64\" NumberOfComponents=\"3\" Name=\"%s\" format=\"appended\">\n", v.x.name);
          fputs ("\t\t\t\t </PDataArray>\n", fp);
        }
        fputs ("\t\t\t </PCellData>\n", fp);
        fputs ("\t\t\t <PPoints>\n", fp);
        fputs ("\t\t\t\t <PDataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"appended\">\n", fp);
        fputs ("\t\t\t\t </PDataArray>\n", fp);
        fputs ("\t\t\t </PPoints>\n", fp);
    
        for (int i = 0; i < npe(); i++)
          fprintf (fp, "<Piece Source=\"%s_n%3.3d.vtu\"/> \n", subname, i);
    
        fputs ("\t </PUnstructuredGrid>\n", fp);
        fputs ("</VTKFile>\n", fp);
        fflush (fp);
        fclose (fp);
      }
      MPI_Barrier(MPI_COMM_WORLD);
    
      sprintf(name, "%s_n%3.3d", subname, pid());
      output_vtu_pid (list, vlist, name);
    }
    @endif
    
    trace
    void output_vtu (scalar * list, vector * vlist, char * subname)
    {
      @if _MPI
      output_pvtu (list, vlist, subname);
      @else
      output_vtu_pid (list, vlist, subname);
      @endif
    }

    This function writes a slice defined by n={n_x, n_y, n_z} and \alpha using a similar approach to view.h into one XML VTK file per PID process of type unstructured grid (*.vtu) in binary format which can be read using Paraview. Only works for x, y, and/or z planes. Here, _alpha is assumed to intersect a cell face and must be a multiple of L0/1<<MINLEVEL. This also means that scalar and vector fields are written at the corresponding face values.

    #if dimension > 2
    void output_vtu_plane_pid (scalar * list, vector * vlist, char * subname, coord n, double _alpha)
    {
      char name[80];
      sprintf(name, "%s.vtu", subname);
      FILE * fp = fopen(name, "w");
    
    #if defined(_OPENMP)
      int num_omp = omp_get_max_threads();
      omp_set_num_threads(1);
    #endif
    
      scalar per_mask[];
      foreach(){
        per_mask[] = 0.;
        double alpha = (_alpha - n.x*x - n.y*y - n.z*z)/Delta;
        if (fabs(alpha) > 0.87)
          continue;
    
        if (alpha > 0.)
          per_mask[] = 1.;
    
        if ((((Period.x) & (x + Delta > X0 + L0)) || ((Period.y) & (y + Delta > Y0 + L0))) || ((Period.z) & (z + Delta > Z0 + L0)))
          per_mask[] = 0.;
      }
    
      vertex scalar marker[];
      uint64_t no_points = 0, no_cells=0 ;
      foreach_vertex(){
        marker[] = 0.;
        double alpha = (_alpha - n.x*x - n.y*y - n.z*z)/Delta;
    
        if (fabs(alpha) > 0.87)
          continue;
    
        marker[] = no_points;
        no_points += 1;
      }
    
      foreach()
        if (per_mask[])
          no_cells += 1;
    
    
      fputs ("<?xml version=\"1.0\"?>\n"
      "<VTKFile type=\"UnstructuredGrid\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt64\">\n", fp);
      fputs ("\t <UnstructuredGrid>\n", fp);
      fprintf (fp,"\t\t <Piece NumberOfPoints=\"%ld\" NumberOfCells=\"%ld\">\n", no_points, no_cells);
      fputs ("\t\t\t <CellData Scalars=\"scalars\">\n", fp);
    
      uint64_t count = 0;
      for (scalar s in list) {
        fprintf (fp,"\t\t\t\t <DataArray type=\"Float64\" Name=\"%s\" format=\"appended\" offset=\"%ld\"/>\n", s.name, count);
        count += (no_cells * sizeof (double)) + sizeof (uint64_t);
      }
      for (vector v in vlist) {
        fprintf (fp,"\t\t\t\t <DataArray type=\"Float64\" Name=\"%s\" NumberOfComponents=\"3\"  format=\"appended\" offset=\"%ld\"/>\n", v.x.name, count);
        count += (3 * no_cells * sizeof (double)) + sizeof (uint64_t);
      }
      fputs ("\t\t\t </CellData>\n", fp);
      fputs ("\t\t\t <Points>\n", fp);
      fprintf (fp,"\t\t\t\t <DataArray type=\"Float64\" NumberOfComponents=\"3\"  format=\"appended\" offset=\"%ld\"/>\n", count);
      fputs ("\t\t\t </Points>\n", fp);
      fputs ("\t\t\t <Cells>\n", fp);
      count += (3 * no_points * sizeof (double)) + sizeof (uint64_t);
    
      uint8_t type=9, noffset=4;
      uint64_t offset, connectivity[noffset];
    
      fprintf (fp,"\t\t\t\t <DataArray type=\"UInt64\" Name=\"offsets\" format=\"appended\" offset=\"%ld\"/>\n", count);
      count +=  (no_cells * sizeof (uint64_t)) + sizeof (uint64_t);
    
      fprintf (fp,"\t\t\t\t <DataArray type=\"UInt8\" Name=\"types\" format=\"appended\" offset=\"%ld\"/>\n", count);
      count +=  (no_cells * sizeof (uint8_t)) + sizeof (uint64_t);
    
      fprintf (fp,"\t\t\t\t <DataArray type=\"UInt64\" Name=\"connectivity\" format=\"appended\" offset=\"%ld\"/>\n", count);
      count +=  (no_cells * noffset * sizeof (uint64_t)) + sizeof (uint64_t);
    
      fputs ("\t\t\t </Cells>\n", fp);
      fputs ("\t\t </Piece>\n", fp);
      fputs ("\t </UnstructuredGrid>\n", fp);
      fputs ("\t <AppendedData encoding=\"raw\">\n", fp);
      fputs ("_", fp);
    
      uint64_t block_len=no_cells*sizeof (double);
      for (scalar s in list) {
        fwrite (&block_len, sizeof (uint64_t), 1, fp);
        foreach(){
          if (per_mask[]){
            double sval;
            if (n.x == 1)
              sval = 0.5*(val(s) + val(s,1,0,0));
            else if (n.y == 1)
              sval = 0.5*(val(s) + val(s,0,1,0));
            else
              sval = 0.5*(val(s) + val(s,0,0,1));
            fwrite (&sval, sizeof (double), 1, fp);
          }
        }
      }
      block_len=no_cells*3*sizeof (double);
      for (vector v in vlist) {
        fwrite (&block_len, sizeof (uint64_t), 1, fp);
        foreach(){
          if (per_mask[]){
            double xval, yval, zval;
            if (n.x == 1) {
              xval = 0.5*(val(v.x) + val(v.x,1,0,0));
              yval = 0.5*(val(v.y) + val(v.y,1,0,0));
              zval = 0.5*(val(v.z) + val(v.z,1,0,0));
            }
            else if (n.y == 1) {
              xval = 0.5*(val(v.x) + val(v.x,0,1,0));
              yval = 0.5*(val(v.y) + val(v.y,0,1,0));
              zval = 0.5*(val(v.z) + val(v.z,0,1,0));
            }
            else {
              xval = 0.5*(val(v.x) + val(v.x,0,0,1));
              yval = 0.5*(val(v.y) + val(v.y,0,0,1));
              zval = 0.5*(val(v.z) + val(v.z,0,0,1));
            }
            fwrite (&xval, sizeof (double), 1, fp);
            fwrite (&yval, sizeof (double), 1, fp);
            fwrite (&zval, sizeof (double), 1, fp);
          }
        }
      }
      block_len=no_points*3*sizeof (double);
      fwrite (&block_len, sizeof (uint64_t), 1, fp);
      foreach_vertex(){
    
        double alpha = (_alpha - n.x*x - n.y*y - n.z*z)/Delta;
    
        if (fabs(alpha) > 0.87)
          continue;
    
        fwrite (&x, sizeof (double), 1, fp);
        fwrite (&y, sizeof (double), 1, fp);
        fwrite (&z, sizeof (double), 1, fp);
      }
    
      block_len=no_cells*1*sizeof(uint64_t);
      fwrite (&block_len, sizeof (uint64_t), 1, fp);
      for (int i = 0; i < no_cells; i++){
        offset = (i+1)*noffset;
        fwrite (&offset, sizeof (int64_t), 1, fp);
      }
    
      block_len=no_cells*1*sizeof(uint8_t);
      fwrite (&block_len, sizeof (uint64_t), 1, fp);
      for (int i = 0; i < no_cells; i++)
        fwrite (&type, sizeof (int8_t), 1, fp);
    
      block_len=no_cells*noffset*sizeof(uint64_t);
      fwrite (&block_len, sizeof (uint64_t), 1, fp);
      foreach(){
        if (per_mask[]){
          if (n.x == 1) {
            connectivity[0] = (uint64_t)marker[1,0,0];
            connectivity[1] = (uint64_t)marker[1,1,0];
            connectivity[2] = (uint64_t)marker[1,1,1];
            connectivity[3] = (uint64_t)marker[1,0,1];
          }
          else if (n.y == 1) {
            connectivity[0] = (uint64_t)marker[0,1,0];
            connectivity[1] = (uint64_t)marker[1,1,0];
            connectivity[2] = (uint64_t)marker[1,1,1];
            connectivity[3] = (uint64_t)marker[0,1,1];
          }
          else {
            connectivity[0] = (uint64_t)marker[0,0,1];
            connectivity[1] = (uint64_t)marker[1,0,1];
            connectivity[2] = (uint64_t)marker[1,1,1];
            connectivity[3] = (uint64_t)marker[0,1,1];
          }
          fwrite (&connectivity, sizeof (uint64_t), noffset, fp);
        }
      }
      fputs ("\t\n", fp);
      fputs ("\t </AppendedData>\n", fp);
      fputs ("</VTKFile>\n", fp);
      fflush (fp);
    #if defined(_OPENMP)
      omp_set_num_threads(num_omp);
    #endif
    }
    
    @if _MPI
    void output_pvtu_plane (scalar * list, vector * vlist, char * subname, coord n, double _alpha)
    {
      char name[80];
      FILE * fp;
      if (pid() == 0) {
        sprintf(name, "%s.pvtu", subname);
        fp = fopen(name, "w");
    
        fputs ("<?xml version=\"1.0\"?>\n"
        "<VTKFile type=\"PUnstructuredGrid\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt64\">\n", fp);
        fputs ("\t <PUnstructuredGrid GhostLevel=\"0\">\n", fp);
        fputs ("\t\t\t <PCellData Scalars=\"scalars\">\n", fp);
        for (scalar s in list) {
          fprintf (fp,"\t\t\t\t <PDataArray type=\"Float64\" Name=\"%s\" format=\"appended\">\n", s.name);
          fputs ("\t\t\t\t </PDataArray>\n", fp);
        }
        for (vector v in vlist) {
          fprintf (fp,"\t\t\t\t <PDataArray type=\"Float64\" NumberOfComponents=\"3\" Name=\"%s\" format=\"appended\">\n", v.x.name);
          fputs ("\t\t\t\t </PDataArray>\n", fp);
        }
        fputs ("\t\t\t </PCellData>\n", fp);
        fputs ("\t\t\t <PPoints>\n", fp);
        fputs ("\t\t\t\t <PDataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"appended\">\n", fp);
        fputs ("\t\t\t\t </PDataArray>\n", fp);
        fputs ("\t\t\t </PPoints>\n", fp);
    
        for (int i = 0; i < npe(); i++)
          fprintf (fp, "<Piece Source=\"%s_n%3.3d.vtu\"/> \n", subname, i);
    
        fputs ("\t </PUnstructuredGrid>\n", fp);
        fputs ("</VTKFile>\n", fp);
        fflush (fp);
        fclose (fp);
      }
      MPI_Barrier(MPI_COMM_WORLD);
    
      sprintf(name, "%s_n%3.3d", subname, pid());
      output_vtu_plane_pid (list, vlist, name, n, _alpha);
    }
    @endif
    
    trace
    void output_vtu_plane (scalar * list, vector * vlist, char * subname, coord n, double _alpha)
    {
      @if _MPI
      output_pvtu_plane (list, vlist, subname, n, _alpha);
      @else
      output_vtu_plane_pid (list, vlist, subname, n, _alpha);
      @endif
    }
    
    #endif

    Here are the additions

    void time_output (char * subname, char * newline, double timestep, int nb_file, int file_number)
    {
      char name[200], name2[200];
      FILE * fp;
      sprintf (name, "%s.pvd", subname);
      sprintf (name2, "%s.vtu", newline);
       
      if (file_number == 0) {
        fp = fopen (name, "w");
        fputs ("<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">\n", fp);
        fputs ("\t<Collection>\n", fp);
        fprintf (fp, "\t\t <DataSet timestep=\"%g\" file=\"%s\"/>\n", timestep, name2);
        fflush (fp);
        fclose (fp);
      }
    
      if (file_number < nb_file - 1 && file_number != 0) {
        fp = fopen (name, "a");
        fprintf (fp, "\t\t <DataSet timestep=\"%g\" file=\"%s\"/>\n", timestep, name2);
        fflush (fp);
        fclose (fp);
      }   
    
      if (file_number == nb_file-1 ) {
        fp = fopen(name, "a");
        fprintf (fp,"\t\t <DataSet timestep=\"%g\" file=\"%s\"/>\n", timestep,name2);
        fputs ("\t</Collection>\n", fp);
        fputs ("</VTKFile>\n", fp);
        fflush (fp);
        fclose (fp);
      }
    }
      
    void time_output_test (char * subname, char * newline, double timestep, int nb_file, int file_number)
    {
      char name[200], name2[200];
      FILE * fp;
      sprintf (name, "%s.pvd", subname);
          
      @if _MPI
      if (pid() == 0) {
        sprintf(name2, "%s.pvtu", newline);
         
        if (file_number == 0) {
          fp = fopen(name, "w");
          fputs ("<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">\n", fp);
          fputs ("\t<Collection>\n", fp);
          fprintf (fp, "\t\t <DataSet timestep=\"%g\" file=\"%s\"/>\n", timestep, name2);
          fflush (fp);
          fclose (fp);
        }
    
        if (file_number < nb_file - 1 && file_number != 0) {
          fp = fopen (name, "a");
          fprintf (fp, "\t\t <DataSet timestep=\"%g\" file=\"%s\"/>\n", timestep, name2);
          fflush (fp);
          fclose (fp);
        }
    		
        if (file_number == nb_file - 1) {
          fp = fopen(name, "a");
          fprintf (fp, "\t\t <DataSet timestep=\"%g\" file=\"%s\"/>\n", timestep, name2);
          fputs ("\t</Collection>\n", fp);
          fputs ("</VTKFile>\n", fp);
          fflush (fp);
          fclose (fp);
        }
      }
      MPI_Barrier (MPI_COMM_WORLD);
      
      @else
        time_output (subname, newline, timestep, nb_file, file_number);
      @endif
    }