ADCIRCtoF5.cpp

Convert ADCIRC ascii grid files and accompanying simulation output into F5. The levee information contained in the grid file is put into a specific triangular mesh for visualization purposes.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <hdf5.h>

#include <F5/F5X.h>
#include <F5/F5F.h>
#include <F5/F5B.h>
#include <F5/F5R.h>
#include <F5/F5coordinates.h>
#include <F5/F5surface.h>
#include <F5/F5defs.h>


#include <vector>
#include <string>
#include <iostream>

using namespace std;

/*
  TODO: Should really implement command line argument parsing,
        instead of reading hard-coded file names in the current
        directory.

        Data format can be found here:
        http://www.adcirc.org/documentv46/Output_file_descriptions.html
        .14 and .63 are interesting...
        .14 is given on cmd line it contains vertices and connectivity and more
        for the types see fort.14 description.

        Added number of time steps to be read as second a command line argument.
 */

void AppendSurfaceData( hid_t fileID, const string&gridname, 
                        const vector<F5_vec3_point_t>&Coords,
                        const vector<F5_triangle_t>&Triangles,
                        int time_steps_to_load) 
{
char    buf[2048];

double  time = 0; 
//FILE*kat63 = fopen("fortkat22.63", "rt"), 
//    *kat74 = fopen("fortkat22.74", "rt"); 
FILE*kat63 = fopen("fort.63", "rt"),
    *kat64 = fopen("fort.64", "rt"),
    *kat74 = fopen("fort.74", "rt"); 
FILE*elev = 0;

#ifdef  R_OK
        if (access("fort.63.gz", R_OK) == 0)
        {
                elev = popen("zcat fort.63.gz", "r"); 
                if (elev==0)
                        perror("Error in reading fort.63"); 
                else
                        fputs("Fine, could open fort63 file.\n", stderr);
        } 
#endif

        if (!(kat63 || kat74 || kat64|| elev))
        {
                fputs("No additional field information available.\n", stderr);
                return; 
        }


unsigned int    Timesteps = 0, Nodes = 0;


        // Skip the first 3 lines, ctj 
        if (kat63)
        {
                fgets(buf, sizeof(buf), kat63); 
                fprintf(stderr, buf ); 

                fgets(buf, sizeof(buf), kat63);
                sscanf(buf, "%d %d", &Timesteps, &Nodes);

                fgets(buf, sizeof(buf), kat63); 
                fprintf(stderr, buf );
        }
        if (kat64)
        {       
                fgets(buf, sizeof(buf), kat64); 
                fprintf(stderr, buf ); 

                fgets(buf, sizeof(buf), kat64); 
                sscanf(buf, "%d %d", &Timesteps, &Nodes);

                fgets(buf, sizeof(buf), kat64); 
                fprintf(stderr, buf );
        } 
        if (kat74)
        {       
                fgets(buf, sizeof(buf), kat74); 
                fprintf(stderr, buf ); 

                fgets(buf, sizeof(buf), kat74); 
                sscanf(buf, "%d %d", &Timesteps, &Nodes);

                fgets(buf, sizeof(buf), kat74); 
                fprintf(stderr, buf );
        } 
        if (elev)
        {       
                fgets(buf, sizeof(buf), elev); 
                fprintf(stderr, buf ); 

                fgets(buf, sizeof(buf), elev); 
                sscanf(buf, "  %d %d", &Timesteps, &Nodes); 
                //      fprintf(stderr, "----> %s (%d: t=%d, n=%d)\n",
                //      buf,i, Timesteps, Nodes ); 

                fgets(buf, sizeof(buf), elev); 
                fprintf(stderr, buf );
        } 


        fprintf(stderr,"ADCIRC Surface Data: %d time steps, %d vertices\n", Timesteps, Nodes); 
        if (Nodes != Coords.size() )
        {
                fputs("Vertices and Coordinates mismatch.", stderr); 
                return;
        } 

        if(time_steps_to_load > 0 && (unsigned)time_steps_to_load < Timesteps )
                Timesteps = time_steps_to_load;


vector<float>   Elevation; 
vector<F5_vec3f_t> Wind; 
vector<F5_vec3f_t> DepthAverageVelocity;

        if (kat63 || elev) Elevation.resize( Coords.size() ); 
        if (kat74)         Wind.resize( Coords.size() ); 
        if (kat64)  DepthAverageVelocity.resize( Coords.size() );

F5Path*FirstSurface = 0;
        for(unsigned tstep=0; tstep < Timesteps; tstep++)
        {
                // Time unit is minutes since... driving MM5 data start.
                // one time step is 30 mins
        double  Time = time + 30*tstep; 
                fprintf(stderr, "Timestep %d -> t=%lg\n", tstep, Time); 

        F5Path *myGrid;
                if (!FirstSurface)
                {
                        FirstSurface = F5write_triangular_surface(fileID, Time, 
                                                                  gridname.c_str(),
                                                                  &Coords[0],  Coords.size(),
                                                                  &Triangles[0], Triangles.size() ); 
                        myGrid = FirstSurface;
                } 
                else
                        myGrid = F5Flink_triangular_surface(FirstSurface, Time,
                                                            gridname.c_str(),
                                                            0, Coords.size(), // share vertices
                                                            0, Triangles.size() // share triangles
                                                            );

                if (kat63)
                {
                        for(unsigned int i=0; i<Coords.size(); i++)
                        {
                        int     num;
                                fgets(buf, sizeof(buf), kat63); 
                                if ( sscanf(buf, "%d %g\n", &num, &Elevation[i] ) != 2 )
                                {
                                        fprintf(stderr, "Error can't find scalar value for vertex %d\n", i ); 
                                        return;
                                } 

                                // ??? No idea what this is good for ???
                                if ( Elevation[i] < -3333 ) Elevation[i] = 0.0; 
                        } 
                        fgets(buf, sizeof(buf), kat63); 

                        F5Fwrite_1D(myGrid, "height", Coords.size(),
                                    H5T_NATIVE_FLOAT, H5T_NATIVE_FLOAT,
                                    &Elevation[0], F5P_DEFAULT);
                }

                if (elev)
                {
                        for(unsigned i=0; i<Coords.size(); i++)
                        {unsigned
                        int     num;
                                fgets(buf, sizeof(buf), elev); 
                                if ( sscanf(buf, "%d %g\n", &num, &Elevation[i] ) != 2 )
                                {
                                        fprintf(stderr, "Error can't find scalar value for vertex %d\n", i ); 
                                        return;
                                }

                                // ??? No idea what this is good for ???
                                //if ( Elevation[i] < -3333 ) Elevation[i] = 0.0; 
                                if (num != i+1)
                                        fprintf(stderr, "Index mismatch: %s\n", buf);
                        } 
                        fgets(buf, sizeof(buf), elev); 

                        F5Fwrite_1D(myGrid, "elevation", Coords.size(),
                                    H5T_NATIVE_FLOAT, H5T_NATIVE_FLOAT,
                                    &Elevation[0], F5P_DEFAULT);
                }


                if (kat74)
                {
                        for(unsigned int i=0; i<Coords.size(); i++)
                        {
                        int     num;
                                fgets(buf, sizeof(buf), kat74); 
                                if ( sscanf(buf, "%d %g %g\n", &num, &Wind[i].x, &Wind[i].y ) != 3 )
                                {
                                        fprintf(stderr, "Error can't find vector value for vertex %d\n", i ); 
                                        return;
                                } 
                                Wind[i].z = 0.0;
                        } 
                        fgets(buf, sizeof(buf), kat74); 

                        F5Fwrite_1D(myGrid, "wind", Coords.size(),
                                    F5T_VEC3_FLOAT, F5T_VEC3_FLOAT,
                                    &Wind[0], F5P_DEFAULT);
                } 

                if (kat64)
                {
                        for(unsigned int i=0; i<Coords.size(); i++)
                        {
                        int     num;
                                fgets(buf, sizeof(buf), kat64); 
                                if ( sscanf(buf, "%d %g %g\n", &num, 
                                            &DepthAverageVelocity[i].x, 
                                            &DepthAverageVelocity[i].y ) != 3 )
                                {
                                        fprintf(stderr, "Error can't find vector value for vertex %d\n", i ); 
                                        return;
                                } 
                                DepthAverageVelocity[i].z = 0.0;
                        } 
                        fgets(buf, sizeof(buf), kat64); 

                        F5Fwrite_1D(myGrid, "depth average velocity", Coords.size(),
                                    F5T_VEC3_FLOAT, F5T_VEC3_FLOAT,
                                    &DepthAverageVelocity[0], F5P_DEFAULT);
                } 


                if (myGrid != FirstSurface)
                        F5Fclose( myGrid );
        } 
        F5Fclose(FirstSurface);

        if (kat63) fclose(kat63); 
        if (kat74) fclose(kat74); 
        if (kat64) fclose(kat64);

        if (elev) pclose(elev);
}


void flip(const vector<F5_vec3_point_t>&Coords, F5_triangle_t &T)
{
F5_vec3_point_t
        A = Coords[T.i],
        B = Coords[T.j],
        C = Coords[T.k],

        BA = { B.x - A.x, B.y - A.y, B.z - A.z },
        CA = { C.x - A.x, C.y - A.y, C.z - A.z };

double  zDir = BA.x*CA.y - CA.x*BA.y;

        if (zDir < 0)
        {
        int     tmp = T.j;
                T.j = T.k;
                T.k = tmp;
        }
}

double zDir(const vector<F5_vec3_point_t>&Coords, F5_triangle_t &T)
{
F5_vec3_point_t
        A = Coords[T.i],
        B = Coords[T.j],
        C = Coords[T.k],

        BA = { B.x - A.x, B.y - A.y, B.z - A.z },
        CA = { C.x - A.x, C.y - A.y, C.z - A.z };

double  zDir = BA.x*CA.y - CA.x*BA.y; 

        return zDir;
}

void flip(F5_triangle_t &T)
{
int     tmp = T.j; 
        T.j = T.k; 
        T.k = tmp;
}


int     main(int argc, char*argv[])
{
        double  time = 0.0;
        hid_t   fileID;
        string  gridname;
        char    buf[1024]; 
        int     nCoords = 0, 
                nTriangles = 0;
        FILE*what; 

        int time_steps_to_load = -1;

        if (argc<2)
        {
                puts("Usage: ADCIRCtoF5 <inputfile.grd> <number of time steps>"); 
                puts("Time step argument may be ommitted to convert all time steps");
                return 1;
        } 

        if (argc > 2)
        {
                time_steps_to_load = atoi(argv[2]); 
        }

/*      putenv("F5_VERBOSITY=30");*/

        strcpy(buf, argv[1]);
        {
        char*c = strrchr(buf, '.');
                if (c)
                {
                        *c = 0;
                        strcat(c, ".f5");
                        fileID = H5Fcreate(buf,       /* The FileName */
                                           H5F_ACC_TRUNC,    /* Creation Flags */
                                           H5P_DEFAULT,      /* File creation property list identifier */
                                           H5P_DEFAULT);     /* File access property list identifier */
                }
                else
                {
                        puts("invalid filename.");
                        return 3;
                }
                *c = 0;
                gridname = buf;
        }


        what = fopen(argv[1], "rt");
        if (!what)
        {
                printf("Cannot open '%s'. That's not good.\n", argv[1] );
                return 2;
        }
        fgets(buf, sizeof(buf), what); 

        /* get no of points and no of triangles here*/ 

        if (fscanf(what, "%d %d\n",&nTriangles, &nCoords) !=2) 
        {
                fprintf(stderr,"Error cant find no of points and triangles in header\n"); 
                return 5;
        } 
        fprintf(stderr,"Read no of coords %d and triangles %d\n",nCoords, nTriangles); 
        fflush(stderr);

        vector<F5_vec3_point_t> Coords; 
        Coords.resize( nCoords );

        /* VERTEX Information */ 
        {for (int i=0; i<nCoords; i++)
        {
        int  index; 
        double  x,y,z;
                if (fscanf(what, "%d %lg %lg %lg\n",&index, &x, &y, &z) !=4) {
                        fprintf(stderr,"Error cant find 3 coords for index %d\n",i); 
                        return 5;
                } 
                assert(index == i+ 1); 
                Coords[i].x = x; 
                Coords[i].y = y; 
                Coords[i].z = z; 
                //need to scale down to see something .. it's difficult with 
                //meters/degrees ratio :(

                //some scaling... which was done before. removed by marcel
                //Coords[i].z /= 15000.0; 
                //Coords[i].z *= -1; 
                //fprintf(stderr,"Reading coords idx:%d (%f, %f, %f)\n",i,Coords[i].x,Coords[i].y,Coords[i].z);
        }} 

        /* allocate for the triangle buffer */ 
        vector<F5_triangle_t> Triangles; 
        Triangles.resize( nTriangles ); 

        vector<F5_triangle_t> Levees; 
        vector<vector<int> >  LeveeComplex;

        {for (int i=0; i<nTriangles; i++) 
        {
        int index; 
        int nodes_nr; 
        int idx[3]; 
                if (fscanf(what, "%d %d %d %d %d\n",&index, &nodes_nr, &idx[0], &idx[1], &idx[2]) !=5) 
                {
                        fprintf(stderr,"Error cant find 3 vertices for index %d\n",i); 
                        return 5;
                } 

                assert(index == i + 1); 
                assert(nodes_nr == 3); 
                Triangles[i].i = idx[0]-1; 
                Triangles[i].j = idx[1]-1; 
                Triangles[i].k = idx[2]-1; 
                //fprintf(stderr,"Reading triangles idx:%d (%d, %d, %d)\n",i,Triangles[i].i,Triangles[i].j, Triangles[i].k);
        }} 


        /*
          see http://www.adcirc.org/documentv46/fort_14.html
         */

        vector<vector<int> > WeirComplex;

int     DoID = -1;
char    *ADCIRC_ID = getenv("ADCIRC_ID");
        if (ADCIRC_ID)
                DoID = atoi( ADCIRC_ID );

        for(int N=0; N<2; N++)
        {
        int     Number;
                fgets(buf, sizeof(buf), what); 
                if (sscanf(buf, "%d", &Number) < 1)
                {
                        puts("ERROR in decoding object number"); 
                        break;
                } 
                printf("Got Object number line: %s", buf);

        int TotalNodeNumber; 
                fgets(buf, sizeof(buf), what); 
                if (sscanf(buf, "%d", &TotalNodeNumber) < 1)
                {
                        puts("ERROR in getting the total number of nodes"); 
                        break;
                }
                printf("Got Object total node number: %s", buf);

                for(int ID=0; ID<Number; ID++)
                {
                int nodes, type;

                        fgets(buf, sizeof(buf), what); 
                int got = sscanf(buf, "%d %d", &nodes, &type); 
                        //      printf("Got Object line: %s", buf);

                        if (got < 2)
                        {
                                if (got<1)
                                {
                                        puts("ERROR in decoding boundary type"); 
                                        printf("LINE: %s\n", buf); 
                                        return 1;
                                }
                                // open boundary 
                                for(int i=0; i<nodes; i++)
                                {
                                int     I;
                                        fgets(buf, sizeof(buf), what); 
                                        sscanf(buf, "%d\n", &I); 
                                } 
                                puts("open boundary done.");
                        } 
                        // NBVV(k,j) include this line only if IBTYPE(k) = 0, 1, 2, 10, 11, 12, 20, 21, 22, 30
                        else if ( type==0 || type==1 || type==2 || type==10 ||  type==11 ||type==11 ||
                                  type==12 || type==20 || type==21 ||  type==22  
                                  || type == 52 // new flux boundary??
                                )    // have a boundary
                        {
                        int     I; 
                                for(int i=0; i<nodes; i++)
                                {
                                        fgets(buf, sizeof(buf), what); 
                                        if (sscanf(buf, "%d\n", &I)<1)
                                        {
                                                puts("ERROR: cannot decode boundary"); 
                                                break;
                                        }
                                } 
                                printf("Boundary No. %d done\n", ID); fflush(stdout);
                        } 
                        //  NBVV(k,j), BARLANHT(k,j), BARLANCFSP(k,j ) - include this line only if IBTYPE(k) = 3, 13, 23 
                        else if ( type==3 || type==13 || type==23 )
                        {
                        int I; 
                        double height, CoeffA; 
                                WeirComplex.push_back( vector<int>() ); 
                                LeveeComplex.push_back( vector<int>() );

                                fgets(buf, sizeof(buf), what); 
                                if (sscanf(buf, "%d %lg %lg\n", &I, &height, &CoeffA )<3)
                                {
                                        puts("ERROR: cannot decode weirs"); 
                                        break;
                                }
                                I--; // Convert from FORTRAN to C indexing

                        double  HeightScale = 0.001;


                                height *= HeightScale;
                        int     VI; 
                                VI = Coords.size(); 
                        F5_vec3_point_t VIc = Coords[I]; 
                                VIc.z = height; 
                                Coords.push_back( VIc ); 

//                      int     VJ; 
//                              VJ = Coords.size(); 
//                      F5_vec3_point_t VJc = Coords[J]; 
//                              VJc.z = height; 
//                              Coords.push_back( VJc ); 

                                std::cerr << "Weir " << ID << "found - adding " 
                                          << 2*nodes << "triangles (now at "
                                          << Triangles.size() << ")" << std::endl; 

                                //fprintf(stderr, "Weir %d found - adding %d triangles (now at %d)\n", ID, 2*nodes, (int)Triangles.size() ); 
                                fflush(stderr); 

                                //bool  flipit = false; 

                                for(int i=0; i<nodes-1; i++)
                                {
                                int     Inew;
                                        fgets(buf, sizeof(buf), what); 
                                        if (sscanf(buf, "%d  %lg %lg\n", &Inew,  &height, &CoeffA)<3)
                                        {
                                                puts("ERROR: cannot decode weirs"); 
                                                break;
                                        } 
                                        Inew--;  // Convert from FORTRAN to C indexing 
/*

                                        if (DoID>0 && ID != DoID) continue;

                                        // Close weirs 
                                        {
                                        F5_triangle_t left, right; 
                                                left.i = I;  left.j = J;   left.k = Inew; 
                                                right.i=Inew; right.j = J; right.k = Jnew; 

                                                if (i==0)
                                                {
                                                        flipit = (zDir( Coords, left) <= 0.0)
                                                                 //||
                                                                 //(zDir( Coords, right) <= 0.0)
                                                                 ;
                                                }

                                        //if (i>1) continue;
                                        //              printf("LeftZDir: %lg\n", zDir( Coords, left) );
                                        //              printf("RightZDir: %lg\n", zDir( Coords, right) );

                                                WeirComplex.back().push_back( Triangles.size() );
                                                if (flipit) flip(left);
                                                Triangles.push_back( left ); 

                                                WeirComplex.back().push_back( Triangles.size() ); 
                                                if (flipit) flip(right);
                                                Triangles.push_back( right ); 
                                        }
*/ 
/*
                                        // Construct Levee 
                                        {
                                                height *= HeightScale;

                                        int     VInew; 
                                                VInew = Coords.size(); 
                                        F5_vec3_point_t VIc = Coords[Inew]; 
                                                VIc.z = height; 
                                                Coords.push_back( VIc ); 

                                        int     VJnew; 
                                                VJnew = Coords.size(); 
                                        F5_vec3_point_t VJc = Coords[Jnew]; 
                                                VJc.z = height; 
                                                Coords.push_back( VJc ); 

                                        F5_triangle_t Trngl;

                                                Trngl.i = I; Trngl.j = VI; Trngl.k = Inew;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );

                                                Trngl.i = Inew; Trngl.j = VI; Trngl.k = VInew;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );


                                                Trngl.i = VI; Trngl.j = VJ; Trngl.k = VInew;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );

                                                Trngl.i = VJ; Trngl.j = VJnew; Trngl.k = VInew;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );


                                                Trngl.i = VJnew; Trngl.j = J; Trngl.k = Jnew;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );

                                                Trngl.i = VJnew; Trngl.j = VJ; Trngl.k = J;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );


                                                VI = VInew; 
                                                VJ = VJnew;
                                        }
*/                              

                                        // Reuse indices
                                        I = Inew; 
                                } 
                        } 
                        // NBVV(k,j), IBCONN(k,j), BARINHT(k,j), BARINCFSB(k,j), BARINCFSP(k,j) - include this line only if IBTYPE(k) = 4, 24
                        else if (type==24 || type== 4) // have a weir!
                        {
                        int I, J; 
                        double height, CoeffA, CoeffB; 
                                WeirComplex.push_back( vector<int>() ); 
                                LeveeComplex.push_back( vector<int>() );

                                fgets(buf, sizeof(buf), what); 
                                if (sscanf(buf, "%d %d %lg %lg %lg\n", &I, &J, &height, &CoeffA, &CoeffB)<5)
                                {
                                        puts("ERROR: cannot decode weirs"); 
                                        break;
                                }
                                I--; J--; // Convert from FORTRAN to C indexing

                        double  HeightScale = 0.001;


                                height *= HeightScale;
                        int     VI; 
                                VI = Coords.size(); 
                        F5_vec3_point_t VIc = Coords[I]; 
                                VIc.z = height; 
                                Coords.push_back( VIc );

                        int     VJ;
                                VJ = Coords.size(); 
                        F5_vec3_point_t VJc = Coords[J]; 
                                VJc.z = height; 
                                Coords.push_back( VJc ); 

                                std::cerr << "Weir " << ID << " found - adding " 
                                          << 2*nodes << " triangles (now at "
                                          << Triangles.size() << ")" << std::endl; 
                                //fprintf(stderr, "Weir %d found - adding %d triangles (now at %d)\n", ID, 2*nodes, (int)Triangles.size() ); 
                                fflush(stderr);
 
                        bool    flipit = false; 

                                for(int i=0; i<nodes-1; i++)
                                {
                                int     Inew, Jnew;
                                        fgets(buf, sizeof(buf), what); 
                                        if (sscanf(buf, "%d %d %lg %lg %lg\n", &Inew, &Jnew, &height, &CoeffA, &CoeffB)<5)
                                        {
                                                puts("ERROR: cannot decode weirs"); 
                                                break;
                                        } 
                                        Inew--; Jnew--; // Convert from FORTRAN to C indexing


                                        if (DoID>0 && ID != DoID) continue;

                                        // Close weirs 
                                        {
                                        F5_triangle_t left, right; 
                                                left.i = I;  left.j = J;   left.k = Inew; 
                                                right.i=Inew; right.j = J; right.k = Jnew; 

                                                if (i==0)
                                                {
                                                        flipit = (zDir( Coords, left) <= 0.0)
                                                                 //||
                                                                 //(zDir( Coords, right) <= 0.0)
                                                                 ;
                                                }

                                        //if (i>1) continue;
                                        //              printf("LeftZDir: %lg\n", zDir( Coords, left) );
                                        //              printf("RightZDir: %lg\n", zDir( Coords, right) );

                                                WeirComplex.back().push_back( Triangles.size() );
                                                if (flipit) flip(left);
                                                Triangles.push_back( left ); 

                                                WeirComplex.back().push_back( Triangles.size() ); 
                                                if (flipit) flip(right);
                                                Triangles.push_back( right ); 
                                        }

                                        // Construct Levee 
                                        {
                                                height *= HeightScale;

                                        int     VInew; 
                                                VInew = Coords.size(); 
                                        F5_vec3_point_t VIc = Coords[Inew]; 
                                                VIc.z = height; 
                                                Coords.push_back( VIc ); 

                                        int     VJnew; 
                                                VJnew = Coords.size(); 
                                        F5_vec3_point_t VJc = Coords[Jnew]; 
                                                VJc.z = height; 
                                                Coords.push_back( VJc ); 

                                        F5_triangle_t Trngl;

                                                Trngl.i = I; Trngl.j = VI; Trngl.k = Inew;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );

                                                Trngl.i = Inew; Trngl.j = VI; Trngl.k = VInew;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );


                                                Trngl.i = VI; Trngl.j = VJ; Trngl.k = VInew;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );

                                                Trngl.i = VJ; Trngl.j = VJnew; Trngl.k = VInew;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );


                                                Trngl.i = VJnew; Trngl.j = J; Trngl.k = Jnew;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );

                                                Trngl.i = VJnew; Trngl.j = VJ; Trngl.k = J;
                                                if (flipit) flip(Trngl);
                                                LeveeComplex.back().push_back( Levees.size() ); Levees.push_back( Trngl );


                                                VI = VInew; 
                                                VJ = VJnew;
                                        }
                                        

                                        // Reuse indices
                                        I = Inew; 
                                        J = Jnew;
                                } 
                        } 
                        
                        else
                        {
                                puts("ERROR in decoding ADCIRC file"); 
                                printf("ERROR LINE: %s\n", buf); 
                                printf("Unsupported type = %d", type);
                                return 1;
                                break;
                        }
                } 
                printf("Boundary Complex %d done.\n", N);
        } 

        std::cerr << "Triangular surface: " << nCoords << " vertices, "
                  << Triangles.size() << " triangles - " 
                  << Triangles.size() - nTriangles << " for weirs" << std::endl; 

//      fprintf(stderr, "Triangular surface: %d vertices, %d triangles - %d for weirs\n", 
//              nCoords, (int)Triangles.size(), (int)Triangles.size() - nTriangles ); 
        fflush(stderr); 

        F5Path *MainGrid = F5write_triangular_surface(fileID, time, gridname.c_str(),
                                                      &Coords[0],  nCoords,
                                                      &Triangles[0], Triangles.size() );

        if (!MainGrid)
                puts("ERROR in writing grid...");


        F5Fclose(MainGrid); 


        std::cerr << "Levee Triangular surface: " << Coords.size() << " vertices, "
                  << Levees.size() << " triangles" << std::endl; 

//      fprintf(stderr, "Levee Triangular surface: %d vertices, %d triangles\n", 
//              (int)Coords.size(), (int)Levees.size() ); 
        fflush(stderr); 

        // No levee data found, don't write
        if( Levees.size()>0 )
        {
        F5Path *LeveeGrid = F5write_triangular_surface(fileID, time, (gridname + ".levee").c_str(),
                                                       &Coords[0],  Coords.size(),
                                                       &Levees[0], Levees.size() ); 

        if (!LeveeGrid)
                puts("ERROR in writing grid..."); 


        F5Fclose(LeveeGrid); 
        }

        // Due to the levees, we have additional vertices now. 
        // In order to write surface data, we need to crop them 
        // to their original count.
        Coords.resize( nCoords ); 
        AppendSurfaceData( fileID, gridname, Coords, Triangles, time_steps_to_load ); 
        

        H5Fclose(fileID);       
        return 0;
}