CDM version 4.3 and above allows you to programatically create, edit, and add data to netCDF-3 and netCDF-4 files, using NetcdfFileWriter or the FileWriter2 class. If you just want to copy an existing CDM dataset, you can use the CDM nccopy application. By combining nccopy and NcML, you can copy just parts of an existing dataset, as well as make modifications to it with NcML.
Writing netCDF-4 files requires that you install the netCDF-4 C library on your machine.
public static void main(String[] args) throws IOException { String location = "C:/tmp/testWrite.nc"; 1) NetcdfFileWriter writer = NetcdfFileWriter.createNew(NetcdfFileWriter.Version.netcdf3, location, null); // add dimensions 2) Dimension latDim = writer.addDimension(null, "lat", 64); Dimension lonDim = writer.addDimension(null, "lon", 128); // add Variable double temperature(lat,lon) List<Dimension> dims = new ArrayList<Dimension>(); dims.add(latDim); dims.add(lonDim); 3) Variable t = writer.addVariable(null, "temperature", DataType.DOUBLE, dims); 4) t.addAttribute(new Attribute("units", "K")); // add a 1D attribute of length 3 5) Array data = Array.factory(int.class, new int[]{3}, new int[]{1, 2, 3}); 6) t.addAttribute(new Attribute("scale", data)); // add a string-valued variable: char svar(80) Dimension svar_len = writer.addDimension(null, "svar_len", 80); 7) writer.addVariable(null, "svar", DataType.CHAR, "svar_len"); // add a 2D string-valued variable: char names(names, 80) Dimension names = writer.addDimension(null, "names", 3); 8) writer.addVariable(null, "names", DataType.CHAR, "names svar_len"); // add a scalar variable 9) writer.addVariable(null, "scalar", DataType.DOUBLE, new ArrayList<Dimension>()); // add global attributes 10) writer.addGroupAttribute(null, new Attribute("yo", "face")); writer.addGroupAttribute(null, new Attribute("versionD", 1.2)); writer.addGroupAttribute(null, new Attribute("versionF", (float) 1.2)); writer.addGroupAttribute(null, new Attribute("versionI", 1)); writer.addGroupAttribute(null, new Attribute("versionS", (short) 2)); writer.addGroupAttribute(null, new Attribute("versionB", (byte) 3)); // create the file try { 11) writer.create(); } catch (IOException e) { System.err.printf("ERROR creating file %s%n%s", location, e.getMessage()); } 12) writer.close(); }
The resulting file looks like:
netcdf C:/tmp/testWrite.nc { dimensions: lat = 64; lon = 128; svar_len = 80; names = 3; variables: double temperature(lat=64, lon=128); :units = "K"; :scale = 1, 2, 3; // int char svar(svar_len=80); char names(names=3, svar_len=80); double scalar; // global attributes: :yo = "face"; :versionD = 1.2; // double :versionF = 1.2f; // float :versionI = 1; // int :versionS = 2S; // short :versionB = 3B; // byte }
Notes:
You can now start writing data to the new file. Or you can open an existing file for example:
NetcdfFileWriter writer = NetcdfFileWriter.openExisting(location);
In both cases the data writing is the same, for example:
// write data to variable Variable v = writer.findVariable("temperature"); int[] shape = v.getShape(); 1) ArrayDouble A = new ArrayDouble.D2(shape[0], shape[1]); int i, j; Index ima = A.getIndex(); for (i = 0; i < shape[0]; i++) { for (j = 0; j < shape[1]; j++) { A.setDouble(ima.set(i, j), (double) (i * 1000000 + j * 1000)); } } 2) int[] origin = new int[2]; try { 3) writer.write(v, origin, A); } catch (IOException e) { System.err.println("ERROR writing file"); } catch (InvalidRangeException e) { e.printStackTrace(); }
// write char variable as String v = writer.findVariable("svar"); shape = v.getShape(); len = shape[0]; try { 4) ArrayChar ac2 = new ArrayChar.D1(len); ac2.setString("Two pairs of ladies stockings!"); 5) writer.write(v, ac2); } catch (IOException e) { System.err.println("ERROR writing Achar2"); assert (false); } catch (InvalidRangeException e) { e.printStackTrace(); assert (false); }
// write String array
v = writer.findVariable("names");
shape = v.getShape();
try {
6) ArrayChar ac2 = new ArrayChar.D2(shape[0], shape[1]);
ima = ac2.getIndex();
ac2.setString(ima.set(0), "No pairs of ladies stockings!");
ac2.setString(ima.set(1), "One pair of ladies stockings!");
ac2.setString(ima.set(2), "Two pairs of ladies stockings!");
writer.write(v, ac2);
} catch (IOException e) {
System.err.println("ERROR writing Achar3");
assert (false);
} catch (InvalidRangeException e) {
e.printStackTrace();
assert (false);
}
// write scalar data try { 7) ArrayDouble.D0 datas = new ArrayDouble.D0(); datas.set(222.333); v = writer.findVariable("scalar");
writer.write(v, datas); } catch (IOException e) { System.err.println("ERROR writing scalar"); } catch (InvalidRangeException e) { e.printStackTrace(); }
try { 8) ncfile.close(); } catch (IOException e) { e.printStackTrace(); }
public void testWriteRecordOneAtaTime() throws IOException, InvalidRangeException { String filename = TestLocal.temporaryDataDir + "testWriteRecord2.nc"; NetcdfFileWriter writer = NetcdfFileWriter.createNew(NetcdfFileWriter.Version.netcdf3, filename); // define dimensions, including unlimited Dimension latDim = writer.addDimension(null, "lat", 3); Dimension lonDim = writer.addDimension(null, "lon", 4); Dimension timeDim = writer.addUnlimitedDimension("time"); // define Variables Variable lat = writer.addVariable(null, "lat", DataType.FLOAT, "lat"); lat.addAttribute( new Attribute("units", "degrees_north")); Variable lon = writer.addVariable(null, "lon", DataType.FLOAT, "lon"); lon.addAttribute( new Attribute("units", "degrees_east")); Variable rh = writer.addVariable(null, "rh", DataType.INT, "time lat lon"); rh.addAttribute( new Attribute("long_name", "relative humidity")); rh.addAttribute( new Attribute("units", "percent")); Variable t = writer.addVariable(null, "T", DataType.DOUBLE, "time lat lon"); t.addAttribute( new Attribute("long_name", "surface temperature")); t.addAttribute( new Attribute("units", "degC")); Variable time = writer.addVariable(null, "time", DataType.INT, "time"); time.addAttribute( new Attribute("units", "hours since 1990-01-01")); // create the file 1) writer.create(); // write out the non-record variables 2) writer.write(lat, Array.factory(new float[]{41, 40, 39})); writer.write(lon, Array.factory(new float[]{-109, -107, -105, -103})); //// heres where we write the record variables // different ways to create the data arrays. // Note the outer dimension has shape 1, since we will write one record at a time 3) ArrayInt rhData = new ArrayInt.D3(1, latDim.getLength(), lonDim.getLength()); ArrayDouble.D3 tempData = new ArrayDouble.D3(1, latDim.getLength(), lonDim.getLength()); Array timeData = Array.factory(DataType.INT, new int[]{1}); Index ima = rhData.getIndex(); int[] origin = new int[]{0, 0, 0}; int[] time_origin = new int[]{0}; // loop over each record 4) for (int timeIdx = 0; timeIdx < 10; timeIdx++) { // make up some data for this record, using different ways to fill the data arrays. 5.1) timeData.setInt(timeData.getIndex(), timeIdx * 12); for (int latIdx = 0; latIdx < latDim.getLength(); latIdx++) { for (int lonIdx = 0; lonIdx < lonDim.getLength(); lonIdx++) { 5.2) rhData.setInt(ima.set(0, latIdx, lonIdx), timeIdx * latIdx * lonIdx); 5.3) tempData.set(0, latIdx, lonIdx, timeIdx * latIdx * lonIdx / 3.14159); } } // write the data out for one record // set the origin here 6) time_origin[0] = timeIdx; origin[0] = timeIdx; 7) writer.write(rh, origin, rhData); writer.write(t, origin, tempData); writer.write(time, time_origin, timeData); } // loop over record // all done writer.close(); }
To write to netCDF-4, you must install the netCDF-4 C library on your machine.
The main use of netCDF-4 is to get the performance benefits from compression, and possibly from chunking (why it matters). By default, the Java library will write chunked and compressed netcdf-4 files, using the default chunking algorithm. To have your own control of chunking and compression, you must create a Nc4Chunking object and pass it into NetcdfFileWriter.createNew():
Nc4Chunking chunker = Nc4Chunking factory(Strategy type, int deflateLevel, boolean shuffle); NetcdfFileWriter.Version version = NetcdfFileWriter.Version.netcdf4; FileWriter2 writer = new ucar.nc2.FileWriter2(ncfileIn, filenameOut, version, chunker); ... NetcdfFile ncfileOut = writer.write(); ncfileIn.close();
ncfileOut.close();See here for more details on Nc4Chunking.