package ucar.coord; import net.jcip.annotations.Immutable; import ucar.nc2.grib.grib1.Grib1Record; import ucar.nc2.grib.grib2.Grib2Record; import ucar.nc2.time.CalendarDate; import ucar.nc2.time.CalendarPeriod; import ucar.nc2.util.Indent; import java.util.*; /** * Grib runtime coordinate * Effectively Immutable * @author caron * @since 11/24/13 */ @Immutable public class CoordinateRuntime implements Coordinate { private final long[] runtimes; final CalendarDate firstDate; final CalendarPeriod timeUnit; final String periodName; private String name = "reftime"; // yeah yeah, not final, bugger off public CoordinateRuntime(List<Long> runtimeSorted, CalendarPeriod timeUnit) { this.runtimes = new long[runtimeSorted.size()]; int idx = 0; for (long val : runtimeSorted) this.runtimes[idx++] = val; this.firstDate = CalendarDate.of(runtimeSorted.get(0)); this.timeUnit = timeUnit == null ? CalendarPeriod.Hour : timeUnit; CalendarPeriod.Field cf = this.timeUnit.getField(); if (cf == CalendarPeriod.Field.Month || cf == CalendarPeriod.Field.Year) this.periodName = "calendar "+ cf.toString(); else this.periodName = cf.toString(); } public CalendarPeriod getTimeUnits() { return timeUnit; } /* public long[] getRuntimesSorted() { return runtimes; } */ public CalendarDate getRuntimeDate(int idx) { return CalendarDate.of(runtimes[idx]); } public long getRuntime(int idx) { return runtimes[idx]; } /** * Get offsets from firstDate, in units of timeUnit * @return for each runtime, a list of values from firstdate */ public List<Double> getOffsetsInTimeUnits() { double start = firstDate.getMillis(); List<Double> result = new ArrayList<>(runtimes.length); for (int idx=0; idx<runtimes.length; idx++) { double runtime = (double) getRuntime(idx); double msecs = (runtime - start); result.add(msecs / timeUnit.getValueInMillisecs()); } return result; } @Override public int getSize() { return runtimes.length; } @Override public Type getType() { return Type.runtime; } @Override public int estMemorySize() { return 616 + getSize() * (48); } @Override public String getUnit() { return periodName+" since "+firstDate.toString(); } @Override public String getName() { return name; } public void setName(String name) { // LOOK need to get this in the constructor to make the name final if (!this.name.equals("reftime")) throw new IllegalStateException("Cant modify"); this.name = name; } @Override public int getCode() { return 0; } public CalendarDate getFirstDate() { return firstDate; } public CalendarDate getLastDate() { return getRuntimeDate(getSize() - 1); } @Override public List<? extends Object> getValues() { List<Long> result = new ArrayList<>(runtimes.length); for (long val : runtimes) result.add(val); return result; } @Override public int getIndex(Object val) { return Arrays.binarySearch(runtimes, (Long) val); } @Override public Object getValue(int idx) { return runtimes[idx]; } @Override public void showInfo(Formatter info, Indent indent) { info.format("%s%s:", indent, getType()); for (int idx=0; idx<getSize(); idx++) info.format(" %s,", getRuntimeDate(idx)); info.format(" (%d) %n", runtimes.length); } @Override public void showCoords(Formatter info) { info.format("Run Times: %s (%s)%n", getName(), getUnit()); List<Double> udunits = getOffsetsInTimeUnits(); int count = 0; for (int idx=0; idx<getSize(); idx++) info.format(" %s (%f)%n", getRuntimeDate(idx), udunits.get(count++)); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CoordinateRuntime that = (CoordinateRuntime) o; if (!periodName.equals(that.periodName)) return false; if (!Arrays.equals(runtimes, that.runtimes)) return false; return true; } @Override public int hashCode() { int result = Arrays.hashCode(runtimes); result = 31 * result + periodName.hashCode(); return result; } /////////////////////////////////////////////////////// public static class Builder2 extends CoordinateBuilderImpl<Grib2Record> { CalendarPeriod timeUnit; public Builder2(CalendarPeriod timeUnit) { this.timeUnit = timeUnit; } @Override public Object extract(Grib2Record gr) { return gr.getReferenceDate().getMillis(); } @Override public Coordinate makeCoordinate(List<Object> values) { List<Long> runtimeSorted = new ArrayList<>(values.size()); for (Object val : values) runtimeSorted.add((Long) val); Collections.sort(runtimeSorted); return new CoordinateRuntime(runtimeSorted, timeUnit); } } public static class Builder1 extends CoordinateBuilderImpl<Grib1Record> { CalendarPeriod timeUnit; public Builder1(CalendarPeriod timeUnit) { this.timeUnit = timeUnit; } @Override public Object extract(Grib1Record gr) { return gr.getReferenceDate().getMillis(); } @Override public Coordinate makeCoordinate(List<Object> values) { List<Long> runtimeSorted = new ArrayList<>(values.size()); for (Object val : values) runtimeSorted.add((Long) val); Collections.sort(runtimeSorted); return new CoordinateRuntime(runtimeSorted, timeUnit); } } }