ucar.nc2.iosp.grid.GridTimeCoord 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.
/*
* 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.iosp.grid;
import ucar.grib.GribPds;
import ucar.ma2.*;
import ucar.nc2.*;
import ucar.nc2.units.DateFormatter;
import ucar.nc2.units.DateUnit;
import ucar.grid.GridRecord;
import ucar.grib.GribGridRecord;
import java.util.*;
/**
* A Time Coordinate for a Grid dataset.
*
* @author caron
*/
public class GridTimeCoord implements Comparable {
static private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GridTimeCoord.class);
//private GridTableLookup lookup;
private int seq = 0; // for getting a unique name
private String timeUdunit, timeUnit;
private Date baseDate;
private List times;
private List timeIntvs;
private int constantInterval = -1;
private int[] coordData;
/**
* Create a new GridTimeCoord from the list of GridRecord
*
* @param records records to use
*/
GridTimeCoord(List records) {
// check time units, get earliest reference date
for (GridRecord record : records) {
if (this.baseDate == null) {
this.baseDate = record.getReferenceTime();
this.timeUdunit = record.getTimeUdunitName();
this.timeUnit = record.getTimeUnitName();
//System.out.printf("%s%n", record.getParameterDescription());
}
// make sure that the time units agree
if (!this.timeUnit.equals(record.getTimeUnitName()))
log.warn(record + " does not have same time unit= " + this.timeUnit + " != " + record.getTimeUnitName());
// use earlier reference date
Date ref = record.getReferenceTime();
if (ref.before(this.baseDate))
this.baseDate = ref;
}
// interval case - only GRIB
if (records.get(0) instanceof GribGridRecord) {
GribGridRecord ggr = (GribGridRecord) records.get(0);
if (ggr.isInterval()) {
timeIntvs = new ArrayList();
boolean same = true;
int intv = -1;
for (GridRecord gr : records) {
ggr = (GribGridRecord) gr;
// make sure that the reference date agrees
Date ref = gr.getReferenceTime();
if (!baseDate.equals(ref))
log.warn(gr + " does not have same base date= " + baseDate + " != " + ref);
GribPds pds = ggr.getPds();
int[] timeInv = pds.getForecastTimeInterval();
int start = timeInv[0];
int end = timeInv[1];
int intv2 = end - start;
if (intv2 > 0) { // skip those weird zero-intervals when testing for constant interval
if (intv < 0) intv = intv2;
else same = same && (intv == intv2);
}
Date validTime = gr.getValidTime();
TimeCoordWithInterval timeCoordIntv = new TimeCoordWithInterval(validTime, start, intv2);
if (!timeIntvs.contains(timeCoordIntv))
timeIntvs.add(timeCoordIntv);
}
if (same) constantInterval = intv;
Collections.sort(timeIntvs);
return;
}
}
// non - interval case
// get list of unique valid times
times = new ArrayList();
for (GridRecord gr : records) {
Date validTime = gr.getValidTime();
if (validTime == null) validTime = gr.getReferenceTime();
if (!times.contains(validTime)) {
times.add(validTime);
}
}
Collections.sort(times);
}
/**
* match time values - can this list of GridRecords use this coordinate?
*
* @param records list of records
* @return true if they are the same as this
*/
boolean matchTimes(List records) {
// make sure that the time units agree
for (GridRecord record : records) {
if (!this.timeUdunit.equals(record.getTimeUdunitName()))
return false;
}
// check intervals match
if (records.get(0) instanceof GribGridRecord) {
GribGridRecord ggr = (GribGridRecord) records.get(0);
if (ggr.isInterval() != isInterval())
return false;
}
if (isInterval()) {
// first create a new list
List timeList = new ArrayList(records.size());
for (GridRecord record : records) {
// make sure that the base times agree
Date ref = record.getReferenceTime();
if (!baseDate.equals(ref))
return false;
GribGridRecord ggr = (GribGridRecord) record;
GribPds pds = ggr.getPds();
int[] timeInv = pds.getForecastTimeInterval();
int start = timeInv[0];
int end = timeInv[1];
int intv2 = end - start;
Date validTime = record.getValidTime();
TimeCoordWithInterval timeCoordIntv = new TimeCoordWithInterval(validTime, start, intv2);
if (!timeList.contains(timeCoordIntv)) {
timeList.add(timeCoordIntv);
}
}
Collections.sort(timeList);
return timeList.equals(timeIntvs);
} else {
// first create a new list
List timeList = new ArrayList(records.size());
for (GridRecord record : records) {
Date validTime = record.getValidTime();
if (validTime == null)
validTime = record.getReferenceTime();
if (!timeList.contains(validTime)) {
timeList.add(validTime);
}
}
Collections.sort(timeList);
return timeList.equals(times);
}
}
/**
* Set the sequence number
*
* @param seq the sequence number
*/
void setSequence(int seq) {
this.seq = seq;
}
/**
* Get the name
*
* @return the name
*/
String getName() {
return (seq == 0) ? "time" : "time" + seq;
}
/**
* Add this as a dimension to a netCDF file
*
* @param ncfile the netCDF file
* @param g the group in the file
*/
void addDimensionsToNetcdfFile(NetcdfFile ncfile, Group g) {
//Collections.sort(times);
ncfile.addDimension(g, new Dimension(getName(), getNTimes(), true));
}
/**
* Add this as a variable to the netCDF file
*
* @param ncfile the netCDF file
* @param g the group in the file
*/
void addToNetcdfFile(NetcdfFile ncfile, Group g) {
Variable v = new Variable(ncfile, g, null, getName());
v.setDataType(DataType.INT);
//Date baseTime = lookup.getFirstBaseTime();
//String timeUnit = lookup.getFirstTimeRangeUnitName();
// String timeUnit = lookup.getTimeRangeUnitName(this.timeUnit);
DateFormatter formatter = new DateFormatter();
String refDate = formatter.toDateTimeStringISO(baseDate);
String udunit = timeUdunit + " since " + refDate;
DateUnit dateUnit = null;
try {
dateUnit = new DateUnit(udunit);
} catch (Exception e) {
log.error("TimeCoord not added, cant make DateUnit from String '" + udunit + "'", e);
return;
}
// create the data
Array coordArray = null;
Array boundsArray = null;
int ntimes = getNTimes();
coordData = new int[ntimes];
if (!isInterval()) {
for (int i = 0; i < times.size(); i++)
coordData[i] = (int) dateUnit.makeValue(times.get(i)); // LOOK why int ?
coordArray = Array.factory(DataType.INT, new int[]{ntimes}, coordData);
} else {
int[] boundsData = new int[ntimes * 2];
for (int i = 0; i < timeIntvs.size(); i++) {
TimeCoordWithInterval tintv = timeIntvs.get(i);
coordData[i] = tintv.start + tintv.interval; // end
boundsData[2 * i + 1] = tintv.start + tintv.interval; // end
boundsData[2 * i] = tintv.start; // start
}
coordArray = Array.factory(DataType.INT, new int[]{ntimes}, coordData);
boundsArray = Array.factory(DataType.INT, new int[]{ntimes, 2}, boundsData);
}
v.setDimensions(v.getShortName());
v.setCachedData(coordArray, false);
if (!isInterval()) {
v.addAttribute(new Attribute("long_name", "forecast time"));
v.addAttribute(new Attribute("units", timeUdunit + " since " + refDate));
} else {
Formatter intervalName = new Formatter();
if (constantInterval < 0)
intervalName.format("(mixed intervals)");
else
intervalName.format("(%d %s intervals)", constantInterval, this.timeUdunit);
v.addAttribute(new Attribute("long_name", "forecast time for " + intervalName.toString()));
v.addAttribute(new Attribute("units", timeUdunit + " since " + refDate));
v.addAttribute(new Attribute("bounds", getName() + "_bounds"));
// add times bound variable
if (g == null) g = ncfile.getRootGroup();
Dimension bd = ucar.nc2.dataset.DatasetConstructor.getBoundsDimension(ncfile);
Variable vb = new Variable(ncfile, g, null, getName() + "_bounds");
vb.setDataType(DataType.INT);
vb.setDimensions(getName() + " "+ bd.getName());
vb.addAttribute(new Attribute("long_name", "bounds for " + getName()));
vb.addAttribute(new Attribute("units", timeUdunit + " since " + refDate));
// add data
vb.setCachedData(boundsArray, false);
ncfile.addVariable(g, vb);
}
/* Date d = lookup.getFirstBaseTime();
if (lookup instanceof Grib2GridTableLookup) {
Grib2GridTableLookup g2lookup = (Grib2GridTableLookup) lookup;
v.addAttribute(new Attribute("GRIB_orgReferenceTime", formatter.toDateTimeStringISO(d)));
v.addAttribute(new Attribute("GRIB2_significanceOfRTName", g2lookup.getFirstSignificanceOfRTName()));
} else if (lookup instanceof Grib1GridTableLookup) {
Grib1GridTableLookup g1lookup = (Grib1GridTableLookup) lookup;
v.addAttribute(new Attribute("GRIB_orgReferenceTime", formatter.toDateTimeStringISO(d)));
v.addAttribute(new Attribute("GRIB2_significanceOfRTName", g1lookup.getFirstSignificanceOfRTName()));
}
v.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Time.toString())); */
ncfile.addVariable(g, v);
}
/**
* Find the index of a GridRecord in the list of times
*
* @param record the GridRecord
* @return the index in the list of time values, or -1 if not found
*/
int findIndex(GridRecord record) {
Date validTime = record.getValidTime();
if (!isInterval())
return times.indexOf(validTime);
else {
int index = 0;
for (TimeCoordWithInterval t : timeIntvs) {
if (t.coord.equals(validTime) && t.interval == record.getTimeInterval()) return index;
index++;
}
return -1;
}
}
/**
* Get the number of times
*
* @return the number of times
*/
int getNTimes() {
return isInterval() ? timeIntvs.size() : times.size();
}
/**
* Get IntervalLength
*
* @return IntervalLength
*/
int getConstantInterval() {
return constantInterval;
}
/**
* Get TimeUnit
*
* @return TimeUnit
*/
String getTimeUnit() {
return timeUdunit;
}
/**
* is this a mixed interval
*
* @return mixed
*/
boolean isInterval() {
return timeIntvs != null;
}
public String getCoord(int i) {
if (timeIntvs == null)
return coordData[i]+" ";
else {
TimeCoordWithInterval ti = timeIntvs.get(i);
return coordData[i]+"=" + ti.start+"/"+ti.interval;
}
}
@Override
public int compareTo(GridTimeCoord o) {
return o.getNTimes() - getNTimes(); // reverse sort on number of coords
}
private class TimeCoordWithInterval implements Comparable {
Date coord;
int start, interval;
private TimeCoordWithInterval(Date coord, int start, int interval) {
this.coord = coord;
this.start = start;
this.interval = interval;
}
@Override
public int compareTo(TimeCoordWithInterval o) {
int diff = coord.compareTo(o.coord);
return (diff == 0) ? (o.interval - interval) : diff; // longer intervals first
}
@Override
public int hashCode() {
return 17 * coord.hashCode() + interval;
}
@Override
public boolean equals(Object obj) {
TimeCoordWithInterval o = (TimeCoordWithInterval) obj;
return coord.equals(o.coord) && (interval == o.interval);
}
}
}