ucar.nc2.ft.fmrc.TimeCoord Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 1998-2018 John Caron and University Corporation for Atmospheric Research/Unidata
* See LICENSE for license information.
*/
package ucar.nc2.ft.fmrc;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Formatter;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import ucar.nc2.Attribute;
import ucar.nc2.constants.CF;
import ucar.nc2.dataset.CoordinateAxis1DTime;
import ucar.nc2.time.Calendar;
import ucar.nc2.time.CalendarDate;
import ucar.nc2.time.CalendarDateUnit;
import ucar.nc2.units.DateUnit;
import ucar.nc2.util.Misc;
/**
* Represents a list of offset times shared among variables
* Tracks a list of variables that all have the same list of offset times.
*/
public class TimeCoord implements Comparable {
static public final TimeCoord EMPTY = new TimeCoord(CalendarDate.of(new Date()), new double[0]);
private CalendarDate runDate;
private List gridInv; // track the grids that use this coord
private int id; // unique id for serialization
private String axisName; // time coordinate axis
// time at point has offsets, intervals have bounds
private boolean isInterval = false;
private double[] offset; // hours since runDate
private double[] bound1, bound2; // hours since runDate [ntimes,2]
TimeCoord(CalendarDate runDate) {
this.runDate = runDate;
}
TimeCoord(CalendarDate runDate, double[] offset) {
this.runDate = runDate;
this.offset = offset;
}
TimeCoord(TimeCoord from) {
this.runDate = from.runDate;
this.axisName = from.axisName;
this.offset = from.offset;
this.isInterval = from.isInterval;
this.bound1 = from.bound1;
this.bound2 = from.bound2;
this.id = from.id;
}
TimeCoord(CalendarDate runDate, CoordinateAxis1DTime axis) {
this.runDate = runDate;
this.axisName = axis.getFullName();
DateUnit unit = null;
Attribute atrCal = null;
Calendar cal = null;
try {
unit = new DateUnit(axis.getUnitsString());
atrCal = axis.findAttribute(CF.CALENDAR );
if(atrCal != null)
cal = Calendar.get((String)atrCal.getValue(0) );
else
cal = Calendar.getDefault();
} catch (Exception e) {
throw new IllegalArgumentException("Not a unit of time " + axis.getUnitsString());
}
int n = (int) axis.getSize();
if (axis.isInterval()) {
this.isInterval = true;
this.bound1 = new double[n];
this.bound2 = new double[n];
double[] orgBound1 = axis.getBound1();
double[] orgBound2 = axis.getBound2();
this.bound2 = new double[n];
for (int i = 0; i < axis.getSize(); i++) {
this.bound1[i] = getValueInHours(unit, orgBound1[i]);
this.bound2[i] = getValueInHours(unit, orgBound2[i]);
}
} else {
offset = new double[n];
for (int i = 0; i < axis.getSize(); i++) {
offset[i] = getValueInHours(cal, unit, axis.getCoordValue(i));
}
}
}
double getValueInHours(Calendar cal, DateUnit unit, double value) {
//CalendarDate d = unit.makeCalendarDate(value);
//double secs = unit.getTimeUnit().getValueInSeconds(value);
//CalendarDate d = CalendarDate.of(cal, unit.getDateOrigin().getTime() + (long)(1000*secs));
CalendarDateUnit dateUnit = CalendarDateUnit.withCalendar(cal, unit.getUnitsString() ); // this will throw exception on failure
CalendarDate d = dateUnit.makeCalendarDate(value);
return FmrcInv.getOffsetInHours(runDate, d);
}
double getValueInHours(DateUnit unit, double value) {
CalendarDate d = unit.makeCalendarDate(value);
return FmrcInv.getOffsetInHours(runDate, d);
}
void addGridInventory(GridDatasetInv.Grid grid) {
if (gridInv == null)
gridInv = new ArrayList<>();
gridInv.add(grid);
}
public CalendarDate getRunDate() {
return runDate;
}
public boolean isInterval() {
return isInterval;
}
/**
* The list of GridDatasetInv.Grid that use this TimeCoord
*
* @return list of GridDatasetInv.Grid that use this TimeCoord
*/
public List getGridInventory() {
return (gridInv == null) ? new ArrayList() : gridInv;
}
/**
* A unique id for this TimeCoord
*
* @return unique id for this TimeCoord
*/
public int getId() {
return id;
}
/**
* Set the unique id for this TimeCoord
*
* @param id id for this TimeCoord
*/
public void setId(int id) {
this.id = id;
}
public String getName() {
if (this == EMPTY) return "EMPTY";
return id == 0 ? "time" : "time" + id;
}
public String getAxisName() {
return axisName;
}
public int getNCoords() {
return (isInterval) ? bound1.length : offset.length;
}
/**
* The list of valid times, in units of hours since the run time
* @return list of valid times, in units of hours since the run time
*/
public double[] getOffsetTimes() {
return isInterval ? bound2 : offset;
}
public double[] getBound1() {
return bound1;
}
public double[] getBound2() {
return bound2;
}
public void setOffsetTimes(double[] offset) {
this.offset = offset;
}
public void setBounds(double[] bound1, double[] bound2) {
this.bound1 = bound1;
this.bound2 = bound2;
this.isInterval = true;
}
public void setBounds(List tinvs) {
this.bound1 = new double[tinvs.size()];
this.bound2 = new double[tinvs.size()];
int count = 0;
for (TimeCoord.Tinv tinv : tinvs) {
this.bound1[count] = tinv.b1;
this.bound2[count] = tinv.b2;
count++;
}
this.isInterval = true;
}
@Override
public String toString() {
Formatter out = new Formatter();
out.format("%-10s %-26s offsets=", getName(), runDate);
if (isInterval)
for (int i=0; i timeCoords, TimeCoord want) {
if (want == null) return null;
for (TimeCoord tc : timeCoords) {
if (want.equalsData(tc))
return tc;
}
// make a new one
TimeCoord result = new TimeCoord(want);
timeCoords.add(result);
return result;
}
/**
* Create the union of all the values in the list of TimeCoord, ignoring the TimeCoord's runDate
* @param timeCoords list of TimeCoord
* @param baseDate resulting union timeCoord uses this as a base date
* @return union TimeCoord
*/
static public TimeCoord makeUnion(List timeCoords, CalendarDate baseDate) {
if (timeCoords.size() == 0) return new TimeCoord(baseDate);
if (timeCoords.size() == 1) return timeCoords.get(0);
if (timeCoords.get(0).isInterval)
return makeUnionIntv(timeCoords, baseDate);
else
return makeUnionReg(timeCoords, baseDate);
}
static private TimeCoord makeUnionReg(List timeCoords, CalendarDate baseDate) {
// put into a set for uniqueness
Set offsets = new HashSet<>();
for (TimeCoord tc : timeCoords) {
if (tc.isInterval)
throw new IllegalArgumentException("Cant mix interval coordinates");
for (double off : tc.getOffsetTimes())
offsets.add(off);
}
// extract into a List
List offsetList = Arrays.asList((Double[]) offsets.toArray(new Double[offsets.size()]));
// sort and extract into double[]
Collections.sort(offsetList);
double[] offset = new double[offsetList.size()];
int count = 0;
for (double off : offsetList)
offset[count++] = off;
// make the resulting time coord
TimeCoord result = new TimeCoord(baseDate);
result.setOffsetTimes(offset);
return result;
}
static private TimeCoord makeUnionIntv(List timeCoords, CalendarDate baseDate) {
// put into a set for uniqueness
Set offsets = new HashSet<>();
for (TimeCoord tc : timeCoords) {
if (!tc.isInterval)
throw new IllegalArgumentException("Cant mix non-interval coordinates");
for (int i=0; i bounds = Arrays.asList((Tinv[]) offsets.toArray(new Tinv[offsets.size()]));
// sort and extract into double[] bounds arrays
Collections.sort(bounds);
int n = bounds.size();
double[] bounds1 = new double[n];
double[] bounds2 = new double[n];
for (int i=0; i {
private double b1, b2; // bounds
public Tinv(double offset) {
this.b2 = offset;
}
public Tinv(double b1, double b2) {
this.b1 = b1;
this.b2 = b2;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Tinv tinv = (Tinv) o;
if (!Misc.nearlyEquals(b2, tinv.b2)) return false;
if (!Misc.nearlyEquals(b1, tinv.b1)) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) Math.round(b1 / Misc.defaultMaxRelativeDiffDouble);
result = 31 * result + (int) Math.round(b2/Misc.defaultMaxRelativeDiffDouble);
return result;
}
@Override
public int compareTo(Tinv o) {
boolean b1close = Misc.nearlyEquals(b1, o.b1);
boolean b2close = Misc.nearlyEquals(b2, o.b2);
if (b1close && b2close) return 0;
if (b2close) return Double.compare(b1, o.b1);
return Double.compare(b2, o.b2);
}
}
/*
* Create the union of all the values in the list of TimeCoord, converting all to a common baseDate
* @param timeCoords list of TimeCoord
* @param baseDate resulting union timeCoord uses this as a base date
* @return union TimeCoord
*
static public TimeResult makeUnionConvert(List timeCoords, Date baseDate) {
Map offsetMap = new HashMap(256);
for (TimeCoord tc : timeCoords) {
double run_offset = FmrcInv.getOffsetInHours(baseDate, tc.getRunDate());
for (double offset : tc.getOffsetHours()) {
offsetMap.put(run_offset + offset, run_offset); // later ones override
}
}
Set keys = offsetMap.keySet();
int n = keys.size();
List offsetList = Arrays.asList((Double[]) keys.toArray(new Double[n]));
Collections.sort(offsetList);
int counto = 0;
double[] offs = new double[n];
double[] runoffs = new double[n];
for (Double key : offsetList) {
offs[counto] = key;
runoffs[counto] = offsetMap.get(key);
counto++;
}
return new TimeResult( baseDate, offs, runoffs);
}
static class TimeResult {
double[] offsets;
double[] runOffsets;
Date base;
TimeResult(Date base, double[] offsets, double[] runOffsets) {
this.base = base;
this.offsets = offsets;
this.runOffsets = runOffsets;
}
} */
}