sandbox/oystelan/output_surfaces.h

    Various output functions for extracting a surface from field data using the build in VOF PLIC surface or the isosurface reconstruction in bview Three different formats are supported: - .ply - .vtu - .vtp all of which can be loaded into Paraview. for the two later alternatives, field data may be added by using the functions with “_w_fielddata“. This is an updated version of the previous fractions_output.h

    Author: Oystein Lande Date: July 2019

    #include "geometry.h"
    #include "fractions.h"
    
    #if dimension == 1
    coord mycs (Point point, scalar c) {
        coord n = {1.};
        return n;
    }
    #elif dimension == 2
    # include "myc2d.h"
    #else // dimension == 3
    # include "myc.h"
    #endif

    This function outputs the VOF surface to a .ply file

    void output_ply (struct OutputFacets p)
    {
    
        #if defined(_OPENMP)
        int num_omp = omp_get_max_threads();
        omp_set_num_threads(1);
        #endif
        scalar c = p.c;
        face vector s = p.s;
        if (!p.fp) p.fp = stdout;
    
        // print header text
        fputs ("ply\n", p.fp);
        fputs ("format ascii 1.0\n", p.fp);
    
        int nverts = 0;
        int nfacets = 0;
    
        foreach()
            if (c[] > 1e-6 && c[] < 1. - 1e-6) {
                coord n;
                if (!s.x.i)
                    // compute normal from volume fraction
                    n = mycs (point, c);
                else {
                    // compute normal from face fractions
                    double nn = 0.;
                    foreach_dimension() {
                        n.x = s.x[] - s.x[1];
                        nn += fabs(n.x);
                    }
                    assert (nn > 0.);
                    foreach_dimension()
                        n.x /= nn;
                }
                double alpha = plane_alpha (c[], n);
    
                coord v[12];
                int m = facets (n, alpha, v, 1.);
                for (int i = 0; i < m; i++) {
                    nverts ++;
                }
                if (m > 0) {
                    nfacets ++;
                }
            }
    
            fprintf (p.fp, "element vertex %i\n", nverts);
            fputs ("property float x\n", p.fp);
            fputs ("property float y\n", p.fp);
            fputs ("property float z\n", p.fp);
            fprintf (p.fp, "element face %i\n", nfacets);
            fputs ("property list uchar int vertex_index\n", p.fp);
            fputs ("end_header\n", p.fp);
    
            int facet_num[nfacets];
    
            int ifacet = 0;
            int ivert = 0;
    
            foreach()
                if (c[] > 1e-6 && c[] < 1. - 1e-6) {
                    coord n;
                    if (!s.x.i)
                        // compute normal from volume fraction
                        n = mycs (point, c);
                    else {
                        // compute normal from face fractions
                        double nn = 0.;
                        foreach_dimension() {
                            n.x = s.x[] - s.x[1];
                            nn += fabs(n.x);
                        }
                        assert (nn > 0.);
                        foreach_dimension()
                            n.x /= nn;
                    }
                    double alpha = plane_alpha (c[], n);
    
                    coord v[12];
                    int m = facets (n, alpha, v, 1.);
                    for (int i = 0; i < m; i++) {
                        fprintf (p.fp, "%g %g %g\n",
                                 x + v[i].x*Delta, y + v[i].y*Delta, z + v[i].z*Delta);
                    }
                    if (m > 0) {
                        facet_num[ifacet] = m;
                        ifacet ++;
                    }
                }
    
                // print face list
                for (ifacet = 0; ifacet < nfacets; ifacet++) {
                    fprintf (p.fp, "%i ", facet_num[ifacet]);
                    for (int iv = 0; iv < facet_num[ifacet]; iv ++) {
                        fprintf (p.fp, "%i ", ivert);
                        ivert ++;
                    }
                    fputc ('\n', p.fp);
                }
    
                fflush (p.fp);
                #if defined(_OPENMP)
                omp_set_num_threads(num_omp);
                #endif
    }

    This function outputs the iso surface to a .ply file

    void output_ply_iso (struct OutputFacets p)
    {
    
        #if defined(_OPENMP)
        int num_omp = omp_get_max_threads();
        omp_set_num_threads(1);
        #endif
        scalar c = p.c;
        face vector s = p.s;
        if (!p.fp) p.fp = stdout;
    
        // print header text
        fputs ("ply\n", p.fp);
        fputs ("format ascii 1.0\n", p.fp);
    
        // Start by creating the vertex and normal field
        vertex scalar v[];
        foreach_vertex()
            v[] = (f[] + f[-1] + f[0,-1] + f[-1,-1] +
            f[0,0,-1] + f[-1,0,-1] + f[0,-1,-1] + f[-1,-1,-1])/8.;
    
        vector n[];
        foreach()
            foreach_dimension()
                n.x[] = (f[1] - f[-1])/(2.*Delta);
            boundary ((scalar *){n});
    
    
        // Loop through all surface cells
        // The point of this first round is to count the number of isosurface triangles
    
        int nverts = 0;
        int nfacets = 0;
        foreach(){
            //if (c[] > 1e-7 && c[] < 1. - 1e-7) {
            double val[8] = {
                v[0,0,0], v[1,0,0], v[1,0,1], v[0,0,1],
                v[0,1,0], v[1,1,0], v[1,1,1], v[0,1,1]
            };
            double t[5][3][3];
            int nt = polygonize (val, 0.5, t);
            nfacets += nt;
            nverts += nt*3;
        }
    
        fprintf (p.fp, "element vertex %i\n", nverts);
        fputs ("property float x\n", p.fp);
        fputs ("property float y\n", p.fp);
        fputs ("property float z\n", p.fp);
        fprintf (p.fp, "element face %i\n", nfacets);
        fputs ("property list uchar int vertex_index\n", p.fp);
        fputs ("end_header\n", p.fp);
    
    
        foreach(){
            //if (c[] > 1e-7 && c[] < 1. - 1e-7) {
    
            double val[8] = {
                v[0,0,0], v[1,0,0], v[1,0,1], v[0,0,1],
                v[0,1,0], v[1,1,0], v[1,1,1], v[0,1,1]
            };
            double t[5][3][3];
            int nt = polygonize (val, 0.5, t);
            for (int i = 0; i < nt; i++) {
                for (int j = 0; j < 3; j++) {
                    coord v = {t[i][j][0], t[i][j][1], t[i][j][2]}, np;
                    //foreach_dimension()
                    //np.x = interp (point, v, n.x);
                    //glNormal3d (np.x, np.y, np.z);
                    //color_vertex (p, interp (point, v, col));
                    //glvertex3d (view, x + v.x*Delta, y + v.y*Delta, z + v.z*Delta);
                    fprintf (p.fp, "%g %g %g\n",
                             x + v.x*Delta, y + v.y*Delta, z + v.z*Delta);
                }
            }
        }
    
        int ifacet = 0;
        int ivert = 0;
        // print face list
        for (ifacet = 0; ifacet < nfacets; ifacet++) {
            fprintf (p.fp, "%i ", 3);
            for (int iv = 0; iv < 3; iv ++) {
                fprintf (p.fp, "%i ", ivert);
                ivert ++;
            }
            fputc ('\n', p.fp);
        }
    
        fflush (p.fp);
        #if defined(_OPENMP)
        omp_set_num_threads(num_omp);
        #endif
    }

    This function outputs the VOF surface to a .vtu format file

    void output_vtu (struct OutputFacets p)
    {
        #if defined(_OPENMP)
        int num_omp = omp_get_max_threads();
        omp_set_num_threads(1);
        #endif
        scalar c = p.c;
        face vector s = p.s;
        if (!p.fp) p.fp = stdout;
    
        // print header text
        fputs ("<?xml version=\"1.0\"?>\n", p.fp);
        fputs ("<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n", p.fp);
        fputs ("  <UnstructuredGrid>\n", p.fp);
    
        int nverts = 0;
        int nfacets = 0;
    
        foreach()
            if (c[] > 1e-6 && c[] < 1. - 1e-6) {
                coord n;
                if (!s.x.i)
                    // compute normal from volume fraction
                    n = mycs (point, c);
                else {
                    // compute normal from face fractions
                    double nn = 0.;
                    foreach_dimension() {
                        n.x = s.x[] - s.x[1];
                        nn += fabs(n.x);
                    }
                    assert (nn > 0.);
                    foreach_dimension()
                        n.x /= nn;
                }
                double alpha = plane_alpha (c[], n);
    
                coord v[12];
                int m = facets (n, alpha, v, 1.);
                for (int i = 0; i < m; i++) {
                    nverts ++;
                }
                if (m > 0) {
                    nfacets ++;
                }
            }
    
            fprintf (p.fp, "    <Piece NumberOfPoints=\"%i\" NumberOfCells=\"%i\">\n", nverts, nfacets);
            fputs ("      <Points>\n", p.fp);
            fputs ("        <DataArray type=\"Float32\" Name=\"vertices\" NumberOfComponents=\"3\" format=\"ascii\">\n", p.fp);
    
            int offsets[nfacets];
    
            int ifacet = 0;
            int offset = 0;
    
            foreach()
                if (c[] > 1e-6 && c[] < 1. - 1e-6) {
                    coord n;
                    if (!s.x.i)
                        // compute normal from volume fraction
                        n = mycs (point, c);
                    else {
                        // compute normal from face fractions
                        double nn = 0.;
                        foreach_dimension() {
                            n.x = s.x[] - s.x[1];
                            nn += fabs(n.x);
                        }
                        assert (nn > 0.);
                        foreach_dimension()
                            n.x /= nn;
                    }
                    double alpha = plane_alpha (c[], n);
    
                    coord v[12];
                    int m = facets (n, alpha, v, 1.);
                    for (int i = 0; i < m; i++) {
                        fprintf (p.fp, "%g %g %g ",
                                 x + v[i].x*Delta, y + v[i].y*Delta, z + v[i].z*Delta);
                    }
                    if (m > 0) {
                        offset += m;
                        offsets[ifacet] = offset;
                        ifacet ++;
                    }
                }
    
    
                fputs ("        </DataArray>\n", p.fp);
                fputs ("      </Points>\n", p.fp);
                fputs ("      <Cells>\n", p.fp);
    
                fputs ("        <DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">\n", p.fp);
    
                // print vert numbers
                for (int ivert = 0; ivert < nverts; ivert++)
                    fprintf (p.fp, "%i ", ivert);
    
                fputs ("        </DataArray>\n", p.fp);
                fputs ("        <DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">\n", p.fp);
    
                // print offsets
                for (ifacet = 0; ifacet < nfacets; ifacet++)
                    fprintf (p.fp, "%i ", offsets[ifacet]);
    
                fputs ("        </DataArray>\n", p.fp);
                fputs ("        <DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">\n", p.fp);
    
                // print cell type list
                for (ifacet = 0; ifacet < nfacets; ifacet++)
                    fprintf (p.fp, "7 ");
    
                fputs ("        </DataArray>\n", p.fp);
                fputs ("      </Cells>\n", p.fp);
                fputs ("      <PointData>\n", p.fp);
                fputs ("      </PointData>\n", p.fp);
                fputs ("      <CellData>\n", p.fp);
                fputs ("      </CellData>\n", p.fp);
                fputs ("    </Piece>\n", p.fp);
                fputs ("  </UnstructuredGrid>\n", p.fp);
                fputs ("</VTKFile>\n", p.fp);
    
                fflush (p.fp);
                #if defined(_OPENMP)
                omp_set_num_threads(num_omp);
                #endif
    }
    
    
    struct OutputFacets_scalar {
        scalar c;
        FILE * fp;     // optional: default is stdout
        scalar * list;  // List of scalar fields to include when writing vtu surface to file
        vector * vlist; // List of vector fields to include.
        face vector s; // optional: default is none
    };

    Outputs VOF surface with fielddata in .vtu format

    void output_vtu_w_fielddata (struct OutputFacets_scalar p)
    {
        #if defined(_OPENMP)
        int num_omp = omp_get_max_threads();
        omp_set_num_threads(1);
        #endif
        scalar c = p.c;
        face vector s = p.s;
        if (!p.fp) p.fp = stdout;
    
        // print header text
        fputs ("<?xml version=\"1.0\"?>\n", p.fp);
        fputs ("<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n", p.fp);
        fputs ("\t<UnstructuredGrid>\n", p.fp);
    
        int nverts = 0;
        int nfacets = 0;
    
        foreach()
            if (c[] > 1e-6 && c[] < 1. - 1e-6) {
                coord n;
                if (!s.x.i)
                    // compute normal from volume fraction
                    n = mycs (point, c);
                else {
                    // compute normal from face fractions
                    double nn = 0.;
                    foreach_dimension() {
                        n.x = s.x[] - s.x[1];
                        nn += fabs(n.x);
                    }
                    assert (nn > 0.);
                    foreach_dimension()
                        n.x /= nn;
                }
                double alpha = plane_alpha (c[], n);
    
                coord v[12];
                int m = facets (n, alpha, v, 1.);
                for (int i = 0; i < m; i++) {
                    nverts ++;
                }
                if (m > 0) {
                    nfacets ++;
                }
            }
    
            fprintf (p.fp, "\t\t<Piece NumberOfPoints=\"%i\" NumberOfCells=\"%i\">\n", nverts, nfacets);
    
            // Write list of scalar field values to file
            fputs ("\t\t\t <CellData Scalars=\"scalars\">\n", p.fp);
            for (scalar s in p.list) {
                fprintf (p.fp,"\t\t\t\t <DataArray type=\"Float64\" Name=\"%s\" format=\"ascii\">\n", s.name);
                foreach(){
                    if (c[] > 1e-6 && c[] < 1. - 1e-6) {
                        fprintf (p.fp, "%g\n", val(s));
                    }
                }
                fputs ("\t\t\t\t </DataArray>\n", p.fp);
            }
            // Write list of vector field values to file
            for (vector v in p.vlist) {
                fprintf (p.fp,"\t\t\t\t <DataArray type=\"Float64\" NumberOfComponents=\"3\" Name=\"%s\" format=\"ascii\">\n", v.x.name);
                foreach(){
                    if (c[] > 1e-6 && c[] < 1. - 1e-6) {
                        #if dimension == 2
                        fprintf (p.fp, "%g %g 0.\n", val(v.x), val(v.y));
                        #endif
                        #if dimension == 3
                        fprintf (p.fp, "%g %g %g\n", val(v.x), val(v.y), val(v.z));
                        #endif
                    }
                }
                fputs ("\t\t\t\t </DataArray>\n", p.fp);
            }
            fputs ("\t\t\t </CellData>\n", p.fp);
    
    
            // Write points to file
            fputs ("      <Points>\n", p.fp);
            fputs ("        <DataArray type=\"Float32\" Name=\"vertices\" NumberOfComponents=\"3\" format=\"ascii\">\n", p.fp);
    
            int offsets[nfacets];
    
            int ifacet = 0;
            int offset = 0;
    
            foreach()
                if (c[] > 1e-6 && c[] < 1. - 1e-6) {
                    coord n;
                    if (!s.x.i)
                        // compute normal from volume fraction
                        n = mycs (point, c);
                    else {
                        // compute normal from face fractions
                        double nn = 0.;
                        foreach_dimension() {
                            n.x = s.x[] - s.x[1];
                            nn += fabs(n.x);
                        }
                        assert (nn > 0.);
                        foreach_dimension()
                            n.x /= nn;
                    }
                    double alpha = plane_alpha (c[], n);
    
                    coord v[12];
                    int m = facets (n, alpha, v, 1.);
                    for (int i = 0; i < m; i++) {
                        fprintf (p.fp, "%g %g %g ",
                                 x + v[i].x*Delta, y + v[i].y*Delta, z + v[i].z*Delta);
                    }
                    if (m > 0) {
                        offset += m;
                        offsets[ifacet] = offset;
                        ifacet ++;
                    }
                }
    
    
                fputs ("        </DataArray>\n", p.fp);
                fputs ("      </Points>\n", p.fp);
                fputs ("      <Cells>\n", p.fp);
    
                fputs ("        <DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">\n", p.fp);
    
                // print vert numbers
                for (int ivert = 0; ivert < nverts; ivert++)
                    fprintf (p.fp, "%i ", ivert);
    
                fputs ("        </DataArray>\n", p.fp);
                fputs ("        <DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">\n", p.fp);
    
                // print offsets
                for (ifacet = 0; ifacet < nfacets; ifacet++)
                    fprintf (p.fp, "%i ", offsets[ifacet]);
    
                fputs ("        </DataArray>\n", p.fp);
                fputs ("        <DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">\n", p.fp);
    
                // print cell type list
                for (ifacet = 0; ifacet < nfacets; ifacet++)
                    fprintf (p.fp, "7 ");
    
                fputs ("        </DataArray>\n", p.fp);
                fputs ("      </Cells>\n", p.fp);
                fputs ("      <PointData>\n", p.fp);
                fputs ("      </PointData>\n", p.fp);
                //fputs ("      <CellData>\n", p.fp);
                //fputs ("      </CellData>\n", p.fp);
                fputs ("    </Piece>\n", p.fp);
                fputs ("  </UnstructuredGrid>\n", p.fp);
                fputs ("</VTKFile>\n", p.fp);
    
                fflush (p.fp);
                #if defined(_OPENMP)
                omp_set_num_threads(num_omp);
                #endif
    }
    
    struct _interpolate_weighted {
      scalar v;
      scalar f;
      double x, y, z;
    };

    Experimental function for interpolating values with a “skewed” weight to one of the two phases

    static double interpolate_momentum_weighted (Point point, struct _interpolate_weighted p)
    {
      scalar v = p.v;
      scalar wmat = p.f;
    #if dimension == 1
      x = (p.x - x)/Delta - v.d.x/2.;
      int i = sign(x);
      x = fabs(x);
      double fsum = p.f[] + p.f[i];
      /* linear interpolation */
      return (v[]*(1. - x)*p.f[] + v[i]*x*p.f[i])/fsum;
    #elif dimension == 2
      x = (p.x - x)/Delta - v.d.x/2.;
      y = (p.y - y)/Delta - v.d.y/2.;
      int i = sign(x), j = sign(y);
      x = fabs(x); y = fabs(y);
    
      double fsum = p.f[] + p.f[i]+ p.f[0,j] + p.f[i,j];
      /* bilinear interpolation */
      return(((v[]*(1. - x)*p.f[] + v[i]*x*p.f[i])*(1. - y) +
    	  (v[0,j]*(1. - x)*p.f[0,j] + v[i,j]*x*p.f[i,j])*y))/fsum;
    #else // dimension == 3
      x = (p.x - x)/Delta - v.d.x/2.;
      y = (p.y - y)/Delta - v.d.y/2.;
      z = (p.z - z)/Delta - v.d.z/2.;
      int i = sign(x), j = sign(y), k = sign(z);
      x = fabs(x); y = fabs(y); z = fabs(z);
    
      double fsum = wmat[] + wmat[i] + wmat[0,j] + wmat[i,j] + wmat[0,0,k] + wmat[i,0,k] + wmat[0,j,k] + wmat[i,j,k];
      /* trilinear interpolation */
      return (((v[]*(1. - x)*wmat[] + v[i]*x*wmat[i])*(1. - y) +
    	   (v[0,j]*(1. - x)*wmat[0,j] + v[i,j]*x*wmat[i,j])*y)*(1. - z) +
    	  ((v[0,0,k]*(1. - x)*wmat[0,0,k] + v[i,0,k]*x*wmat[i,0,k])*(1. - y) +
    	   (v[0,j,k]*(1. - x)*wmat[0,j,k] + v[i,j,k]*x*wmat[i,j,k])*y)*z)/fsum;
    #endif
    }
    
    
    static inline double interp3_skewed (Point point, coord p, scalar col, scalar weights) {
      struct _interpolate_weighted _r = { col, weights, x + p.x*Delta, y + p.y*Delta, z + p.z*Delta };
      return interpolate_momentum_weighted (point, _r);
    }
    
    static inline double interp3 (Point point, coord p, scalar col) {
      struct _interpolate _r = { col, x + p.x*Delta, y + p.y*Delta, z + p.z*Delta };
      return interpolate_linear (point, _r);
    }

    Outputs ISO surface with fielddata in .vtp format

    void output_vtp_iso_w_fielddata (struct OutputFacets_scalar p)
    {
        #if defined(_OPENMP)
        int num_omp = omp_get_max_threads();
        omp_set_num_threads(1);
        #endif
        scalar c = p.c;
        //face vector s = p.s;
        if (!p.fp) p.fp = stdout;
    
        // print header text
        fputs ("<?xml version=\"1.0\"?>\n", p.fp);
        fputs ("<VTKFile type=\"PolyData\" version=\"0.1\" byte_order=\"LittleEndian\">\n", p.fp);
        fputs ("\t<PolyData>\n", p.fp);
    
        // Start by creating the vertex and smoothed normal field
        vertex scalar v[];
        foreach_vertex()
            v[] = (c[] + c[-1] + c[0,-1] + c[-1,-1] +
            c[0,0,-1] + c[-1,0,-1] + c[0,-1,-1] + c[-1,-1,-1])/8.;

    Loop through all surface cells * The point of this first round is to count the number of isosurface triangles. Should be improved…

        int nverts = 0;
        int nfacets = 0;
        foreach(){
            //if (c[] > 1e-7 && c[] < 1. - 1e-7) {
            double val[8] = {
                v[0,0,0], v[1,0,0], v[1,0,1], v[0,0,1],
                v[0,1,0], v[1,1,0], v[1,1,1], v[0,1,1]
            };
            double t[5][3][3];
            int nt = polygonize (val, 0.5, t);
            nfacets += nt;
            nverts += nt*3;
        }
    
        fprintf (p.fp, "\t\t<Piece NumberOfPoints=\"%i\" NumberOfPolys=\"%i\">\n", nverts, nfacets);
    
        fputs ("      <CellData>\n", p.fp);
        fputs ("      </CellData>\n", p.fp);
    
        // Write list of scalar field values to file
        fputs ("\t\t\t <PointData Normals=\"Normals\">\n", p.fp);
        for (scalar s in p.list) {
            fprintf (p.fp,"\t\t\t\t <DataArray type=\"Float32\" Name=\"%s\" format=\"ascii\">\n", s.name);
            foreach() {
    	      	// Rearranging v[]
    	      	double val[8] = {
    	      		v[0,0,0], v[1,0,0], v[1,0,1], v[0,0,1],
    	      		v[0,1,0], v[1,1,0], v[1,1,1], v[0,1,1]
    	     	 };
    	      	double t[5][3][3];
    	      	int nt = polygonize (val, 0.5, t);
    	      	for (int i = 0; i < nt; i++) {
    		      	for (int j = 0; j < 3; j++) {
    	      	  		coord v = {t[i][j][0], t[i][j][1], t[i][j][2]};
    	      	  		fprintf (p.fp, "%g\n", interp3 (point, v, s));
    	      		}
    	      	}
        	}
            fputs ("\t\t\t\t </DataArray>\n", p.fp);
        }
        // Write list of vector field values to file
        for (vector ve in p.vlist) {
            fprintf (p.fp,"\t\t\t\t <DataArray type=\"Float32\" NumberOfComponents=\"3\" Name=\"%s\" format=\"ascii\">\n", ve.x.name);
            foreach() {
    	      	// Rearranging v[]
    	      	double val[8] = {
    	      		v[0,0,0], v[1,0,0], v[1,0,1], v[0,0,1],
    	      		v[0,1,0], v[1,1,0], v[1,1,1], v[0,1,1]
    	     	 };
    	      	double t[5][3][3];
    	      	int nt = polygonize (val, 0.5, t);
    	      	for (int i = 0; i < nt; i++) {
    		      	for (int j = 0; j < 3; j++) {
    	      	  		coord v = {t[i][j][0], t[i][j][1], t[i][j][2]};
    	      	  		#if dimension == 2
    	                fprintf (p.fp, "%g %g 0.\n", interp3 (point, v, ve.x), interp3 (point, v, ve.y));
    	                #endif
    	                #if dimension == 3
    	                fprintf (p.fp, "%g %g %g\n", interp3 (point, v, ve.x), interp3 (point, v, ve.y), interp3 (point, v, ve.z));
    	                #endif
    	      	  		//fprintf (p.fp, "%g\n", interp3 (point, v, s));
    	      		}
    	      	}
        	}
            fputs ("\t\t\t\t </DataArray>\n", p.fp);
        }
        fputs ("\t\t\t </PointData>\n", p.fp);
    
    
        // Write points to file
        fputs ("      <Points>\n", p.fp);
        fputs ("        <DataArray type=\"Float32\" Name=\"vertices\" NumberOfComponents=\"3\" format=\"ascii\">\n", p.fp);
    
    
        foreach(){
            //if (c[] > 1e-7 && c[] < 1. - 1e-7) {
    
            double val[8] = {
                v[0,0,0], v[1,0,0], v[1,0,1], v[0,0,1],
                v[0,1,0], v[1,1,0], v[1,1,1], v[0,1,1]
            };
            double t[5][3][3];
            int nt = polygonize (val, 0.5, t);
            for (int i = 0; i < nt; i++) {
                for (int j = 0; j < 3; j++) {
                    coord v = {t[i][j][0], t[i][j][1], t[i][j][2]}, np;
    
                    fprintf (p.fp, "%g %g %g\n",
                             x + v.x*Delta, y + v.y*Delta, z + v.z*Delta);
                }
            }
        }
    
        fputs ("        </DataArray>\n", p.fp);
        fputs ("      </Points>\n", p.fp);
        fputs ("      <Polys>\n", p.fp);
    
        fputs ("        <DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">\n", p.fp);
    
        // print vert numbers
        for (int ivert = 0; ivert < nverts; ivert++)
            fprintf (p.fp, "%i ", ivert);
    
        fputs ("        </DataArray>\n", p.fp);
        fputs ("        <DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">\n", p.fp);
    
        // print offsets
        for (int ifacet = 0; ifacet < nfacets; ifacet++)
            fprintf (p.fp, "%i ", ifacet*3+3);
    
    
        fputs ("        </DataArray>\n", p.fp);
        fputs ("      </Polys>\n", p.fp);
        fputs ("    </Piece>\n", p.fp);
        fputs ("  </PolyData>\n", p.fp);
        fputs ("</VTKFile>\n", p.fp);
    
        fflush (p.fp);
        #if defined(_OPENMP)
        omp_set_num_threads(num_omp);
        #endif
    }