All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
ucar.nc2.ft2.coverage.CoverageCoordAxis1D Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 John Caron and University Corporation for Atmospheric Research/Unidata
* See LICENSE for license information.
*/
package ucar.nc2.ft2.coverage;
import ucar.ma2.*;
import ucar.nc2.constants.AxisType;
import ucar.nc2.time.CalendarDate;
import ucar.nc2.time.CalendarDateRange;
import ucar.nc2.util.Indent;
import ucar.nc2.util.NamedAnything;
import ucar.nc2.util.NamedObject;
import ucar.nc2.util.Optional;
import ucar.unidata.util.Format;
import javax.annotation.concurrent.Immutable;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.Iterator;
import java.util.List;
/**
* Coverage CoordAxis 1D case
*
* @author caron
* @since 7/15/2015
*/
@Immutable
public class CoverageCoordAxis1D extends CoverageCoordAxis { // implements Iterable {
// does this really describe all subset possibilities? what about RangeScatter, composite ??
protected final Range range; // for subset, tracks the indexes in the original
protected final RangeComposite crange;
public CoverageCoordAxis1D(CoverageCoordAxisBuilder builder) {
super(builder);
if (axisType == null && builder.dependenceType == DependenceType.independent)
throw new IllegalArgumentException("independent axis must have type");
// make sure range has axisType as the name
String rangeName = (axisType != null) ? axisType.toString() : null;
if (builder.range != null) {
this.range = (rangeName != null) ? builder.range.setName(rangeName) : builder.range;
} else {
this.range = Range.make(rangeName, getNcoords());
}
this.crange = builder.crange;
}
@Override
public RangeIterator getRangeIterator() {
return crange != null ? crange : range;
}
@Override
public Range getRange() {
return range;
}
@Override
public void toString(Formatter f, Indent indent) {
super.toString(f, indent);
f.format("%s range=%s isSubset=%s", indent, range, isSubset());
f.format("%n");
}
@Override
public String getSummary() {
if (axisType != AxisType.RunTime)
return super.getSummary();
if (ncoords < 7) {
Formatter f = new Formatter();
for (int i = 0; i < ncoords; i++) {
CalendarDate cd = makeDate(getCoordMidpoint(i));
if (i > 0) f.format(", ");
f.format("%s", cd);
}
return f.toString();
}
Formatter f = new Formatter();
CalendarDate start = makeDate(getStartValue());
f.format("start=%s", start);
CalendarDate end = makeDate(getEndValue());
f.format(", end=%s", end);
f.format(" (npts=%d spacing=%s)", getNcoords(), getSpacing());
return f.toString();
}
///////////////////////////////////////////////////////////////////
// Spacing
public boolean isAscending() {
loadValuesIfNeeded();
switch (spacing) {
case regularInterval:
case regularPoint:
return getResolution() > 0;
case irregularPoint:
return values[0] <= values[ncoords - 1];
case contiguousInterval:
return values[0] <= values[ncoords];
case discontiguousInterval:
return values[0] <= values[2 * ncoords - 1];
}
throw new IllegalStateException("unknown spacing" + spacing);
}
public double getCoordMidpoint(int index) {
if (index < 0 || index >= getNcoords())
throw new IllegalArgumentException("Index out of range=" + index);
loadValuesIfNeeded();
switch (spacing) {
case regularPoint:
return startValue + index * getResolution();
case irregularPoint:
return values[index];
case regularInterval:
return startValue + (index + .5) * getResolution();
case contiguousInterval:
case discontiguousInterval:
return (getCoordEdge1(index) + getCoordEdge2(index)) / 2;
}
throw new IllegalStateException("Unknown spacing=" + spacing);
}
public double getCoordEdge1(int index) {
if (index < 0 || index >= getNcoords())
throw new IllegalArgumentException("Index out of range=" + index);
loadValuesIfNeeded();
switch (spacing) {
case regularPoint:
return startValue + (index - .5) * getResolution();
case regularInterval:
return startValue + index * getResolution();
case irregularPoint:
if (index > 0)
return (values[index - 1] + values[index]) / 2;
else
return values[0] - (values[1] - values[0]) / 2;
case contiguousInterval:
return values[index];
case discontiguousInterval:
return values[2 * index];
}
throw new IllegalStateException("Unknown spacing=" + spacing);
}
public double getCoordEdge2(int index) {
if (index < 0 || index >= getNcoords())
throw new IllegalArgumentException("Index out of range=" + index);
loadValuesIfNeeded();
switch (spacing) {
case regularPoint:
if (index < 0 || index >= ncoords) throw new IllegalArgumentException("Index out of range " + index);
return startValue + (index + .5) * getResolution();
case regularInterval:
return startValue + (index+1) * getResolution();
case irregularPoint:
if (index < ncoords - 1)
return (values[index] + values[index + 1]) / 2;
else
return values[index] + (values[index] - values[index - 1]) / 2;
case contiguousInterval:
return values[index + 1];
case discontiguousInterval:
return values[2 * index + 1];
}
throw new IllegalStateException("Unknown spacing=" + spacing);
}
public double getCoordEdgeFirst() {
return getCoordEdge1(0);
}
public double getCoordEdgeLast() {
return getCoordEdge2(ncoords - 1);
}
@Override
public Array getCoordsAsArray() {
Array result;
switch (dependenceType) {
case scalar:
result = Array.factory(getDataType(), new int[0]);
break;
default:
result = Array.factory(getDataType(), new int[]{ncoords});
break;
}
for (int i = 0; i < ncoords; i++)
result.setDouble(i, getCoordMidpoint(i));
return result;
}
@Override
public Array getCoordBoundsAsArray() {
Array result = Array.factory(getDataType(), new int[]{ncoords, 2});
int count = 0;
for (int i = 0; i < ncoords; i++) {
result.setDouble(count++, getCoordEdge1(i));
result.setDouble(count++, getCoordEdge2(i));
}
return result;
}
@Override
public Optional subset(double minValue, double maxValue, int stride) throws InvalidRangeException {
CoordAxisHelper helper = new CoordAxisHelper(this);
Optional buildero = helper.subset(minValue, maxValue, stride);
return !buildero.isPresent() ? Optional.empty(buildero.getErrorMessage()) : Optional.of(new CoverageCoordAxis1D(buildero.get()));
}
// CalendarDate, double[2], or Double
public Object getCoordObject(int index) {
if (axisType == AxisType.RunTime)
return makeDate(getCoordMidpoint(index));
if (isInterval())
return new double[]{getCoordEdge1(index), getCoordEdge2(index)};
return getCoordMidpoint(index);
}
public List getCoordValueNames() {
loadValuesIfNeeded();
if (timeHelper != null)
return timeHelper.getCoordValueNames(this);
List result = new ArrayList<>();
for (int i = 0; i < ncoords; i++) {
Object value = null;
switch (spacing) {
case regularPoint:
case irregularPoint:
value = Format.d(getCoordMidpoint(i), 3);
break;
case regularInterval:
case contiguousInterval:
case discontiguousInterval:
value = new CoordInterval(getCoordEdge1(i), getCoordEdge2(i), 3);
break;
}
result.add(new NamedAnything(value, value + " " + getUnits()));
}
return result;
}
@Override
public CoverageCoordAxis copy() {
return new CoverageCoordAxis1D(new CoverageCoordAxisBuilder(this));
}
@Override
public Optional subset(SubsetParams params) {
Optional buildero = subsetBuilder(params);
return !buildero.isPresent() ? Optional.empty(buildero.getErrorMessage()) : Optional.of(new CoverageCoordAxis1D(buildero.get()));
}
// only for longitude, only for regular (do we need a subclass for longitude 1D coords ??
public Optional subsetByIntervals(List lonIntvs, int stride) {
if (axisType != AxisType.Lon)
return Optional.empty("subsetByIntervals only for longitude");
if (!isRegular())
return Optional.empty("subsetByIntervals only for regular longitude");
CoordAxisHelper helper = new CoordAxisHelper(this);
double start = Double.NaN;
boolean first = true;
List ranges = new ArrayList<>();
for (MAMath.MinMax lonIntv : lonIntvs) {
if (first) start = lonIntv.min;
first = false;
Optional opt = helper.makeRange(lonIntv.min, lonIntv.max, stride);
if (!opt.isPresent())
return Optional.empty(opt.getErrorMessage());
ranges.add(opt.get());
}
try {
RangeComposite compositeRange = new RangeComposite(AxisType.Lon.toString(), ranges);
int npts = compositeRange.length();
double end = start + npts * resolution;
CoverageCoordAxisBuilder builder = new CoverageCoordAxisBuilder(this); // copy
builder.subset(npts, start, end, resolution, null);
builder.setRange(null);
builder.setCompositeRange(compositeRange);
return Optional.of(new CoverageCoordAxis1D(builder));
} catch (InvalidRangeException e) {
return Optional.empty(e.getMessage());
}
}
public Optional subsetByIndex(Range range) {
try {
CoordAxisHelper helper = new CoordAxisHelper(this);
CoverageCoordAxisBuilder builder = helper.subsetByIndex(range);
return Optional.of(new CoverageCoordAxis1D(builder));
} catch (InvalidRangeException e) {
return Optional.empty(e.getMessage());
}
}
// LOOK incomplete handling of subsetting params
protected Optional subsetBuilder(SubsetParams params) {
if (params == null)
return Optional.of(new CoverageCoordAxisBuilder(this));
CoordAxisHelper helper = new CoordAxisHelper(this);
switch (getAxisType()) {
case GeoZ:
case Pressure:
case Height:
Double dval = params.getVertCoord();
if (dval != null)
return Optional.of(helper.subsetClosest(dval));
// use midpoint of interval LOOK may not always be unique
double[] intv = params.getVertCoordIntv();
if (intv != null)
return Optional.of(helper.subsetClosest((intv[0]+intv[1])/2));
double[] vertRange = params.getVertRange(); // used by WCS
if (vertRange != null)
return helper.subset(vertRange[0], vertRange[1], 1);
// default is all
break;
case Ensemble:
Double eval = params.getDouble(SubsetParams.ensCoord);
if (eval != null) {
return Optional.of(helper.subsetClosest(eval));
}
// default is all
break;
// x,y get seperately subsetted
case GeoX:
case GeoY:
case Lat:
case Lon:
throw new IllegalArgumentException();
// return null; // LOOK heres a case where null is "correct"
case Time:
if (params.isTrue(SubsetParams.timePresent))
return Optional.of(helper.subsetLatest());
CalendarDate date = (CalendarDate) params.get(SubsetParams.time);
if (date != null)
return Optional.of(helper.subsetClosest(date));
Integer stride = (Integer) params.get(SubsetParams.timeStride);
if (stride == null || stride < 0) stride = 1;
CalendarDateRange dateRange = (CalendarDateRange) params.get(SubsetParams.timeRange);
if (dateRange != null)
return helper.subset(dateRange, stride);
// If no time range or time point, a timeOffset can be used to specify the time point.
/* CalendarDate timeOffsetDate = params.getTimeOffsetDate();
if (timeOffsetDate != null) {
return Optional.of(helper.subsetClosest(timeOffsetDate));
} */
// A time offset or time offset interval starts from the rundate of the offset
Double timeOffset = params.getTimeOffset();
CalendarDate runtime = params.getRunTime();
if (timeOffset != null) {
if (runtime != null) {
date = makeDateInTimeUnits(runtime, timeOffset);
return Optional.of(helper.subsetClosest(date));
} else {
return Optional.of(helper.subsetClosest(timeOffset));
}
}
// If a time interval is sent, search for match.
double[] timeOffsetIntv = params.getTimeOffsetIntv();
if (timeOffsetIntv != null && runtime != null) {
// double midOffset = (timeOffsetIntv[0] + timeOffsetIntv[1]) / 2;
CalendarDate[] dateIntv = new CalendarDate[2];
dateIntv[0] = makeDateInTimeUnits(runtime, timeOffsetIntv[0]);
dateIntv[1] = makeDateInTimeUnits(runtime, timeOffsetIntv[1]);
return Optional.of(helper.subsetClosest(dateIntv));
}
if (stride != 1)
try {
return Optional.of(helper.subsetByIndex(getRange().setStride(stride)));
} catch (InvalidRangeException e) {
return Optional.empty(e.getMessage());
}
// default is all
break;
case RunTime:
CalendarDate rundate = (CalendarDate) params.get(SubsetParams.runtime);
if (rundate != null)
return Optional.of(helper.subsetClosest(rundate));
/* CalendarDateRange rundateRange = (CalendarDateRange) params.get(SubsetParams.runtimeRange);
if (rundateRange != null)
return helper.subset(rundateRange, 1); */
if (params.isTrue(SubsetParams.runtimeAll))
break;
// default is latest
return Optional.of(helper.subsetLatest());
case TimeOffset:
Double oval = params.getDouble(SubsetParams.timeOffset);
if (oval != null) {
return Optional.of(helper.subsetClosest(oval));
}
// If a time interval is sent, search for match.
timeOffsetIntv = params.getTimeOffsetIntv();
if (timeOffsetIntv != null) {
return Optional.of(helper.subsetClosest((timeOffsetIntv[0]+timeOffsetIntv[1])/2));
}
if (params.isTrue(SubsetParams.timeOffsetFirst)) {
try {
return Optional.of(helper.subsetByIndex(new Range(1)));
} catch (InvalidRangeException e) {
return Optional.empty(e.getMessage());
}
}
// default is all
break;
}
// otherwise return copy the original axis
return Optional.of(new CoverageCoordAxisBuilder(this));
}
@Override
public Optional subsetDependent(CoverageCoordAxis1D dependsOn) {
CoverageCoordAxisBuilder builder;
try {
builder = new CoordAxisHelper(this).subsetByIndex(dependsOn.getRange()); // LOOK Other possible subsets?
} catch (InvalidRangeException e) {
return Optional.empty(e.getMessage());
}
return Optional.of(new CoverageCoordAxis1D(builder));
}
// @Override
public Iterator iterator() {
return new MyIterator();
}
// Look what about intervals ??
private class MyIterator implements java.util.Iterator {
private int current = 0;
private int ncoords = getNcoords();
public boolean hasNext() {
return current < ncoords;
}
public Object next() {
return getCoordMidpoint(current++);
}
}
}