ucar.nc2.dt.grid.NetcdfCFWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of netcdf Show documentation
Show all versions of netcdf Show documentation
The NetCDF-Java Library is a Java interface to NetCDF files,
as well as to many other types of scientific data formats.
The newest version!
/*
* Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package ucar.nc2.dt.grid;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import ucar.ma2.Array;
import ucar.ma2.DataType;
import ucar.ma2.InvalidRangeException;
import ucar.ma2.Range;
import ucar.nc2.Attribute;
import ucar.nc2.Dimension;
import ucar.nc2.FileWriter2;
import ucar.nc2.NetcdfFile;
import ucar.nc2.NetcdfFileWriter;
import ucar.nc2.Variable;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants.CDM;
import ucar.nc2.constants.CF;
import ucar.nc2.constants._Coordinate;
import ucar.nc2.dataset.CoordinateAxis;
import ucar.nc2.dataset.CoordinateAxis1D;
import ucar.nc2.dataset.CoordinateAxis1DTime;
import ucar.nc2.dataset.CoordinateAxis2D;
import ucar.nc2.dataset.CoordinateTransform;
import ucar.nc2.dataset.NetcdfDataset;
import ucar.nc2.dataset.ProjectionCT;
import ucar.nc2.dataset.TransformType;
import ucar.nc2.dataset.transform.AbstractCoordTransBuilder;
import ucar.nc2.dt.GridCoordSystem;
import ucar.nc2.dt.GridDatatype;
import ucar.nc2.jni.netcdf.Nc4Chunking;
import ucar.nc2.jni.netcdf.Nc4ChunkingStrategyGrib;
import ucar.nc2.time.CalendarDateRange;
import ucar.nc2.units.DateFormatter;
import ucar.unidata.geoloc.*;
import ucar.unidata.geoloc.projection.LatLonProjection;
import ucar.unidata.util.Parameter;
/**
* Write a CF compliant Netcdf-3 or netcdf-4 file (classic mode only) from any gridded dataset.
* The datasets can optionally be subsetted by a lat/lon bounding box and/or a time range.
*
* @author caron
*/
public class NetcdfCFWriter {
static private final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NetcdfCFWriter.class);
/**
* Write a netcdf-3 file from a subset of a grid dataset
* @param location write new file
* @param gds from this grid dataset
* @param gridList just these grids
* @param llbb horiz subset, may be null
* @param range time subset, may be null
* @throws IOException
* @throws InvalidRangeException
*/
static public void makeFile(String location, ucar.nc2.dt.GridDataset gds, List gridList, LatLonRect llbb, CalendarDateRange range)
throws IOException, InvalidRangeException {
NetcdfCFWriter writer = new NetcdfCFWriter();
writer.makeFile(location, gds, gridList, llbb, range, false, 1, 1, 1);
}
static public void makeFileVersioned(String location, ucar.nc2.dt.GridDataset gds, List gridList, LatLonRect llbb,
CalendarDateRange dateRange, NetcdfFileWriter.Version version)
throws IOException, InvalidRangeException {
NetcdfCFWriter writer = new NetcdfCFWriter();
writer.makeOrTestSize(location, gds, gridList, llbb, 1, null, dateRange, 1, false, false, version);
}
/**
* Write a netcdf-3 file from a subset of a grid dataset, as long as it doesnt exceed a certain file size.
*
* @param gds from this grid dataset
* @param gridList just these grids
* @param llbb horiz subset, may be null
* @param zRange vertical subset, may be null
* @param dateRange time subset, may be null
* @param stride_time time may be strided, -1 if want all
* @param addLatLon optionally add a lat/lon coordinate (if dataset uses projection coords)
* @return file size
* @throws IOException
* @throws InvalidRangeException
*/
public long makeGridFileSizeEstimate(ucar.nc2.dt.GridDataset gds, List gridList,
LatLonRect llbb, int horizStride,
Range zRange,
CalendarDateRange dateRange, int stride_time,
boolean addLatLon) throws IOException, InvalidRangeException {
return makeOrTestSize(null, gds, gridList, llbb, horizStride, zRange, dateRange, stride_time, addLatLon, true, NetcdfFileWriter.Version.netcdf3);
}
/**
* Write a netcdf-3 file from a subset of a grid dataset (projection coordinates), as long as it doesnt exceed a certain file size.
* @param gds from this grid dataset
* @param gridList just these grids
* @param projBB horiz subset in Projection coords, may be null
* @param zRange vertical subset, may be null
* @param dateRange time subset, may be null
* @param stride_time time may be strided, -1 if want all
* @param addLatLon optionally add a lat/lon coordinate (if dataset uses projection coords)
* @return file size
* @throws IOException
* @throws InvalidRangeException
*/
public long makeGridFileSizeEstimate(ucar.nc2.dt.GridDataset gds, List gridList,
ProjectionRect projBB, int horizStride,
Range zRange,
CalendarDateRange dateRange, int stride_time,
boolean addLatLon) throws IOException, InvalidRangeException {
return makeOrTestSize(null, gds, gridList, projBB, horizStride, zRange, dateRange, stride_time, addLatLon, true, NetcdfFileWriter.Version.netcdf3);
}
/**
* Write a CF compliant Netcdf-3 file from any gridded dataset.
*
* @param location write to this location on disk
* @param gds A gridded dataset
* @param gridList the list of grid names to be written, must not be empty. Full name (not short).
* @param llbb optional lat/lon bounding box
* @param range optional time range
* @param addLatLon should 2D lat/lon variables be added, if its a projection coordinate system?
* @param horizStride x,y stride
* @param stride_z not implemented yet
* @param stride_time not implemented yet
* @throws IOException if write or read error
* @throws InvalidRangeException if subset is illegal
*/
public void makeFile(String location, ucar.nc2.dt.GridDataset gds, List gridList,
LatLonRect llbb, CalendarDateRange range,
boolean addLatLon,
int horizStride, int stride_z, int stride_time)
throws IOException, InvalidRangeException {
makeFile(location, gds, gridList, llbb, horizStride, null, range, stride_time, addLatLon, NetcdfFileWriter.Version.netcdf3);
}
public long makeFile(String location, ucar.nc2.dt.GridDataset gds, List gridList,
LatLonRect llbb, int horizStride, Range zRange,
CalendarDateRange dateRange, int stride_time,
boolean addLatLon)
throws IOException, InvalidRangeException {
return makeOrTestSize(location, gds, gridList, llbb, horizStride, zRange, dateRange, stride_time, addLatLon, false, NetcdfFileWriter.Version.netcdf3);
}
public long makeFile(String location, ucar.nc2.dt.GridDataset gds, List gridList,
LatLonRect llbb, int horizStride, Range zRange,
CalendarDateRange dateRange, int stride_time,
boolean addLatLon, NetcdfFileWriter.Version version)
throws IOException, InvalidRangeException {
return makeOrTestSize(location, gds, gridList, llbb, horizStride, zRange, dateRange, stride_time, addLatLon, false, version);
}
public long makeFile(String location, ucar.nc2.dt.GridDataset gds, List gridList,
ProjectionRect llbb, int horizStride,
Range zRange,
CalendarDateRange dateRange, int stride_time,
boolean addLatLon)
throws IOException, InvalidRangeException {
return makeOrTestSize(location, gds, gridList, llbb, horizStride, zRange, dateRange, stride_time, addLatLon, false, NetcdfFileWriter.Version.netcdf3);
}
public long makeFile(String location, ucar.nc2.dt.GridDataset gds, List gridList,
ProjectionRect llbb, int horizStride,
Range zRange,
CalendarDateRange dateRange, int stride_time,
boolean addLatLon, NetcdfFileWriter.Version version)
throws IOException, InvalidRangeException {
return makeOrTestSize(location, gds, gridList, llbb, horizStride, zRange, dateRange, stride_time, addLatLon, false, version);
}
private long makeOrTestSize(String location, ucar.nc2.dt.GridDataset gds, List gridList,
LatLonRect llbb, int horizStride,
Range zRange,
CalendarDateRange dateRange, int stride_time,
boolean addLatLon, boolean testSizeOnly,
NetcdfFileWriter.Version version)
throws IOException, InvalidRangeException {
NetcdfDataset ncd = (NetcdfDataset) gds.getNetcdfFile();
LatLonRect llrect = new LatLonRect();
ArrayList varList = new ArrayList();
ArrayList varNameList = new ArrayList();
ArrayList axisList = new ArrayList();
LatLonRect resultBB = null;
// add each desired Grid to the new file
long total_size = 0;
for (String gridName : gridList) {
if (varNameList.contains(gridName))
continue;
varNameList.add(gridName);
GridDatatype grid = gds.findGridDatatype(gridName);
GridCoordSystem gcsOrg = grid.getCoordinateSystem();
CoordinateAxis1DTime timeAxis = gcsOrg.getTimeAxis1D();
CoordinateAxis1D vertAxis = gcsOrg.getVerticalAxis();
boolean global = gcsOrg.isGlobalLon();
// make subset if needed
Range timeRange = makeTimeRange(dateRange, timeAxis, stride_time);
Range zRangeUse = makeVerticalRange(zRange, vertAxis);
if ((null != timeRange) || (zRangeUse != null) || (llbb != null) || (horizStride > 1)) {
grid = grid.makeSubset(timeRange, zRangeUse, llbb, 1, horizStride, horizStride);
LatLonRect gridBB = grid.getCoordinateSystem().getLatLonBoundingBox();
if (resultBB == null)
resultBB = gridBB;
else
resultBB.extend(gridBB);
}
Variable gridV = grid.getVariable();
varList.add(gridV);
total_size += gridV.getSize() * gridV.getElementSize();
// add coordinate axes
GridCoordSystem gcs = grid.getCoordinateSystem();
llrect = gcs.getLatLonBoundingBox();
addCoordinateAxis(gcs, varNameList, varList, axisList);
// add coordinate transform variables
addCoordinateTransform(gcs, ncd, varNameList, varList);
//Add Variables from the formula_terms
total_size += processTransformationVars(varList, varNameList, ncd, gds, grid, timeRange, zRangeUse, llbb, 1, horizStride, horizStride, axisList );
// optional lat/lon
if (addLatLon) {
Projection proj = gcs.getProjection();
if ((null != proj) && !(proj instanceof LatLonProjection)) {
addLatLon2D(ncd, varList, proj, gcs.getXHorizAxis(), gcs.getYHorizAxis());
addLatLon = false;
}
}
}
if (testSizeOnly)
return total_size;
// check size is ok
boolean isLargeFile = isLargeFile(total_size);
//Default chunking strategy for NCSS will be used if chunking = null
Nc4Chunking chunking = null;
if( version == NetcdfFileWriter.Version.netcdf4 ){
//version = NetcdfFileWriter.Version.netcdf4_classic;
//use grib chunking as default --> one chunk for each (y,x)-slide
chunking = new Nc4ChunkingStrategyGrib(5, true);
}
NetcdfFileWriter writer = NetcdfFileWriter.createNew(version, location, chunking);
//writer.setLargeFile(isLargeFile);
writeGlobalAttributes(writer, gds, resultBB);
// use fileWriter to copy the variables
FileWriter2 fileWriter = new FileWriter2(writer);
for (Variable v : varList)
fileWriter.addVariable(v);
addCFAnnotations(writer, gds, gridList, ncd, axisList, addLatLon);
writer.create();
// use fileWriter to copy the data
fileWriter.copyVarData(varList, null, null);
//updateGeospatialRanges(writer, llrect );
writer.close();
// this writes the data to the new file.
return 0; // ok
}
private long makeOrTestSize(String location, ucar.nc2.dt.GridDataset gds, List gridList,
ProjectionRect llbb, int horizStride,
Range zRange,
CalendarDateRange dateRange, int stride_time,
boolean addLatLon, boolean testSizeOnly,
NetcdfFileWriter.Version version)
throws IOException, InvalidRangeException {
NetcdfDataset ncd = (NetcdfDataset) gds.getNetcdfFile();
ArrayList varList = new ArrayList();
ArrayList varNameList = new ArrayList();
ArrayList axisList = new ArrayList();
LatLonRect resultBB = null;
LatLonRect llrec = new LatLonRect();
// add each desired Grid to the new file
long total_size = 0;
for (String gridName : gridList) {
if (varNameList.contains(gridName))
continue;
varNameList.add(gridName);
//GridDatatype grid = gds.findGridDatatype(gridName);
GeoGrid grid = (GeoGrid) gds.findGridDatatype(gridName);
GridCoordSystem gcsOrg = grid.getCoordinateSystem();
CoordinateAxis1DTime timeAxis = gcsOrg.getTimeAxis1D();
CoordinateAxis1D vertAxis = gcsOrg.getVerticalAxis();
// make subset if needed
Range timeRange = makeTimeRange(dateRange, timeAxis, stride_time);
if( gcsOrg.getXHorizAxis().getRank() >1 || gcsOrg.getYHorizAxis().getRank() > 1){
throw new IllegalArgumentException("Coordinate systems with 2D horizontal axis are not supported");
}
CoordinateAxis1D xAxis = (CoordinateAxis1D) gcsOrg.getXHorizAxis();
double[] xCoords = xAxis.getCoordValues();
CoordinateAxis1D yAxis = (CoordinateAxis1D) gcsOrg.getYHorizAxis();
double[] yCoords = yAxis.getCoordValues();
ProjectionRect fullBB = new ProjectionRect(xCoords[0], yCoords[0], xCoords[xCoords.length-1], yCoords[yCoords.length-1]);
if( !llbb.intersects(fullBB) ){
throw new InvalidRangeException("BBOX must intersect grid BBOX, minx="+xCoords[0]+", miny="+yCoords[0]+", maxx="+xCoords[xCoords.length-1]+", maxy="+yCoords[yCoords.length-1]);
}
ProjectionRect.intersect(fullBB, llbb, llbb);
ProjectionPoint lowerLeft = llbb.getLowerLeftPoint();
ProjectionPoint upperRigth = llbb.getUpperRightPoint();
double minx = lowerLeft.getX();
double miny = lowerLeft.getY();
double maxx = upperRigth.getX();
double maxy = upperRigth.getY();
//y_range
int minyCoord = yAxis.findCoordElement(miny);
int maxyCoord = yAxis.findCoordElement(maxy);
//x_range
int minxCoord = xAxis.findCoordElement(minx);
int maxxCoord = xAxis.findCoordElement(maxx);
Range y_range = new Range(minyCoord, maxyCoord, horizStride);
Range x_range = new Range(minxCoord, maxxCoord, horizStride);
Range zRangeUse = makeVerticalRange(zRange, vertAxis);
if ((null != timeRange) || (zRangeUse != null) || (llbb != null) || (horizStride > 1)) {
grid = grid.subset(timeRange, zRangeUse, y_range, x_range);
LatLonRect gridBB = grid.getCoordinateSystem().getLatLonBoundingBox();
if (resultBB == null)
resultBB = gridBB;
else
resultBB.extend(gridBB);
}
Variable gridV = grid.getVariable();
varList.add(gridV);
total_size += gridV.getSize() * gridV.getElementSize();
GridCoordSystem gcs = grid.getCoordinateSystem();
llrec = gcs.getLatLonBoundingBox();
// add coordinate axes
addCoordinateAxis(gcs, varNameList, varList, axisList);
//add coordinate transforms
addCoordinateTransform(gcs, ncd, varNameList, varList);
//Add Variables from the formula_terms
total_size += processTransformationVars(varList, varNameList, ncd, gds, grid, timeRange, zRangeUse, y_range, x_range, 1, horizStride, horizStride );
// optional lat/lon
if (addLatLon) {
Projection proj = gcs.getProjection();
if ((null != proj) && !(proj instanceof LatLonProjection)) {
addLatLon2D(ncd, varList, proj, gcs.getXHorizAxis(), gcs.getYHorizAxis());
addLatLon = false;
}
}
}
if (testSizeOnly)
return total_size;
// check size is ok
boolean isLargeFile = isLargeFile(total_size);
//Default chunking strategy for NCSS
Nc4Chunking chunking = null;
if (version == NetcdfFileWriter.Version.netcdf4){
//version = NetcdfFileWriter.Version.netcdf4_classic;
//use grib chunking as default --> one chunk for each (y,x)-slide
chunking = new Nc4ChunkingStrategyGrib(5, true);
}
//NetcdfFileWriter writer = NetcdfFileWriter.createNew(version, location, null);
NetcdfFileWriter writer = NetcdfFileWriter.createNew(version, location, chunking);
writer.setLargeFile(isLargeFile);
writeGlobalAttributes(writer, gds, resultBB);
// use fileWriter to copy the variables
FileWriter2 fileWriter = new FileWriter2(writer);
for (Variable v : varList)
fileWriter.addVariable(v);
addCFAnnotations(writer, gds, gridList, ncd, axisList, addLatLon);
writer.create();
//updateGeospatialRanges(writer, llrec);
// use fileWriter to copy the data
fileWriter.copyVarData(varList, null, null);
writer.close();
//updateGeospatialRanges(location, llrec);
return 0; // ok
}
/**
* Looks for the attributes in the unidata discovery conventions and, if present, updates their values
* to the values in the new axes.
*
* @param writer
* @param axisList
* @throws IOException
*/
/**
private void updateGeospatialRanges(NetcdfFileWriter writer, LatLonRect llRect) throws IOException{
//Flush before updating...
writer.flush();
//should we add them if they are not present??
if(writer.getNetcdfFile().findAttribute("@"+CDM.LAT_MIN)!=null){
Attribute from = writer.getNetcdfFile().findAttribute("@"+CDM.LAT_MIN);
updateAttribute(writer, from, CDM.LAT_MIN, llRect.getLatMin());
}
if(writer.getNetcdfFile().findAttribute("@"+CDM.LAT_MAX)!=null){
Attribute from = writer.getNetcdfFile().findAttribute("@"+CDM.LAT_MAX);
updateAttribute(writer, from, CDM.LAT_MAX, llRect.getLatMax());
}
if(writer.getNetcdfFile().findAttribute("@"+CDM.LON_MIN)!=null){
Attribute from = writer.getNetcdfFile().findAttribute("@"+CDM.LON_MIN);
updateAttribute(writer, from, CDM.LON_MIN, llRect.getLonMin());
}
if(writer.getNetcdfFile().findAttribute("@"+CDM.LON_MAX )!=null){
Attribute from = writer.getNetcdfFile().findAttribute("@"+CDM.LON_MAX);
updateAttribute(writer, from, CDM.LON_MAX, llRect.getLonMax());
}
}
private void updateAttribute(NetcdfFileWriter writer, Attribute from, String attName, double value) throws IOException{
if( from.getDataType() == DataType.FLOAT )
writer.updateAttribute(null, new Attribute( attName, (float) value));
else
writer.updateAttribute(null, new Attribute( attName, value));
}
*/
private void convertProjectionCTV(NetcdfDataset ds, Variable ctv) {
Attribute att = ctv.findAttribute(_Coordinate.TransformType);
if ((null != att) && att.getStringValue().equals("Projection")) {
Attribute east = ctv.findAttribute("false_easting");
Attribute north = ctv.findAttribute("false_northing");
if ((null != east) || (null != north)) {
double scalef = AbstractCoordTransBuilder.getFalseEastingScaleFactor(ds, ctv);
if (scalef != 1.0) {
convertAttribute(ctv, east, scalef);
convertAttribute(ctv, north, scalef);
}
}
}
}
private void convertAttribute(Variable ctv, Attribute att, double scalef) {
if (att == null) return;
double val = scalef * att.getNumericValue().doubleValue();
ctv.addAttribute(new Attribute(att.getShortName(), val));
}
private void addLatLon2D(NetcdfFile ncfile, List varList, Projection proj,
CoordinateAxis xaxis, CoordinateAxis yaxis) throws IOException {
double[] xData = (double[]) xaxis.read().get1DJavaArray(double.class);
double[] yData = (double[]) yaxis.read().get1DJavaArray(double.class);
List dims = new ArrayList();
dims.add(yaxis.getDimension(0));
dims.add(xaxis.getDimension(0));
Variable latVar = new Variable(ncfile, null, null, "lat");
latVar.setDataType(DataType.DOUBLE);
latVar.setDimensions(dims);
latVar.addAttribute(new Attribute(CDM.UNITS, CDM.LAT_UNITS));
latVar.addAttribute(new Attribute(CDM.LONG_NAME, "latitude coordinate"));
latVar.addAttribute(new Attribute("standard_name", "latitude"));
latVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Lat.toString()));
Variable lonVar = new Variable(ncfile, null, null, "lon");
lonVar.setDataType(DataType.DOUBLE);
lonVar.setDimensions(dims);
lonVar.addAttribute(new Attribute(CDM.UNITS, CDM.LON_UNITS));
lonVar.addAttribute(new Attribute(CDM.LONG_NAME, "longitude coordinate"));
lonVar.addAttribute(new Attribute("standard_name", "longitude"));
lonVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Lon.toString()));
int nx = xData.length;
int ny = yData.length;
// create the data
ProjectionPointImpl projPoint = new ProjectionPointImpl();
LatLonPointImpl latlonPoint = new LatLonPointImpl();
double[] latData = new double[nx * ny];
double[] lonData = new double[nx * ny];
for (int i = 0; i < ny; i++) {
for (int j = 0; j < nx; j++) {
projPoint.setLocation(xData[j], yData[i]);
proj.projToLatLon(projPoint, latlonPoint);
latData[i * nx + j] = latlonPoint.getLatitude();
lonData[i * nx + j] = latlonPoint.getLongitude();
}
}
Array latDataArray = Array.factory(DataType.DOUBLE, new int[]{ny, nx}, latData);
latVar.setCachedData(latDataArray, false);
Array lonDataArray = Array.factory(DataType.DOUBLE, new int[]{ny, nx}, lonData);
lonVar.setCachedData(lonDataArray, false);
varList.add(latVar);
varList.add(lonVar);
}
private Range makeVerticalRange(Range zRange, CoordinateAxis1D vertAxis) throws InvalidRangeException {
return (zRange != null) && (vertAxis != null) && (vertAxis.getSize() > 1) ? zRange : null;
}
private Range makeTimeRange(CalendarDateRange dateRange, CoordinateAxis1DTime timeAxis, int stride_time) throws InvalidRangeException {
Range timeRange = null;
if ((dateRange != null) && (timeAxis != null)) {
int startIndex = timeAxis.findTimeIndexFromCalendarDate(dateRange.getStart());
int endIndex = timeAxis.findTimeIndexFromCalendarDate(dateRange.getEnd());
if (startIndex < 0)
throw new InvalidRangeException("start time=" + dateRange.getStart() + " must be >= " + timeAxis.getCalendarDate(0));
if (endIndex < 0)
throw new InvalidRangeException("end time=" + dateRange.getEnd() + " must be >= " + timeAxis.getCalendarDate(0));
if (stride_time <= 1) stride_time = 1;
timeRange = new Range(startIndex, endIndex, stride_time);
}
return timeRange;
}
private void addCoordinateAxis(GridCoordSystem gcs, List varNameList, List varList, List axisList) {
for (CoordinateAxis axis : gcs.getCoordinateAxes()) {
if (!varNameList.contains(axis.getFullName())) {
varNameList.add(axis.getFullName());
varList.add(axis);
axisList.add(axis);
//if (timeAxis != null && timeAxis.isInterval()) {
// LOOK gotta add the bounds !!!
//}
}
}
}
private void addCoordinateTransform(GridCoordSystem gcs, NetcdfFile ncd, List varNameList, List varList) {
for (CoordinateTransform ct : gcs.getCoordinateTransforms()) {
Variable v = ncd.findVariable(ct.getName());
if (!varNameList.contains(ct.getName()) && (null != v)) {
varNameList.add(ct.getName());
varList.add(v);
}
}
}
/**
*
* Process the coordinate transformations (formula_terms) and adds the variables needed for performing that transformation to the list of variables in the new file.
* Also, subsets the grids variables, if needed.
*
* @param varList
* @param varNameList
* @param ncd
* @param gds
* @param grid
* @param timeRange
* @param zRangeUse
* @param llbb
* @param z_stride
* @param y_stride
* @param x_stride
* @return size of the added variables
* @throws InvalidRangeException
*/
private long processTransformationVars(ArrayList varList, ArrayList varNameList , NetcdfDataset ncd, ucar.nc2.dt.GridDataset gds, GridDatatype grid, Range timeRange, Range zRangeUse, LatLonRect llbb, int z_stride, int y_stride, int x_stride, List axisList) throws InvalidRangeException {
List yxRanges = new ArrayList(2);
if(llbb == null){
yxRanges.add(null);
yxRanges.add(null);
}else{
yxRanges = grid.getCoordinateSystem().getRangesFromLatLonRect(llbb);
}
return processTransformationVars(varList, varNameList, ncd, gds, grid, timeRange, zRangeUse, yxRanges.get(0), yxRanges.get(1), z_stride, y_stride, x_stride );
}
private long processTransformationVars(ArrayList varList, ArrayList varNameList , NetcdfDataset ncd, ucar.nc2.dt.GridDataset gds, GridDatatype grid, Range timeRange, Range zRangeUse, Range yRange, Range xRange, int z_stride, int y_stride, int x_stride) throws InvalidRangeException {
long varsSize =0L;
List cctt = grid.getCoordinateSystem().getCoordinateTransforms();
for(CoordinateTransform ct : cctt){
Parameter param = ct.findParameterIgnoreCase( CF.FORMULA_TERMS );
if(param != null){
String[] varStrings = param.getStringValue().split(" ");
for(int i = 1; i 1 && y_stride > 1) || (yRange !=null || xRange !=null )) {
GridDatatype complementaryGrid = gds.findGridDatatype(paramVar.getFullName());
complementaryGrid = complementaryGrid.makeSubset(null, null, timeRange, zRangeUse, yRange, xRange);
paramVar = complementaryGrid.getVariable();
}
}else{
//Also have to subset the var if it is not a grid but has vertical dimension (the dimensionless vars in the formula) and zRangeUse != null
if( zRangeUse != null && paramVar.getRank() == 1 ){
List ranges = new ArrayList();
ranges.add(zRangeUse);
paramVar = paramVar.section(ranges);
}
}
varNameList.add(paramVar.getFullName());
varsSize += paramVar.getSize() * paramVar.getElementSize();
varList.add(paramVar);
}
}
}
}
return varsSize;
}
private boolean isLargeFile(long total_size) {
boolean isLargeFile = false;
long maxSize = 2 * 1000 * 1000 * 1000;
if (total_size > maxSize) {
log.info("Request size = {} Mbytes", total_size / 1000 / 1000);
isLargeFile = true;
}
return isLargeFile;
}
private void writeGlobalAttributes(NetcdfFileWriter writer, ucar.nc2.dt.GridDataset gds, LatLonRect llbb) {
// global attributes
for (Attribute att : gds.getGlobalAttributes()) {
if (att.getShortName().equals(CDM.FILE_FORMAT)) continue;
if (att.getShortName().equals(_Coordinate._CoordSysBuilder)) continue;
writer.addGroupAttribute(null, att);
}
writer.addGroupAttribute(null, new Attribute(CDM.CONVENTIONS, "CF-1.0"));
writer.addGroupAttribute(null, new Attribute("History",
"Translated to CF-1.0 Conventions by Netcdf-Java CDM (NetcdfCFWriter)\n" +
"Original Dataset = " + gds.getLocationURI() + "; Translation Date = " + new Date()));
// this will replace any existing
writer.addGroupAttribute(null, new Attribute(CDM.LAT_MIN, llbb.getLatMin()));
writer.addGroupAttribute(null, new Attribute(CDM.LAT_MAX, llbb.getLatMax()));
writer.addGroupAttribute(null, new Attribute(CDM.LON_MIN, llbb.getLonMin()));
writer.addGroupAttribute(null, new Attribute(CDM.LON_MAX, llbb.getLonMax()));
}
private void addCFAnnotations(NetcdfFileWriter writer, ucar.nc2.dt.GridDataset gds, List gridList, NetcdfDataset ncd,
List axisList, boolean addLatLon) {
//Group root = ncfile.getRootGroup();
for (String gridName : gridList) {
GridDatatype grid = gds.findGridDatatype(gridName);
Variable newV = writer.findVariable(gridName);
if (newV == null) {
log.warn("NetcdfCFWriter cant find " + gridName + " in gds " + gds.getLocationURI());
continue;
}
// annotate Variable for CF
StringBuilder sbuff = new StringBuilder();
GridCoordSystem gcs = grid.getCoordinateSystem();
for (Variable axis : gcs.getCoordinateAxes()) {
sbuff.append(axis.getFullName()).append(" ");
}
if (addLatLon)
sbuff.append("lat lon");
newV.addAttribute(new Attribute(CF.COORDINATES, sbuff.toString()));
// looking for coordinate transform variables
for (CoordinateTransform ct : gcs.getCoordinateTransforms()) {
Variable v = ncd.findVariable(ct.getName());
if (ct.getTransformType() == TransformType.Projection)
newV.addAttribute(new Attribute(CF.GRID_MAPPING, v.getFullName()));
}
}
for (CoordinateAxis axis : axisList) {
Variable newV = writer.findVariable(axis.getFullNameEscaped());
if ((axis.getAxisType() == AxisType.Height) || (axis.getAxisType() == AxisType.Pressure) || (axis.getAxisType() == AxisType.GeoZ)) {
if (null != axis.getPositive())
newV.addAttribute(new Attribute(CF.POSITIVE, axis.getPositive()));
}
if (axis.getAxisType() == AxisType.Lat) {
newV.addAttribute(new Attribute(CDM.UNITS, "degrees_north"));
newV.addAttribute(new Attribute("standard_name", "latitude"));
}
if (axis.getAxisType() == AxisType.Lon) {
newV.addAttribute(new Attribute(CDM.UNITS, "degrees_east"));
newV.addAttribute(new Attribute("standard_name", "longitude"));
}
if (axis.getAxisType() == AxisType.GeoX) {
newV.addAttribute(new Attribute("standard_name", "projection_x_coordinate"));
}
if (axis.getAxisType() == AxisType.GeoY) {
newV.addAttribute(new Attribute("standard_name", "projection_y_coordinate"));
}
}
// coordinate transform variables : must convert false easting, northing to km
List ctvList = new ArrayList();
for (ucar.nc2.dt.GridDataset.Gridset gridSet : gds.getGridsets()) {
ucar.nc2.dt.GridCoordSystem gcs = gridSet.getGeoCoordSystem();
ProjectionCT pct = gcs.getProjectionCT();
if (pct != null) {
Variable v = writer.findVariable(pct.getName()); // look for the ctv
if ((v != null) && !ctvList.contains(v)) {
convertProjectionCTV((NetcdfDataset) gds.getNetcdfFile(), v);
ctvList.add(v);
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////
public static void test1() throws IOException, InvalidRangeException, ParseException {
String fileIn = "C:/data/ncmodels/NAM_CONUS_80km_20051206_0000.nc";
String fileOut = "C:/temp/cf3.nc";
ucar.nc2.dt.GridDataset gds = ucar.nc2.dt.grid.GridDataset.open(fileIn);
NetcdfCFWriter writer = new NetcdfCFWriter();
List gridList = new ArrayList();
gridList.add("RH");
gridList.add("T");
DateFormatter format = new DateFormatter();
Date start = format.getISODate("2005-12-06T18:00:00Z");
Date end = format.getISODate("2005-12-07T18:00:00Z");
writer.makeFile(fileOut, gds, gridList,
new LatLonRect(new LatLonPointImpl(37, -109), 400, 7),
CalendarDateRange.of(start, end),
true,
1, 1, 1);
}
public static void main(String args[]) throws IOException, InvalidRangeException, ParseException {
String fileIn = "dods://motherlode.ucar.edu/repository/entry/show/output:data.opendap/entryid:c41a3a26-57e5-4b15-b8b1-a8762b6f02c7/dodsC/entry";
String fileOut = "C:/temp/testCF.nc";
ucar.nc2.dt.GridDataset gds = ucar.nc2.dt.grid.GridDataset.open(fileIn);
NetcdfCFWriter writer = new NetcdfCFWriter();
List gridList = new ArrayList();
gridList.add("Z_sfc");
DateFormatter format = new DateFormatter();
Date start = format.getISODate("2003-06-01T03:00:00Z");
Date end = format.getISODate("2004-01-01T00:00:00Z");
writer.makeFile(fileOut, gds, gridList, null,
// new LatLonRect(new LatLonPointImpl(30, -109), 10, 50),
CalendarDateRange.of(start, end),
true,
1, 1, 1);
}
}