/* This is part of the netCDF package.
   Copyright 2006 University Corporation for Atmospheric Research/Unidata.
   See COPYRIGHT file for conditions of use.

   This is an example program which writes some 4D pressure and
   temperatures. This example demonstrates the netCDF C++ API. 

   This is part of the netCDF tutorial:
   http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

   Full documentation of the netCDF C++ API can be found at:
   http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx

   $Id: pres_temp_4D_wr.cpp,v 1.11 2007/01/19 12:52:13 ed Exp $
*/

#include <iostream>
#include <netcdfcpp.h>

using namespace std;

// We are writing 4D data, a 2 x 6 x 12 lvl-lat-lon grid, with 2
// timesteps of data.
static const int NLVL = 2;
static const int NLAT = 6;
static const int NLON = 12;
static const int NREC = 2;

// These are used to construct some example data. 
static const float SAMPLE_PRESSURE = 900.0;
static const float SAMPLE_TEMP = 9.0;
static const float START_LAT = 25.0;
static const float START_LON = -125.0;

// Return this code to the OS in case of failure.
static const int NC_ERR = 2;

int main()
{
   // These arrays will store the latitude and longitude values.
   float lats[NLAT],lons[NLON];

   // These arrays will hold the data we will write out. We will
   // only need enough space to hold one timestep of data; one record.
   float pres_out[NLVL][NLAT][NLON];
   float temp_out[NLVL][NLAT][NLON];

   int i = 0;
  
   // Create some pretend data. If this wasn't an example program, we
   // would have some real data to write for example, model output.
   for (int lat = 0; lat < NLAT; lat++)
      lats[lat] = START_LAT + 5. * lat;
   for (int lon = 0; lon < NLON; lon++)
      lons[lon] = START_LON + 5. * lon;

   for (int lvl = 0; lvl < NLVL; lvl++)
      for (int lat = 0; lat < NLAT; lat++)
	 for (int lon = 0; lon < NLON; lon++)
	 {
	    pres_out[lvl][lat][lon] = SAMPLE_PRESSURE + i;
	    temp_out[lvl][lat][lon]  = SAMPLE_TEMP + i++;
	 }
   
   // Change the error behavior of the netCDF C++ API by creating an
   // NcError object. Until it is destroyed, this NcError object will
   // ensure that the netCDF C++ API returns error codes on any
   // failure, prints an error message, and leaves any other error
   // handling to the calling program. In the case of this example, we
   // just exit with an NC_ERR error code.
   NcError err(NcError::verbose_nonfatal);

   // Create the file.
   NcFile dataFile("pres_temp_4D.nc", NcFile::Replace);

   // Check to see if the file was created.
   if(!dataFile.is_valid())
      return NC_ERR;

   // Define the dimensions. NetCDF will hand back an ncDim object for
   // each.
   NcDim *lvlDim, *latDim, *lonDim, *recDim;
   if (!(lvlDim = dataFile.add_dim("level", NLVL)))
      return NC_ERR;
   if (!(latDim = dataFile.add_dim("latitude", NLAT)))
      return NC_ERR;
   if (!(lonDim = dataFile.add_dim("longitude", NLON)))
      return NC_ERR;
   // Add an unlimited dimension...
   if (!(recDim = dataFile.add_dim("time")))
      return NC_ERR;
       
   // Define the coordinate variables.
   NcVar *latVar, *lonVar;
   if (!(latVar = dataFile.add_var("latitude", ncFloat, latDim)))
      return NC_ERR;
   if (!(lonVar = dataFile.add_var("longitude", ncFloat, lonDim)))
      return NC_ERR;
       
   // Define units attributes for coordinate vars. This attaches a
   // text attribute to each of the coordinate variables, containing
   // the units.
   if (!latVar->add_att("units", "degrees_north"))
      return NC_ERR;
   if (!lonVar->add_att("units", "degrees_east"))
      return NC_ERR;
       
   // Define the netCDF variables for the pressure and temperature
   // data.
   NcVar *presVar, *tempVar;
   if (!(presVar = dataFile.add_var("pressure", ncFloat, recDim, 
				    lvlDim, latDim, lonDim)))
      return NC_ERR;
   if (!(tempVar = dataFile.add_var("temperature", ncFloat, recDim, 
				    lvlDim, latDim, lonDim)))
      return NC_ERR;       

   // Define units attributes for data variables.
   if (!presVar->add_att("units", "hPa"))
      return NC_ERR;       
   if (!tempVar->add_att("units", "celsius"))
      return NC_ERR;       

   // Write the coordinate variable data to the file.
   if (!latVar->put(lats, NLAT))
      return NC_ERR;       
   if (!lonVar->put(lons, NLON))
      return NC_ERR;       
            
   // Write the pretend data. This will write our surface pressure and
   // surface temperature data. The arrays only hold one timestep
   // worth of data. We will just rewrite the same data for each
   // timestep. In a real application, the data would change between
   // timesteps.
   for (int rec = 0; rec < NREC; rec++) 
   {
      if (!presVar->put_rec(&pres_out[0][0][0], rec))
	 return NC_ERR;       
      if (!tempVar->put_rec(&temp_out[0][0][0], rec))
	 return NC_ERR;       
   }

   // The file is automatically closed by the destructor. This frees
   // up any internal netCDF resources associated with the file, and
   // flushes any buffers.
   
   cout << "*** SUCCESS writing example file pres_temp_4D.nc!" << endl;
   return 0;
}
