Exemple #1
0
void COutput::SetCGNS_Solution(CConfig *config, CGeometry *geometry, unsigned short iZone) {
  
#ifdef HAVE_CGNS
  
	/*--- local CGNS variables ---*/
	int cgns_file, cgns_flow, cgns_field, cgns_err;
//  int element_dims;
	unsigned long jVar, iVar, iExtIter = config->GetExtIter();
	string base_file, buffer, elements_name;
	stringstream name, results_file;
	bool unsteady = config->GetUnsteady_Simulation();
  
  bool compressible = (config->GetKind_Regime() == COMPRESSIBLE);
  
	/*--- Create CGNS base file name ---*/
	base_file = config->GetFlow_FileName();
  
	/*--- Add CGNS extension. ---*/
	base_file = base_file.append(".cgns");
  
	/*--- Create CGNS results file name ---*/
	if (unsteady) {
    
		buffer = config->GetFlow_FileName();
    
		results_file.str(string()); results_file << buffer;
		if (((int)iExtIter >= 0) && ((int)iExtIter < 10))			results_file << "_0000" << iExtIter;
		if (((int)iExtIter >= 10) && ((int)iExtIter < 100))		results_file << "_000" << iExtIter;
		if (((int)iExtIter >= 100) && ((int)iExtIter < 1000))		results_file << "_00" << iExtIter;
		if (((int)iExtIter >= 1000) && ((int)iExtIter < 10000))	results_file << "_0" << iExtIter;
		if ((int)iExtIter >= 10000)							results_file << iExtIter;
		results_file << ".cgns";
	}
    
		if (!unsteady) {
      
      /*--- Write base file ---*/
      cgns_err = cg_open((char *)base_file.c_str(), CG_MODE_MODIFY, &cgns_file);
      if (cgns_err) cg_error_print();
      
//      element_dims = geometry->GetnDim();		// Currently (release 2.0) only all-2D or all-3D zones permitted
      
      /*--- write CGNS descriptor data ---*/
      cgns_err = cg_goto(cgns_file, cgns_base,"end");
      if (cgns_err) cg_error_print();
      
			/*--- Create a CGNS solution node ---*/
			cgns_err = cg_sol_write(cgns_file, cgns_base, cgns_zone,"Solution", Vertex, &cgns_flow);
			if (cgns_err) cg_error_print();
      
			cgns_err = cg_goto(cgns_file, cgns_base,"Zone_t", cgns_zone,"FlowSolution_t", cgns_flow,"end");
			if (cgns_err) cg_error_print();
      
			cgns_err = cg_gridlocation_write(Vertex);
			if (cgns_err) cg_error_print();
		}

    
		//wrote_CGNS_base = true;
    else {
	
	/*--- Set up results file for this time step if necessary ---*/
    
		cgns_err = cg_open((char *)results_file.str().c_str(), CG_MODE_MODIFY, &cgns_file);
    
//		element_dims = geometry->GetnDim();		// Currently (release 2.0) only all-2D or all-3D zones permitted
//    
//		/*--- write CGNS base data (one base assumed currently) ---*/
//		cgns_err = cg_base_write(cgns_file,"SU2 Base", element_dims, physical_dims, &cgns_base);
//		if (cgns_err) cg_error_print();
    
//		/*--- write CGNS zone data ---*/
//		cgns_err = cg_zone_write(cgns_file, cgns_base,"SU2 Zone", isize[0],Unstructured, &cgns_zone);
//		if (cgns_err) cg_error_print();
    
		cgns_err = cg_goto(cgns_file, cgns_base_results,"Zone_t", cgns_zone_results,"end");
		if (cgns_err) cg_error_print();
    
		/*--- Write a CGNS solution node for this time step ---*/
		cgns_err = cg_sol_write(cgns_file, cgns_base_results, cgns_zone_results,"Solution", Vertex, &cgns_flow);
		if (cgns_err) cg_error_print();
    
		cgns_err = cg_goto(cgns_file, cgns_base_results,"Zone_t", cgns_zone_results,"FlowSolution_t", cgns_flow,"end");
		if (cgns_err) cg_error_print();
    
		cgns_err = cg_gridlocation_write(Vertex);
		if (cgns_err) cg_error_print();
    
      cgns_base = cgns_base_results;
      cgns_zone = cgns_zone_results;
	}
//	else {
//    
//		/*--- Open CGNS file for soltuion writing ---*/
//		cgns_err = cg_open((char *)base_file.c_str(), CG_MODE_MODIFY, &cgns_file);
//		cgns_base = 1; cgns_zone = 1; cgns_flow = 1;	// fix for multiple zones
//    
//	}
	
	/*	Reference Note on solution variables:
   index 0 --> (nVar_Consv-1)			= Conservative Variables
   nVar_Consv --> (2*nVar_Consv-1)		= Conservative Variable Residuals
   (2*nVar_Consv-1)+					= Additional p, M, T, laminar, eddy depending on solver used */
  
	/*--- Write conservative variables to CGNS file ---*/
	for (iVar = 0; iVar < nVar_Consv; iVar++) {
		name.str(string()); name << "Conservative Variable " << iVar+1;
		cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,(char *)name.str().c_str(), Data[iVar], &cgns_field);
		if (cgns_err) cg_error_print();
	}
  
  /*--- Write primitive variable residuals to CGNS file ---*/
  if (config->GetWrt_Limiters()) {
    for (jVar = 0; jVar < nVar_Consv; jVar++) {
      name.str(string()); name << "Primitive Limiter " << jVar+1;
      cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,(char *)name.str().c_str(), Data[iVar], &cgns_field); iVar++;
      if (cgns_err) cg_error_print();
    }
  }
  
	/*--- Write conservative variable residuals to CGNS file ---*/
  if (config->GetWrt_Residuals()) {
    for (jVar = 0; jVar < nVar_Consv; jVar++) {
      name.str(string()); name << "Conservative Residual " << jVar+1;
      cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,(char *)name.str().c_str(), Data[iVar], &cgns_field); iVar++;
      if (cgns_err) cg_error_print();
    }
  }
  
	/*--- Write grid velocities to CGNS file, if applicable ---*/
	if (config->GetGrid_Movement()) {
		cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Grid Velocity X", Data[iVar], &cgns_field); iVar++;
		if (cgns_err) cg_error_print();
		cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Grid Velocity Y", Data[iVar], &cgns_field); iVar++;
		if (cgns_err) cg_error_print();
		if (geometry->GetnDim() == 3) {
			cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Grid Velocity Z", Data[iVar], &cgns_field); iVar++;
			if (cgns_err) cg_error_print();
		}
	}
  
	if (compressible) {
		switch (config->GetKind_Solver()) {
        
        /*--- Write pressure and Mach data to CGNS file ---*/
      case EULER:
        cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Pressure", Data[iVar], &cgns_field); iVar++;
        if (cgns_err) cg_error_print();
        cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Mach", Data[iVar], &cgns_field); iVar++;
        if (cgns_err) cg_error_print();
        break;
        
        /*--- Write temperature and laminar viscosity to CGNS file, if applicable ---*/
      case NAVIER_STOKES:
        cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Pressure", Data[iVar], &cgns_field); iVar++;
        if (cgns_err) cg_error_print();
        cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Mach", Data[iVar], &cgns_field); iVar++;
        if (cgns_err) cg_error_print();
        cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Temperature", Data[iVar], &cgns_field); iVar++;
        if (cgns_err) cg_error_print();
        cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Viscosity", Data[iVar], &cgns_field); iVar++;
        if (cgns_err) cg_error_print();
        break;
        
        /*--- Write eddy viscosity to CGNS file, if applicable ---*/
      case RANS:
        cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Pressure", Data[iVar], &cgns_field); iVar++;
        if (cgns_err) cg_error_print();
        cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Mach", Data[iVar], &cgns_field); iVar++;
        if (cgns_err) cg_error_print();
        cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Temperature", Data[iVar], &cgns_field); iVar++;
        if (cgns_err) cg_error_print();
        cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Viscosity", Data[iVar], &cgns_field); iVar++;
        if (cgns_err) cg_error_print();
        cgns_err = cg_field_write(cgns_file, cgns_base, cgns_zone, cgns_flow, RealDouble,"Eddy Viscosity", Data[iVar], &cgns_field); iVar++;
        if (cgns_err) cg_error_print();
        break;
        
      default:
        cout << "Error: Unrecognized equation type \n"; 
        exit(EXIT_FAILURE); break;
		}
	}	
  
	/*--- Close CGNS file ---*/
	cgns_err = cg_close(cgns_file);
	if (cgns_err) cg_error_print();
  
#else // Not built with CGNS support
  
	cout << "CGNS file requested but SU2 was built without CGNS support. No file written" << "\n"; 
  
#endif
  
}
int main()
{
    int index_file,index_base,index_zone;
    int nelem_start,nelem_end,icount,index_bc,ibc,n;
    cgsize_t ipnts[maxcount];

/* WRITE BOUNDARY CONDITIONS TO EXISTING CGNS FILE */
/* open CGNS file for modify */
    if (cg_open("grid_c.cgns",CG_MODE_MODIFY,&index_file)) cg_error_exit();
/* we know there is only one base (real working code would check!) */
    index_base=1;
/* we know there is only one zone (real working code would check!) */
    index_zone=1;
/* we know that for the unstructured zone, the following face elements */
/* have been defined as inflow (real working code would check!): */
    nelem_start=2561;
    nelem_end=2688;
    icount=0;
    for (n=nelem_start; n <= nelem_end; n++)
    {
      ipnts[icount]=n;
      icount=icount+1;
    }
    if (icount > maxcount)
    {
      printf("\nError. Need to increase maxcount to at least %i\n",icount);
      return 1;
    }
/* write boundary conditions for ilo face */
    cg_boco_write(index_file,index_base,index_zone,"Ilo",BCTunnelInflow,
        PointList,icount,ipnts,&index_bc);
/* we know that for the unstructured zone, the following face elements */
/* have been defined as outflow (real working code would check!): */
    nelem_start=2689;
    nelem_end=2816;
    icount=0;
    for (n=nelem_start; n <= nelem_end; n++)
    {
      ipnts[icount]=n;
      icount=icount+1;
    }
    if (icount > maxcount)
    {
      printf("\nError. Need to increase maxcount to at least %i\n",icount);
      return 1;
    }
/* write boundary conditions for ihi face */
    cg_boco_write(index_file,index_base,index_zone,"Ihi",BCExtrapolate,
        PointList,icount,ipnts,&index_bc);
/* we know that for the unstructured zone, the following face elements */
/* have been defined as walls (real working code would check!): */
    nelem_start=2817;
    nelem_end=3776;
    icount=0;
    for (n=nelem_start; n <= nelem_end; n++)
    {
      ipnts[icount]=n;
      icount=icount+1;
    }
    if (icount > maxcount)
    {
      printf("\nError. Need to increase maxcount to at least %i\n",icount);
      return 1;
    }
/* write boundary conditions for wall faces */
    cg_boco_write(index_file,index_base,index_zone,"Walls",BCWallInviscid,
        PointList,icount,ipnts,&index_bc);

/* the above are all face-center locations for the BCs - must indicate this, */
/* otherwise Vertices will be assumed! */
    for (ibc=1; ibc <= index_bc; ibc++)
    {
/*    (the following call positions you in BC_t - it assumes there */
/*    is only one Zone_t and one ZoneBC_t - real working code would check!) */
      cg_goto(index_file,index_base,"Zone_t",1,"ZoneBC_t",1,"BC_t",ibc,"end");
      cg_gridlocation_write(FaceCenter);
    }
/* close CGNS file */
    cg_close(index_file);
    printf("\nSuccessfully added FaceCenter BCs (PointList) to unstructured grid file grid_c.cgns\n");
    return 0;
}
int main (int argc, char **argv)
{
    int n, i, j, k, nuser, dim = 1;
    int cgfile, cgbase, cgzone, cgcoord, cgdset;
    int size[9];
    int ptlist[3] = {1, 2, 3};
    int ptrange[6] = {1, 1, 1, 2, 2, 2};
    int bcpoints[6], bcfaces[6];
    static char *fname = "gotest.cgns";
    char name[33];
    float data1 = 1;
    float data2 = 2;
    float exponents[8], rate[3], center[3];
    GridLocation_t gridloc;
    int ordinal, ndata, cgfam, cgbc, nunits, nexps;
    int elecflag, magnflag, condflag, dirichlet, neumann;
    PointSetType_t pttype;
    DataClass_t dclass;
    DataType_t dtype;
    BCType_t bctype;
    MassUnits_t mass;
    LengthUnits_t length;
    TimeUnits_t time;
    TemperatureUnits_t temp;
    AngleUnits_t angle;
    ElectricCurrentUnits_t current;
    SubstanceAmountUnits_t amount;
    LuminousIntensityUnits_t intensity;
    ModelType_t elecmodel;
    ModelType_t magnmodel;
    ModelType_t emconduct;

    /* errors and warnings go to error_exit */

    cg_configure(CG_CONFIG_ERROR, (void *)error_exit);

    for (n = 0; n < 8; n++)
        exponents[n] = (float)n;
    for (n = 0; n < 3; n++) {
        rate[n] = (float)n;
        center[n] = (float)n;
    }
    for (n = 0; n < NUM_SIDE*NUM_SIDE*NUM_SIDE; n++)
        coord[n] = (float)n;

    unlink (fname);
    printf ("creating CGNS file %s\n", fname);
    cg_open (fname, CG_MODE_WRITE, &cgfile);
    cg_base_write (cgfile, "Base", 3, 3, &cgbase);

    /* write electomagnetics model under base */

    puts ("writing electromagnetics");
    cg_goto(cgfile, cgbase, NULL);
    cg_equationset_write (3);
    cg_goto(cgfile, cgbase, "FlowEquationSet_t", 1, NULL);
    cg_model_write("EMElectricFieldModel_t", Voltage);
    cg_model_write("EMMagneticFieldModel_t", Interpolated);
    cg_model_write("EMConductivityModel_t", Equilibrium_LinRessler);

    /* write rotating coordinates under family_t */

    puts ("writing family/rotating");
    cg_family_write(cgfile, cgbase, "Family", &cgfam);
    /* go to a named node */
    cg_goto(cgfile, cgbase, "Family", 0, NULL);
    cg_rotating_write (rate, center);

    /* write BCDataSet under FamilyBC_t */

    puts("writing FamilyBCDataSet");
    cg_fambc_write(cgfile, cgbase, cgfam, "FamilyBC", BCWall, &cgbc);
    /* relative go to */
    cg_gorel(cgfile, "FamilyBC_t", cgbc, NULL);
    cg_bcdataset_write ("FamilyBCDataSet", BCWallInviscid, Dirichlet);

    /* write user data under base */

    puts("writing user defined data under base");
    /* relative path */
    cg_gopath (cgfile, "../..");
    cg_user_data_write ("User");
    /* absolute path */
    cg_gopath (cgfile, "/Base/User");
    cg_gridlocation_write (CellCenter);
    cg_famname_write ("Family");
    cg_ordinal_write (0);
    cg_array_write ("Data1", RealSingle, 1, &dim, &data1);
    cg_array_write ("Data2", RealSingle, 1, &dim, &data2);

    for (n = 1; n <= 2; n++) {
        cg_goto (cgfile, cgbase, "User", 0, "DataArray_t", n, "end");
        cg_dataclass_write (Dimensional);
        cg_units_write (Kilogram, Meter, Second, Kelvin, Radian);
        cg_exponents_write (RealSingle, exponents);
    }

    /* this should fail since ptset not allowed as child of
       user data, except below a zone_t node */

    cg_configure(CG_CONFIG_ERROR, NULL);
    if (cg_ptset_write (PointList, 1, ptlist) == CG_OK)
        printf ("WHAT!! - ptset should not work under base/userdata\n");
    cg_configure(CG_CONFIG_ERROR, (void *)error_exit);

    /* write zone */

    puts("writing zone");
    for (n = 0; n < 3; n++) {
        size[n]   = NUM_SIDE;
        size[n+3] = NUM_SIDE - 1;
        size[n+6] = 0;
    }
    cg_zone_write (cgfile, cgbase, "Zone", size, Structured, &cgzone);
    cg_coord_write(cgfile, cgbase, cgzone, RealSingle,
        "CoordinateX", coord, &cgcoord);
    cg_coord_write(cgfile, cgbase, cgzone, RealSingle,
        "CoordinateY", coord, &cgcoord);
    cg_coord_write(cgfile, cgbase, cgzone, RealSingle,
        "CoordinateZ", coord, &cgcoord);

    /* create a BC node with point range and Dirichlet node*/

    puts("writing Dirichlet BC with vertex range");
    for (n = 0; n < 3; n++) {
        bcpoints[n]   = 1;
        bcpoints[n+3] = NUM_SIDE;
        bcfaces[n]    = 1;
        bcfaces[n+3]  = NUM_SIDE - 1;
    }
    bcpoints[5] = bcfaces[5] = 1;
    cg_boco_write (cgfile, cgbase, cgzone, "BC", BCWall,
        PointList, 1, bcpoints, &cgbc);
    cg_dataset_write (cgfile, cgbase, cgzone, cgbc,
        "DataSet", BCWallViscous, &cgdset);
    cg_bcdata_write (cgbase, cgfile, cgzone, cgbc, cgdset, Dirichlet);

    /* create Dirichlet data at faces */

    puts("writing Dirichlet data at faces");
    cg_gopath (cgfile, "/Base/Zone/ZoneBC/BC/DataSet");
    cg_gridlocation_write (KFaceCenter);
    cg_ptset_write (PointRange, 2, bcfaces);

    size[0] = (NUM_SIDE - 1) * (NUM_SIDE - 1);
    cg_gorel (cgfile, "BCData_t", Dirichlet, NULL);
    cg_array_write ("Data", RealSingle, 1, size, coord);

    /* write recursive user data */

    puts("writing recursive user defined data under zone");
    cg_goto(cgfile, cgbase, "Zone", 0, NULL);
    for (i = 1; i <= 4; i++) {
        sprintf (name, "User%d", i);
        cg_user_data_write (name);
        cg_gorel(cgfile, name, 0, NULL);
        cg_gridlocation_write (CellCenter);
        cg_famname_write ("Family");
        cg_ordinal_write (i);
        cg_ptset_write (PointList, 1, ptlist);
        cg_array_write ("Data1", RealSingle, 1, &dim, &data1);
        cg_array_write ("Data2", RealSingle, 1, &dim, &data2);
        for (n = 1; n <= 2; n++) {
            cg_gorel (cgfile, "DataArray_t", n, "end");
            cg_dataclass_write (Dimensional);
            cg_unitsfull_write (Kilogram, Meter, Second, Kelvin, Radian,
                Ampere, Mole, Candela);
            cg_expfull_write (RealSingle, exponents);
            cg_gopath (cgfile, "..");
        }

        for (j = 1; j <= 3; j++) {
            sprintf (name, "User%d.%d", i, j);
            cg_user_data_write (name);
            cg_gopath (cgfile, name);
            cg_gridlocation_write (Vertex);
            cg_famname_write ("Family");
            cg_ordinal_write (i + j);
            cg_ptset_write (PointRange, 2, ptrange);
            cg_array_write ("Data1", RealSingle, 1, &dim, &data1);
            cg_array_write ("Data2", RealSingle, 1, &dim, &data2);
            for (n = 1; n <= 2; n++) {
                cg_gorel (cgfile, "DataArray_t", n, "end");
                cg_dataclass_write (Dimensional);
                cg_unitsfull_write (Kilogram, Meter, Second, Kelvin,
                    Radian, Ampere, Mole, Candela);
                cg_expfull_write (RealSingle, exponents);
                cg_gorel (cgfile, "..", 0, NULL);
            }

            for (k = 1; k <= 2; k++) {
                sprintf (name, "User%d.%d.%d", i, j, k);
                cg_user_data_write (name);
                cg_gorel (cgfile, name, 0, NULL);
                cg_array_write ("Data1", RealSingle, 1, &dim, &data1);
                cg_array_write ("Data2", RealSingle, 1, &dim, &data2);
                for (n = 1; n <= 2; n++) {
                    cg_gorel (cgfile, "DataArray_t", n, "end");
                    cg_dataclass_write (Dimensional);
                    cg_unitsfull_write (Kilogram, Meter, Second, Kelvin,
                        Radian, Ampere, Mole, Candela);
                    cg_expfull_write (RealSingle, exponents);
                    cg_gopath (cgfile, "..");
                }

                for (n = 1; n <= 2; n++) {
                    sprintf (name, "User%d.%d.%d.%d", i, j, k, n);
                    cg_user_data_write (name);
                    cg_gopath (cgfile, name);
                    cg_array_write ("Data1", RealSingle, 1, &dim, &data1);
                    cg_array_write ("Data2", RealSingle, 1, &dim, &data2);
                    cg_gopath (cgfile, "..");
                }
                cg_gopath (cgfile, "..");
            }
            cg_gopath (cgfile, "..");
        }
        cg_gopath (cgfile, "..");
    }

    puts ("closing and reopening in read mode");
    cg_close (cgfile);

    /* read file and check values */

    cg_configure(CG_CONFIG_ERROR, NULL);

    if (cg_open (fname, CG_MODE_READ, &cgfile))
        cg_error_exit ();
    cgbase = cgzone = 1;

    /* check electomagnetics model under base */

    puts ("checking electromagnetics");
    if (cg_goto(cgfile, cgbase, NULL) ||
        cg_equationset_elecmagn_read(&elecflag, &magnflag, &condflag) ||
        cg_goto(cgfile, cgbase, "FlowEquationSet_t", 1, NULL) ||
        cg_model_read ("EMElectricFieldModel_t", &elecmodel) ||
        cg_model_read ("EMMagneticFieldModel_t", &magnmodel) ||
        cg_model_read ("EMConductivityModel_t", &emconduct))
        cg_error_exit();
    CHECK ("ElectricFieldFlag", elecflag == 1);
    CHECK ("ElectricFieldModel", elecmodel == Voltage);
    CHECK ("MagneticFieldFlag", magnflag == 1);
    CHECK ("MagneticFieldModel", magnmodel == Interpolated);
    CHECK ("EMConductivityFlag", condflag == 1);
    CHECK ("EMConductivityModel", emconduct == Equilibrium_LinRessler);

    /* check rotating coordinates under family_t */

    puts ("checking family/rotating");
    if (cg_goto(cgfile, cgbase, "Family_t", 1, NULL) ||
        cg_rotating_read (rate, center))
        cg_error_exit();
    for (n = 0; n < 3; n++) {
        CHECK ("rotation rate", rate[n] == (float)n);
        CHECK ("rotation center", center[n] == (float)n);
    }

    /* check BCDataSet under FamilyBC_t */

    puts("checking FamilyBCDataSet");
    *name = 0;
    if (cg_goto(cgfile, cgbase, "Family_t", 1, "FamilyBC_t", 1, NULL) ||
        cg_bcdataset_info(&ndata) ||
        cg_bcdataset_read (1, name, &bctype, &dirichlet, &neumann))
        cg_error_exit();
    CHECK("bcdataset_info", ndata == 1);
    CHECK("bcdatset name", strcmp(name, "FamilyBCDataSet") == 0);
    CHECK("bcdatset type", bctype == BCWallInviscid);
    CHECK("bcdatset dirichlet", dirichlet == 1);
    CHECK("bcdatset neumann", neumann == 0);

    /* check BC data */

    puts("checking BC data");
    if (cg_boco_info (cgfile, cgbase, cgzone, 1, name, &bctype, &pttype,
            &n, size, &i, &dtype, &ndata))
        cg_error_exit();
    CHECK("BC_t name", strcmp(name, "BC") == 0);
    CHECK("BC_t type", bctype == BCWall);
    CHECK("BC_t pntset type", pttype == PointList);
    CHECK("BC_t npnts", n == 1);

    if (cg_dataset_read (cgfile, cgbase, cgzone, 1, 1, name,
            &bctype, &dirichlet, &neumann) ||
        cg_goto (cgfile, cgbase, "Zone_t", 1, "ZoneBC_t", 1, "BC_t", 1,
            "BCDataSet_t", 1, NULL) ||
        cg_gridlocation_read (&gridloc) ||
        cg_ptset_info (&pttype, &n))
        cg_error_exit();
    CHECK("BCDataSet_t name", strcmp(name, "DataSet") == 0);
    CHECK("BCDataSet_t type", bctype == BCWallViscous);
    CHECK("BCDataSet_t location", gridloc == KFaceCenter);
    CHECK("BCDataSet_t pntset type", pttype == PointRange);
    CHECK("BC_t npnts", n == 2);
    CHECK("BCDataSet_t dirichlet", dirichlet == 1);
    CHECK("BCDataSet_t neumann", neumann == 0);

    /* check user defined data */

    puts("checking user defined data");
    *name = 0;
    if (cg_goto (cgfile, cgbase, "UserDefinedData_t", 1, "end") ||
        cg_gridlocation_read (&gridloc) ||
        cg_famname_read (name) ||
        cg_ordinal_read (&ordinal) ||
        cg_narrays (&ndata))
        cg_error_exit ();
    CHECK ("gridlocation", gridloc == CellCenter);
    CHECK ("famname", strcmp (name, "Family") == 0);
    CHECK ("ordinal", ordinal == 0);
    CHECK ("narrays", ndata == 2);

    if (cg_goto (cgfile, cgbase, "Zone_t", cgzone, "end") ||
        cg_nuser_data (&nuser))
        cg_error_exit ();
    CHECK ("nuserdata", nuser == 4);

    for (i = 1; i <= 4; i++) {
        *name = 0;
        if (cg_goto (cgfile, cgbase, "Zone_t", cgzone,
                "UserDefinedData_t", i, "end") ||
            cg_gridlocation_read (&gridloc) ||
            cg_famname_read (name) ||
            cg_ordinal_read (&ordinal) ||
            cg_ptset_info (&pttype, &n) ||
            cg_ptset_read (ptlist) ||
            cg_narrays (&ndata) ||
            cg_nuser_data (&nuser))
            cg_error_exit ();
        CHECK ("gridlocation", gridloc == CellCenter);
        CHECK ("famname", strcmp (name, "Family") == 0);
        CHECK ("ordinal", ordinal == i);
        CHECK ("pointtype", pttype == PointList);
        CHECK ("npoints", n == 1);
        CHECK ("narrays", ndata == 2);
        CHECK ("nuserdata", nuser == 3);

        for (j = 1; j <= 3; j++) {
            *name = 0;
            if (cg_goto (cgfile, cgbase, "Zone_t", cgzone,
                    "UserDefinedData_t", i,
                    "UserDefinedData_t", j, "end") ||
                cg_gridlocation_read (&gridloc) ||
                cg_famname_read (name) ||
                cg_ordinal_read (&ordinal) ||
                cg_ptset_info (&pttype, &n) ||
                cg_ptset_read (ptlist) ||
                cg_narrays (&ndata) ||
                cg_nuser_data (&nuser))
                cg_error_exit ();
            CHECK ("gridlocation", gridloc == Vertex);
            CHECK ("famname", strcmp (name, "Family") == 0);
            CHECK ("ordinal", ordinal == (i + j));
            CHECK ("pointtype", pttype == PointRange);
            CHECK ("npoints", n == 2);
            CHECK ("narrays", ndata == 2);
            CHECK ("nuserdata", nuser == 2);

            for (n = 1; n <= 2; n++) {
                if (cg_goto (cgfile, cgbase, "Zone_t", cgzone,
                        "UserDefinedData_t", i,
                        "UserDefinedData_t", j,
                        "DataArray_t", n, "end") ||
                    cg_dataclass_read (&dclass) ||
                    cg_nunits (&nunits) ||
                    cg_unitsfull_read (&mass, &length, &time, &temp, &angle,
                        &current, &amount, &intensity) ||
                    cg_nexponents (&nexps) ||
                    cg_expfull_read (exponents))
                    cg_error_exit ();
                CHECK ("dataclass", dclass == Dimensional);
                CHECK ("nunits", nunits == 8);
                CHECK ("massunits", mass == Kilogram);
                CHECK ("lengthunits", length == Meter);
                CHECK ("timeunits", time == Second);
                CHECK ("tempunits", temp == Kelvin);
                CHECK ("angleunits", angle == Radian);
                CHECK ("currentunits", current == Ampere);
                CHECK ("amountunits", amount == Mole);
                CHECK ("intensityunits", intensity == Candela);
                CHECK ("nexponents", nexps == 8);
                for (n = 0; n < 8; n++)
                    CHECK ("exponents", exponents[n] == (float)n);
            }
        }
    }

    if (cg_goto (cgfile, cgbase, "Zone_t", cgzone,
            "UserDefinedData_t", 2, "UserDefinedData_t", 2,
            "UserDefinedData_t", 2, "UserDefinedData_t", 1, "end") ||
        cg_narrays (&ndata) ||
        cg_nuser_data (&nuser) ||
        cg_array_info (2, name, &dtype, &n, &dim) ||
        cg_array_read (1, &data1) ||
        cg_array_read (2, &data2))
        cg_error_exit ();
    CHECK ("narrays", ndata == 2);
    CHECK ("nuserdata", nuser == 0);
    CHECK ("arrayname", strcmp (name, "Data2") == 0);
    CHECK ("datatype", dtype == RealSingle);
    CHECK ("ndims", n == 1);
    CHECK ("dims", dim == 1);
    CHECK ("data1", data1 == 1.0);
    CHECK ("data2", data2 == 2.0);

    /* read partial units/exponents as full */

    puts("checking units and exponents");
    if (cg_goto(cgfile, cgbase, "UserDefinedData_t", 1,
            "DataArray_t", 1, NULL) ||
        cg_nunits (&nunits) ||
        cg_unitsfull_read (&mass, &length, &time, &temp, &angle,
            &current, &amount, &intensity) ||
        cg_nexponents (&nexps) ||
        cg_expfull_read (exponents))
        cg_error_exit ();
    CHECK ("nunits", nunits == 5);
    CHECK ("massunits", mass == Kilogram);
    CHECK ("lengthunits", length == Meter);
    CHECK ("timeunits", time == Second);
    CHECK ("tempunits", temp == Kelvin);
    CHECK ("angleunits", angle == Radian);
    CHECK ("currentunits", current == 0);
    CHECK ("amountunits", amount == 0);
    CHECK ("intensityunits", intensity == 0);
    CHECK ("nexponents", nexps == 5);
    for (n = 0; n < 5; n++)
        CHECK ("exponents", exponents[n] == (float)n);
    for (n = 6; n < 8; n++)
        CHECK ("exponents", exponents[n] == (float)0.0);

    /* read full units/exponents as partial */

    if (cg_goto(cgfile, cgbase, "Zone_t", 1, "UserDefinedData_t", 1,
            "DataArray_t", 1, NULL) ||
        cg_nunits (&nunits) ||
        cg_units_read (&mass, &length, &time, &temp, &angle) ||
        cg_nexponents (&nexps) ||
        cg_exponents_read (exponents))
        cg_error_exit ();
    CHECK ("nunits", nunits == 8);
    CHECK ("massunits", mass == Kilogram);
    CHECK ("lengthunits", length == Meter);
    CHECK ("timeunits", time == Second);
    CHECK ("tempunits", temp == Kelvin);
    CHECK ("angleunits", angle == Radian);
    CHECK ("nexponents", nexps == 8);
    for (n = 0; n < 5; n++)
        CHECK ("exponents", exponents[n] == (float)n);

    puts ("closing file and reopening in modify mode");
    cg_close (cgfile);

    /* delete userdata node */

    if (cg_open (fname, CG_MODE_MODIFY, &cgfile))
        cg_error_exit ();

    puts ("deleting user defined data and checking");
    if (cg_goto (cgfile, 1, "Zone_t", 1,
            "UserDefinedData_t", 3,
            "UserDefinedData_t", 2,
            "UserDefinedData_t", 1, "end") ||
        cg_nuser_data (&nuser))
        cg_error_exit ();
    CHECK ("nuserdata", nuser == 2);
    if (cg_delete_node ("User3.2.1.1") ||
        cg_nuser_data (&nuser))
        cg_error_exit ();
    CHECK ("nuserdata", nuser == 1);

    /* don't compress file on close */

    cg_configure(CG_CONFIG_COMPRESS, (void *)0);

    puts ("closing file");
    cg_close (cgfile);

    return 0;
}