netcdf converting_to_netcdf_basic { // CONVERTING DATA TO THE "NETWORK COMMON DATA FORM" (netCDF): // AN INTRODUCTION // // NOAA PMEL Thermal Modeling and Analysis Project (TMAP) // Dan Trueman, Steve Hankin // last revised: 1 Aug 93 // // I. INTRODUCTION // // There are two separate procedures required to convert data to // netCDF format: // // 1. The cdl file. // a. Create a cdl (the ASCII netCDF Description Language) file // that describes the grid (i.e. latitude, // longitude, depth, time) and describes but does not // actually contain values for the data variables // (i.e. temperature, salt). // b. Run this file, using a command called "ncgen," thus // creating a cdf file to which the data will be directed. // // 2. Directing of data to the cdf file. // a. Create code which: // 1. Reads the data of interest from another file or // section of code. // 2. Identifies the cdf file where the data is to be // sent. // 3. Identifies the variables of interest in the cdf // file. // 4. Defines the dimensions of the data to be sent. // 5. Writes the data to the cdf file. // // This file contains both procedures for a simple gridded oceanic data set. // A separate document describes how to set up model outputs on staggered // grids with more detailed control of grid coordinates. // // II. THE CDL FILE // // A cdl file consists of three sections: Dimensions, Variables, and Data. // // // 1. DIMENSIONS // // In this section, the sizes of the grid dimensions are specified. The // dimension which represents time can optionally be of "unlimited" size. dimensions: lon = 160 ; // longitude lat = 100 ; // latitude depth = 27 ; // depth time = unlimited ; // These are essentially parameter statements that assign certain numbers // which will be used in the Variables section to define axes and variable // dimensions. // 2. VARIABLES // // Variables, variable attributes, axes, axis attributes, and global // attributes are specified. variables: // variable definitions: float temp(time, depth, lat, lon) ; temp: long_name = "TEMPERATURE" ; temp: units = "deg. C" ; temp: _FillValue = 1.E34f ; float salt(time, depth, lat, lon) ; salt: long_name = "(SALINITY(ppt) - 35) /1000" ; salt: units = "frac. by wt. less .035" ; salt: _FillValue = -999.f ; // Variable names must not exceed 24 characters for FERRET compatibility. // FERRET is case-insensitive with respect to variable names so "temp", // "TEMP", and "Temp" are interpreted as identical names. The following // names are reserved by FERRET and should not be used: "X", "Y", "Z", // "T", "I", "J", "K", "L", "XBOX", "YBOX", "ZBOX", and "TBOX" // The _FillValue attribute informs FERRET that any data value matching // this value is a missing (invalid) data point. For example, an ocean data // set may label land locations with a value such as 1E34. By identifying // 1E34 as a "_FillValue", FERRET knows to ignore, for example, temperature // values of 1E34. Note that variables of 1, 2, and 3 dimensions are allowed // as well. See the supplement to this document for an example of a // 3-dimensional variable. // The ordering of the four dimensions, "time, depth, lat, lon", is mandatory // - permutations of this order will be mis-interpreted by FERRET. // The data type of Variables may be float (32 bit float), long (32 bit // integer), short (16 bit integer), or byte (8 bit integer). The double // data type is not supported for FERRET variables. // axis definitions: double lon(lon) ; lon: units = "degrees"; double lat(lat) ; lat: units = "degrees"; double depth(depth) ; depth: units = "meters"; depth: positive = "down"; // so netCDF doesn't think // positive is up double time(time) ; time: time_origin = "15-JAN-1972"; // date associated with t=0 time: units = "seconds"; // Axes are distinguished from other 1-dimensional netCDF variables by the // fact that their variable names are identical to their dimension names. // Any legal variable name is also a legal axis name. However, for // data sets which are 1, 2, or 3 dimensions the axis names are used as // "hints" to determine whether a given axis is latitude, longitude, // depth, or time. See converting_to_netcdf.supplement for elaboration // on axis names. // The data type of Axes may be double (64 bit floating point), float // (32 bit floating point), long (32 bit integer), short (16 bit // integer), or byte (8 bit integer). // The values of time must be positive. The time_origin attribute defines // the calendar date and time to associate with the value 0. The format of // the time_origin attribute is "dd-mmm-yyyy:hh:mm:ss". The hours, minutes, // and seconds are optional. If the time_origin attribute is absent FERRET // will not perform calendar date formatting on this axis. // global attributes: :title = "NetCDF Example"; // :message = "This message will be displayed when the CDF file is opened"; // :history = "Remarks on the origins and evolution of this dat set or // variable"; // 3. DATA // // In this section, data is entered into any of the variables. Typically, the // grid coordinates are defined here. Below, there are 100 latitude // coordinates entered (in degrees) into the variable axis lat, 160 // longitude coordinates in lon, and 27 depth coordinates (in meters) in depth. data: lat= -28.8360729218,-26.5299491882,-24.2880744934,-22.1501560211,-20.1513576508, -18.3207626343,-16.6801033020,-15.2428140640,-14.0134353638,-12.9874248505, -12.1513509750,-11.4834814072,-10.9547319412,-10.5299386978,-10.1693935394, -9.8333206177,-9.4999876022,-9.1666536331,-8.8333196640,-8.4999856949, -8.1666526794,-7.8333187103,-7.4999847412,-7.1666512489,-6.8333182335, -6.4999852180,-6.1666517258,-5.8333182335,-5.4999852180,-5.1666517258, -4.8333187103,-4.4999852180,-4.1666517258,-3.8333187103,-3.4999852180, -3.1666517258,-2.8333184719,-2.4999852180,-2.1666519642,-1.8333185911, -1.4999852180,-1.1666518450,-0.8333183527,-0.4999849498,-0.1666515470, 0.1666818559,0.5000152588,0.8333486915,1.1666821241,1.5000154972, 1.8333489895,2.1666824818,2.5000159740,2.8333494663,3.1666829586, 3.5000162125,3.8333497047,4.1666831970,4.5000162125,4.8333497047, 5.1666831970,5.5000162125,5.8333497047,6.1666827202,6.5000162125, 6.8333497047,7.1666827202,7.5000166893,7.8333501816,8.1666841507, 8.5000181198,8.8333511353,9.1666851044,9.5000190735,9.8333530426, 10.1679363251,10.5137376785,10.8892869949,11.3138961792,11.8060989380, 12.3833675385,13.0618314743,13.8560228348,14.7786512375,15.8403968811, 17.0497493744,18.4128704071,19.9334945679,21.6128730774,23.4497566223, 25.4404067993,27.5786647797,29.8560409546,32.2618522644,34.7833900452, 37.4061241150,40.1139259338,42.8893203735,45.7137718201,48.5679702759; lon= 130.5,131.5,132.5,133.5,134.5,135.5,136.5,137.5,138.5,139.5,140.5,141.5,142.5, 143.5,144.5,145.5,146.5,147.5,148.5,149.5,150.5,151.5,152.5,153.5,154.5,155.5, 156.5,157.5,158.5,159.5,160.5,161.5,162.5,163.5,164.5,165.5,166.5,167.5,168.5, 169.5,170.5,171.5,172.5,173.5,174.5,175.5,176.5,177.5,178.5,179.5,180.5,181.5, 182.5,183.5,184.5,185.5,186.5,187.5,188.5,189.5,190.5,191.5,192.5,193.5,194.5, 195.5,196.5,197.5,198.5,199.5,200.5,201.5,202.5,203.5,204.5,205.5,206.5,207.5, 208.5,209.5,210.5,211.5,212.5,213.5,214.5,215.5,216.5,217.5,218.5,219.5,220.5, 221.5,222.5,223.5,224.5,225.5,226.5,227.5,228.5,229.5,230.5,231.5,232.5,233.5, 234.5,235.5,236.5,237.5,238.5,239.5,240.5,241.5,242.5,243.5,244.5,245.5,246.5, 247.5,248.5,249.5,250.5,251.5,252.5,253.5,254.5,255.5,256.5,257.5,258.5,259.5, 260.5,261.5,262.5,263.5,264.5,265.5,266.5,267.5,268.5,269.5,270.5,271.5,272.5, 273.5,274.5,275.5,276.5,277.5,278.5,279.5,280.5,281.5,282.5,283.5,284.5,285.5, 286.5,287.5,288.5,289.5; depth= 5.0,15.0,25.0,35.0,45.0,55.0,65.0,75.0,85.0,95.0,106.25,120.0,136.25,155.0, 177.5,205.0,240.0,288.5,362.5,483.5,680.0,979.5,1395.5,1916.0,2524.0,3174.0, 3824.0; // This next data entry, for time, should be ignored. Time is initialized here // only so that FERRET can read test.cdf as generated by the ncgen utility. // (the file created by this cdl file). If "time" were left uninitialized the // resulting time axis would be of zero length. time=1000; // To run this program in the UNIX environment, use: // // ncgen -o test.cdf converting_to_netcdf.basic // // This will will create a file called "test.cdf" to which data can be // directed. } // // III. DIRECTING DATA TO TEST.CDF // // program netCDF_write // //c This program reads in gridded oceanic temperature and salt data and //c writes it out into the netCDF file "test.cdf." //************************************************************************* //c An alternative to writing this program is to use the command: // //c ncgen -f converting_to_netcdf.basic // //c This will create a large source code to which select lines can //c be added to write out your data. //************************************************************************* //c To compile and link netCDF_write.f, use: // //c f77 -o netCDF_write netCDF_write.f -lnetCDF // //************************************************************************* //c include file necessary for netCDF // // include 'netCDF.inc' //************************************************************************* //c parameters relevant to the data being read in // // integer imt, jmt, km, nt, lnew, inlun // parameter (imt=160, jmt=100, km=27, nt=5) // //c imt is longitude, jmt latitude, km depth, and nt number of time steps //************************************************************************* //c variable declaration // // real temp(imt,jmt,km),salt(imt,jmt,km) // // integer cdfid, rcode //c ** cdfid = id number for the netCDF file test.cdf //c ** rcode = error id number // // integer tid, sid, timeaxid //c ** tid = variable id number for temperature //c ** sid = variable id number for salt //c ** timeaxid = variable id for the time axis // integer itime //c ** itime = index for do loop //************************************************************************* //c dimension corner and step for defining size of gridded data // // integer corner(4) // integer step(4) // //c corner and step are used to define the size of the gridded data //c to be written out. Since temp and salt are four dimensional arrays, //c corner and step must be four dimensions as well. In each output //c to test.cdf within the do loop, the entire array of data (160 long. pts, //c 100 lat. pts., 27 depth pts.) will be written for one time step. //c Corner tells netCDF where to start, and step indicates how many steps //c in each dimension to take. // // data corner/1, 1, 1, -1/ ! -1 is arbitrary; the time value // ! of corner will be initialized // ! within the do loop. // // data step/imt, jmt, km, 1/ ! NOT /1, km, jmt, imt/ // //c ***NOTE*** Since Fortran and C access data differently, the order of //c the variables in the Fortran code must be opposite that in the cdl //c file. In Fortran, the first variable varies fastest while in C, the //c last variables varies fastest. //************************************************************************** //c initialize cdfid by using ncopn // // cdfid = ncopn('test.cdf', ncwrite, rcode) // if (rcode.ne.ncnoerr) stop 'error with ncopn' // //************************************************************************** //c get variable id's by using ncvid // // tid = ncvid(cdfid, 'temp', rcode) // if (rcode.ne.ncnoerr) stop 'error with tid' // sid = ncvid(cdfid, 'salt', rcode) // if (rcode.ne.ncnoerr) stop 'error with sid' // timeaxid = ncvid(cdfid, 'time', rcode) // if (rcode.ne.ncnoerr) stop 'error with timeaxid' //************************************************************************** //c begin do loop. Each step will read in one time step of data //c and then write it out to test.cdf. // // do 10 itime = 1, nt // // corner(4) = itime ! initialize time step in corner // // call read_my_data(temp,salt) ! you write this // // call ncvpt(cdfid,tid,corner,step,temp(1,1,1),rcode) ! write data to // if (rcode.ne.ncnoerr) stop 'error with t-put' // call ncvpt(cdfid,sid,corner,step,salt(1,1,1),rcode) ! test.cdf with ncvpt // if (rcode.ne.ncnoerr) stop 'error with s-put' // call ncvpt1(cdfid,timeaxid,itime,DBLE(itime),rcode) // if (rcode.ne.ncnoerr) stop 'error with timax-put' // //c ncvpt1 writes a single data point to the specified location within timeaxid. //c The itime argument in ncvpt1 specifies the location within time to write. //c The DBLE(itime) argument is the value to be written; DBLS(itime) is used //c (rather than simply itime) so the type matches the type of time declared in //c the CDL file. Instructions for dealing with more complex time labels are in //c the supplement to this document, converting_to_netcdf.supplement. // // 10 continue //************************************************************************** //c close test.cdf using ncclos // // call ncclos(cdfid, rcode) // if (rcode.ne.ncnoerr) stop 'error with ncclos' //************************************************************************** // stop // end //**************************************************************************