ucar.nc2.ft.point.standard.plug.CFpointObs Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cdm Show documentation
Show all versions of cdm 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-2014 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.ft.point.standard.plug;
import ucar.nc2.constants.CDM;
import ucar.nc2.dataset.CoordSysBuilder;
import ucar.nc2.dataset.CoordinateAxis;
import ucar.nc2.ft.point.standard.*;
import ucar.nc2.ft.point.standard.CoordSysEvaluator;
import ucar.nc2.dataset.NetcdfDataset;
import ucar.nc2.dataset.VariableDS;
import ucar.nc2.constants.FeatureType;
import ucar.nc2.constants.CF;
import ucar.nc2.constants.AxisType;
import ucar.nc2.Dimension;
import ucar.nc2.Variable;
import ucar.nc2.Structure;
import ucar.ma2.DataType;
import java.util.*;
import java.io.IOException;
/**
* CF "point obs" Convention.
*
* @author caron
* @see "http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.6/cf-conventions.html#discrete-sampling-geometries"
* @see "http://www.unidata.ucar.edu/software/netcdf-java/reference/FeatureDatasets/CFencodingTable.html"
* @since Nov 3, 2008
*/
public class CFpointObs extends TableConfigurerImpl {
protected enum Encoding {
single, // single feature in files
multidim, // feature(s1, s2, ...)
raggedContiguous,// row_size
raggedIndex, // stn_index
flat, // not used
// multiStructure // multiple structures (nc4)
}
public boolean isMine(FeatureType wantFeatureType, NetcdfDataset ds) {
String conv = ds.findAttValueIgnoreCase(null, CDM.CONVENTIONS, null);
if (conv == null) return false;
List names = CoordSysBuilder.breakupConventionNames(conv);
for (String s : names) {
if (s.startsWith("CF-1"))
return true;
}
return false;
}
public TableConfig getConfig(FeatureType wantFeatureType, NetcdfDataset ds, Formatter errlog) throws IOException {
EncodingInfo info = new EncodingInfo();
// figure out the actual feature type of the dataset
CF.FeatureType ftype = CF.FeatureType.getFeatureTypeFromGlobalAttribute(ds);
if (ftype == null) ftype = CF.FeatureType.point;
// make sure lat, lon, time coordinates exist
if (!checkCoordinates(ds, info, errlog)) return null; // fail fast
switch (ftype) {
case point:
return getPointConfig(ds, info, errlog);
case timeSeries:
return getStationConfig(ds, info, errlog);
case profile:
return getProfileConfig(ds, info, errlog);
case trajectory:
return getTrajectoryConfig(ds, info, errlog);
case timeSeriesProfile:
return getTimeSeriesProfileConfig(ds, info, errlog);
case trajectoryProfile:
return getSectionConfig(ds, info, errlog);
}
return null;
}
protected boolean checkCoordinates(NetcdfDataset ds, EncodingInfo info, Formatter errlog) {
boolean ok = true;
info.time = CoordSysEvaluator.findCoordByType(ds, AxisType.Time);
if (info.time == null) {
errlog.format("CFpointObs cant find a Time coordinate %n");
ok = false;
}
// find lat coord
info.lat = CoordSysEvaluator.findCoordByType(ds, AxisType.Lat);
if (info.lat == null) {
errlog.format("CFpointObs cant find a Latitude coordinate %n");
ok = false;
}
// find lon coord
info.lon = CoordSysEvaluator.findCoordByType(ds, AxisType.Lon);
if (info.lon == null) {
errlog.format("CFpointObs cant find a Longitude coordinate %n");
ok = false;
}
if (!ok) return false;
// dimensions must match
List dimLat = info.lat.getDimensions();
List dimLon = info.lon.getDimensions();
if (!dimLat.equals(dimLon)) {
errlog.format("CFpointObs Lat, Lon coordinate dimensions must match lat=%s lon=%s %n", info.lat.getNameAndDimensions(), info.lon.getNameAndDimensions());
ok = false;
}
return ok;
}
/////////////////////////////////////////////////////////////////////////////////
protected TableConfig getPointConfig(NetcdfDataset ds, EncodingInfo info, Formatter errlog) throws IOException {
if (info.time.getRank() != 1) {
errlog.format("CFpointObs type=point: coord time must have rank 1, coord var= %s %n", info.time.getNameAndDimensions());
return null;
}
Dimension obsDim = info.time.getDimension(0);
TableConfig obsTable = makeSingle(ds, obsDim, errlog);
obsTable.featureType = FeatureType.POINT;
return obsTable;
}
//////////////////////////////////////////////////////////////////////////////////
protected TableConfig getStationConfig(NetcdfDataset ds, EncodingInfo info, Formatter errlog) throws IOException {
if (!identifyEncodingStation(ds, info, CF.FeatureType.timeSeries, errlog))
return null;
// make station table
TableConfig stnTable = makeStationTable(ds, FeatureType.STATION, info, errlog);
if (stnTable == null) return null;
Dimension obsDim = info.childDim;
TableConfig obsTable = null;
switch (info.encoding) {
case single:
obsTable = makeSingle(ds, obsDim, errlog);
break;
case multidim:
obsTable = makeMultidimInner(ds, stnTable, info.childDim, info, errlog);
if (info.time.getRank() == 1) { // time(time)
obsTable.addJoin(new JoinArray(info.time, JoinArray.Type.raw, 0));
obsTable.time = info.time.getFullName();
}
break;
case raggedContiguous:
stnTable.numRecords = info.ragged_rowSize.getFullName();
obsTable = makeRaggedContiguousChildTable(ds, info.parentDim, info.childDim, info.childStruct, errlog);
break;
case raggedIndex:
obsTable = makeRaggedIndexChildTable(ds, info.parentDim, info.childDim, info.ragged_parentIndex, errlog);
break;
case flat:
info.set(Encoding.flat, obsDim);
obsTable = makeStructTable(ds, FeatureType.STATION, info, errlog);
obsTable.parentIndex = (info.instanceId == null) ? null : info.instanceId.getFullName();
Variable stnIdVar = Evaluator.findVariableWithAttributeAndDimension(ds, CF.CF_ROLE, CF.STATION_ID, obsDim, errlog);
if (stnIdVar == null)
stnIdVar = Evaluator.findVariableWithAttributeAndDimension(ds, CF.STANDARD_NAME, CF.STATION_ID, obsDim, errlog);
obsTable.stnId = (stnIdVar == null) ? null : stnIdVar.getFullName();
obsTable.stnDesc = Evaluator.findNameOfVariableWithAttributeValue(ds, CF.STANDARD_NAME, CF.PLATFORM_NAME);
if (obsTable.stnDesc == null)
obsTable.stnDesc = Evaluator.findNameOfVariableWithAttributeValue(ds, CF.STANDARD_NAME, CF.STATION_DESC);
obsTable.stnWmoId = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.STATION_WMOID, obsDim, errlog);
obsTable.stnAlt = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.SURFACE_ALTITUDE, obsDim, errlog);
if (obsTable.stnAlt == null)
obsTable.stnAlt = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.STATION_ALTITUDE, obsDim, errlog);
break;
}
if (obsTable == null) return null;
stnTable.addChild(obsTable);
return stnTable;
}
////
protected TableConfig getProfileConfig(NetcdfDataset ds, EncodingInfo info, Formatter errlog) throws IOException {
if (!identifyEncodingProfile(ds, info, errlog)) return null;
TableConfig profileTable = makeStructTable(ds, FeatureType.PROFILE, info, errlog);
if (profileTable == null) return null;
profileTable.feature_id = identifyIdVariableName(ds, CF.FeatureType.profile);
if (profileTable.feature_id == null) {
errlog.format("CFpointObs getProfileConfig cant find a profile id %n");
}
// obs table
VariableDS z = CoordSysEvaluator.findCoordByType(ds, AxisType.Height);
if (z == null) z = CoordSysEvaluator.findCoordByType(ds, AxisType.Pressure);
if (z == null) z = CoordSysEvaluator.findCoordByType(ds, AxisType.GeoZ);
if (z == null) {
errlog.format("CFpointObs getProfileConfig cant find a Height coordinate %n");
return null;
}
if (info.childStruct == null)
info.childStruct = z.getParentStructure();
TableConfig obsTable = null;
switch (info.encoding) {
case single:
obsTable = makeSingle(ds, info.childDim, errlog);
break;
case multidim:
obsTable = makeMultidimInner(ds, profileTable, info.childDim, info, errlog);
if (z.getRank() == 1) // z(z)
obsTable.addJoin(new JoinArray(z, JoinArray.Type.raw, 0));
break;
case raggedContiguous:
profileTable.numRecords = info.ragged_rowSize.getFullName();
obsTable = makeRaggedContiguousChildTable(ds, info.parentDim, info.childDim, info.childStruct, errlog);
break;
case raggedIndex:
obsTable = makeRaggedIndexChildTable(ds, info.parentDim, info.childDim, info.ragged_parentIndex, errlog);
break;
case flat:
throw new UnsupportedOperationException("CFpointObs: profile flat encoding");
}
if (obsTable == null) return null;
profileTable.addChild(obsTable);
return profileTable;
}
////
protected TableConfig getTrajectoryConfig(NetcdfDataset ds, EncodingInfo info, Formatter errlog) throws IOException {
if (!identifyEncodingTraj(ds, info, errlog)) return null;
TableConfig trajTable = makeStructTable(ds, FeatureType.TRAJECTORY, info, errlog);
if (trajTable == null) return null;
trajTable.feature_id = identifyIdVariableName(ds, CF.FeatureType.trajectory);
if (trajTable.feature_id == null) {
errlog.format("CFpointObs getTrajectoryConfig cant find a trajectoy id %n");
}
// obs table
//Variable time = CoordSysEvaluator.findCoordByType(ds, AxisType.Time);
//Dimension obsDim = time.getDimension(time.getRank() - 1); // may be time(time) or time(traj, obs)
TableConfig obsConfig = null;
switch (info.encoding) {
case single:
obsConfig = makeSingle(ds, info.childDim, errlog);
break;
case multidim:
obsConfig = makeMultidimInner(ds, trajTable, info.childDim, info, errlog);
break;
case raggedContiguous:
trajTable.numRecords = info.ragged_rowSize.getFullName();
obsConfig = makeRaggedContiguousChildTable(ds, info.parentDim, info.childDim, info.childStruct, errlog);
break;
case raggedIndex:
obsConfig = makeRaggedIndexChildTable(ds, info.parentDim, info.childDim, info.ragged_parentIndex, errlog);
break;
case flat:
throw new UnsupportedOperationException("CFpointObs: trajectory flat encoding");
}
if (obsConfig == null) return null;
trajTable.addChild(obsConfig);
return trajTable;
}
////
protected TableConfig getTimeSeriesProfileConfig(NetcdfDataset ds, EncodingInfo info, Formatter errlog) throws IOException {
if (!identifyEncodingTimeSeriesProfile(ds, info, CF.FeatureType.timeSeriesProfile, errlog)) return null;
VariableDS time = CoordSysEvaluator.findCoordByType(ds, AxisType.Time);
if (time == null) return null;
if (time.getRank() == 0 && time.getParentStructure() == null) {
errlog.format("CFpointObs timeSeriesProfile cannot have a scalar time coordinate%n"); // why ?
return null;
}
/* distinguish multidim from flat
if ((info.encoding == Encoding.multidim) && (time.getRank() < 3) && (z.getRank() < 3)) {
Variable parentId = identifyParent(ds, CF.FeatureType.timeSeriesProfile);
if ((parentId != null) && (parentId.getRank() == 1) && (parentId.getDimension(0).equals(time.getDimension(0)))) {
if (time.getRank() == 1) // multidim time must be 2 or 3 dim
info = new EncodingInfo(Encoding.flat, parentId);
else if (time.getRank() == 2) {
Dimension zDim = z.getDimension(z.getRank() - 1); // may be z(z) or z(profile, z)
if (zDim.equals(time.getDimension(1))) // flat 2D time will have time as inner dim
info = new EncodingInfo(Encoding.flat, parentId);
}
}
} */
TableConfig stationTable = makeStationTable(ds, FeatureType.STATION_PROFILE, info, errlog);
if (stationTable == null) return null;
//Dimension stationDim = ds.findDimension(stationTable.dimName);
//Dimension profileDim = null;
//Dimension zDim = null;
VariableDS z = info.alt;
switch (info.encoding) {
case single: {
assert ((time.getRank() >= 1) && (time.getRank() <= 2)) : "time must be rank 1 or 2";
assert ((z.getRank() >= 1) && (z.getRank() <= 2)) : "z must be rank 1 or 2";
if (time.getRank() == 2) {
if (z.getRank() == 2) // 2d time, 2d z
assert time.getDimensions().equals(z.getDimensions()) : "rank-2 time and z dimensions must be the same";
else // 2d time, 1d z
assert time.getDimension(1).equals(z.getDimension(0)) : "rank-2 time must have z inner dimension";
//profileDim = time.getDimension(0);
//zDim = time.getDimension(1);
} else { // 1d time
if (z.getRank() == 2) { // 1d time, 2d z
assert z.getDimension(0).equals(time.getDimension(0)) : "rank-2 z must have time outer dimension";
//profileDim = z.getDimension(0);
//zDim = z.getDimension(1);
} else { // 1d time, 1d z
assert !time.getDimension(0).equals(z.getDimension(0)) : "time and z dimensions must be different";
//profileDim = time.getDimension(0);
//zDim = z.getDimension(0);
}
}
// make profile table
TableConfig profileTable = makeStructTable(ds, FeatureType.PROFILE, new EncodingInfo().set(Encoding.multidim, info.childDim), errlog);
if (profileTable == null) return null;
if (time.getRank() == 1) // join time(time)
//profileTable.addJoin(new JoinArray(time, JoinArray.Type.raw, 0));
profileTable.addJoin(new JoinArray(time, JoinArray.Type.level, 1));
stationTable.addChild(profileTable);
// make the inner (z) table
TableConfig zTable = makeMultidimInner(ds, profileTable, info.grandChildDim, info, errlog);
if (z.getRank() == 1) // join z(z)
zTable.addJoin(new JoinArray(z, JoinArray.Type.raw, 0));
profileTable.addChild(zTable);
break;
}
case multidim: {
assert ((time.getRank() >= 1) && (time.getRank() <= 3)) : "time must be rank 2 or 3";
assert ((z.getRank() == 1) || (z.getRank() == 3)) : "z must be rank 1 or 3";
if (time.getRank() == 3) {
if (z.getRank() == 3) // 3d time, 3d z
assert time.getDimensions().equals(z.getDimensions()) : "rank-3 time and z dimensions must be the same";
else // 3d time, 1d z
assert time.getDimension(2).equals(z.getDimension(0)) : "rank-3 time must have z inner dimension";
//profileDim = time.getDimension(1);
//zDim = time.getDimension(2);
} else if (time.getRank() == 2) { // 2d time
if (z.getRank() == 3) { // 2d time, 3d z
assert z.getDimension(1).equals(time.getDimension(1)) : "rank-2 time must have time inner dimension";
//profileDim = z.getDimension(1);
//zDim = z.getDimension(2);
} else { // 2d time, 1d z
assert !time.getDimension(0).equals(z.getDimension(0)) : "time and z dimensions must be different";
assert !time.getDimension(1).equals(z.getDimension(0)) : "time and z dimensions must be different";
//profileDim = time.getDimension(1);
//zDim = z.getDimension(0);
}
} else { // 1d time
if (z.getRank() == 1) {
assert !time.getDimension(0).equals(z.getDimension(0)) : "time and z dimensions must be different";
}
}
TableConfig profileTable = makeMultidimInner(ds, stationTable, info.childDim, info, errlog);
if (profileTable == null) return null;
if (time.getRank() == 1) {// join time(time)
// profileTable.addJoin(new JoinArray(time, JoinArray.Type.raw, 0));
profileTable.addJoin(new JoinArray(time, JoinArray.Type.level, 1));
profileTable.time = time.getFullName();
}
stationTable.addChild(profileTable);
// make the inner (z) table
TableConfig zTable = makeMultidimInner3D(ds, stationTable, profileTable, info.grandChildDim, errlog);
if (z.getRank() == 1) { // join z(z)
zTable.addJoin(new JoinArray(z, JoinArray.Type.raw, 0));
zTable.elev = z.getFullName();
}
profileTable.addChild(zTable);
break;
}
case raggedIndex: {
TableConfig profileTable = makeRaggedIndexChildTable(ds, info.parentDim, info.childDim, info.ragged_parentIndex, errlog);
stationTable.addChild(profileTable);
profileTable.numRecords = info.ragged_rowSize.getFullName();
TableConfig obsTable = makeRaggedContiguousChildTable(ds, info.childDim, info.grandChildDim, info.grandChildStruct, errlog);
profileTable.addChild(obsTable);
break;
}
case raggedContiguous: // NOT USED
throw new UnsupportedOperationException("CFpointObs: timeSeriesProfile raggedContiguous encoding not allowed");
/*
case flat:
//profileDim = time.getDimension(0); // may be time(profile) or time(profile, z)
Variable parentId = identifyParent(ds, CF.FeatureType.timeSeriesProfile);
TableConfig profileTable = makeStructTable(ds, FeatureType.PROFILE, info, errlog);
profileTable.parentIndex = parentId.getName();
profileTable.stnId = findNameVariableWithStandardNameAndDimension(ds, CF.STATION_ID, info.childDim, errlog);
profileTable.stnDesc = findNameVariableWithStandardNameAndDimension(ds, CF.STATION_DESC, info.childDim, errlog);
profileTable.stnWmoId = findNameVariableWithStandardNameAndDimension(ds, CF.STATION_WMOID, info.childDim, errlog);
profileTable.stnAlt = findNameVariableWithStandardNameAndDimension(ds, CF.STATION_ALTITUDE, info.childDim, errlog);
stationTable.addChild(profileTable);
//zDim = z.getDimension(z.getRank() - 1); // may be z(z) or z(profile, z)
TableConfig zTable = makeMultidimInner(ds, profileTable, info.grandChildDim, errlog);
if (z.getRank() == 1) // z(z)
zTable.addJoin(new JoinArray(z, JoinArray.Type.raw, 0));
profileTable.addChild(zTable);
break; */
}
return stationTable;
}
protected TableConfig getSectionConfig(NetcdfDataset ds, EncodingInfo info, Formatter errlog) throws IOException {
if (!identifyEncodingSection(ds, info, CF.FeatureType.trajectoryProfile, errlog)) return null;
TableConfig parentTable = makeStructTable(ds, FeatureType.SECTION, info, errlog);
if (parentTable == null) return null;
parentTable.feature_id = identifyIdVariableName(ds, CF.FeatureType.trajectoryProfile);
if (parentTable.feature_id == null) {
errlog.format("CFpointObs:getSectionConfig cant find a section id %n");
}
//Dimension sectionDim = ds.findDimension(parentTable.dimName);
//Dimension profileDim = null;
//Dimension zDim = null;
VariableDS time = info.time;
VariableDS z = info.alt;
switch (info.encoding) {
case single: {
assert ((time.getRank() >= 1) && (time.getRank() <= 2)) : "time must be rank 1 or 2";
assert ((z.getRank() >= 1) && (z.getRank() <= 2)) : "z must be rank 1 or 2";
if (time.getRank() == 2) {
if (z.getRank() == 2) // 2d time, 2d z
assert time.getDimensions().equals(z.getDimensions()) : "rank-2 time and z dimensions must be the same";
else // 2d time, 1d z
assert time.getDimension(1).equals(z.getDimension(0)) : "rank-2 time must have z inner dimension";
//profileDim = time.getDimension(0);
//zDim = time.getDimension(1);
} else { // 1d time
if (z.getRank() == 2) { // 1d time, 2d z
assert z.getDimension(0).equals(time.getDimension(0)) : "rank-2 z must have time outer dimension";
//profileDim = z.getDimension(0);
//zDim = z.getDimension(1);
} else { // 1d time, 1d z
assert !time.getDimension(0).equals(z.getDimension(0)) : "time and z dimensions must be different";
//profileDim = time.getDimension(0);
//zDim = z.getDimension(0);
}
}
// make profile table
TableConfig profileTable = makeStructTable(ds, FeatureType.PROFILE, new EncodingInfo().set(Encoding.multidim, info.childDim), errlog);
if (profileTable == null) return null;
if (time.getRank() == 1) // join time(time)
profileTable.addJoin(new JoinArray(time, JoinArray.Type.raw, 0));
parentTable.addChild(profileTable);
// make the inner (z) table
TableConfig zTable = makeMultidimInner(ds, profileTable, info.grandChildDim, info, errlog);
if (z.getRank() == 1) // join z(z)
zTable.addJoin(new JoinArray(z, JoinArray.Type.raw, 0));
profileTable.addChild(zTable);
break;
}
case multidim: {
assert ((time.getRank() >= 2) && (time.getRank() <= 3)) : "time must be rank 2 or 3";
assert ((z.getRank() == 1) || (z.getRank() == 3)) : "z must be rank 1 or 3";
if (time.getRank() == 3) {
if (z.getRank() == 3) // 3d time, 3d z
assert time.getDimensions().equals(z.getDimensions()) : "rank-3 time and z dimensions must be the same";
else // 3d time, 1d z
assert time.getDimension(2).equals(z.getDimension(0)) : "rank-3 time must have z inner dimension";
//profileDim = time.getDimension(1);
//zDim = time.getDimension(2);
} else { // 2d time
if (z.getRank() == 3) { // 2d time, 3d z
assert z.getDimension(1).equals(time.getDimension(1)) : "rank-2 time must have time inner dimension";
// profileDim = z.getDimension(1);
//zDim = z.getDimension(2);
} else { // 2d time, 1d z
assert !time.getDimension(0).equals(z.getDimension(0)) : "time and z dimensions must be different";
assert !time.getDimension(1).equals(z.getDimension(0)) : "time and z dimensions must be different";
//profileDim = time.getDimension(1);
//zDim = z.getDimension(0);
}
}
// make profile table
// private TableConfig makeMultidimInner(NetcdfDataset ds, TableConfig parentTable, Dimension obsDim, Formatter errlog) throws IOException {
TableConfig profileTable = makeMultidimInner(ds, parentTable, info.childDim, info, errlog);
if (profileTable == null) return null;
profileTable.feature_id = identifyIdVariableName(ds, CF.FeatureType.profile);
parentTable.addChild(profileTable);
// make the inner (z) table
TableConfig zTable = makeMultidimInner3D(ds, parentTable, profileTable, info.grandChildDim, errlog);
if (z.getRank() == 1) // join z(z)
zTable.addJoin(new JoinArray(z, JoinArray.Type.raw, 0));
profileTable.addChild(zTable);
break;
}
case raggedIndex: {
TableConfig profileTable = makeRaggedIndexChildTable(ds, info.parentDim, info.childDim, info.ragged_parentIndex, errlog);
profileTable.feature_id = identifyIdVariableName(ds, CF.FeatureType.profile);
if (profileTable.feature_id == null) {
errlog.format("CFpointObs:getSectionConfig cant find a profile id %n");
}
parentTable.addChild(profileTable);
profileTable.numRecords = info.ragged_rowSize.getFullName();
TableConfig obsTable = makeRaggedContiguousChildTable(ds, info.childDim, info.grandChildDim, info.grandChildStruct, errlog);
profileTable.addChild(obsTable);
break;
}
case raggedContiguous: {
throw new UnsupportedOperationException("CFpointObs: section raggedContiguous encoding " + info.encoding);
}
/*
case flat:
parentTable.type = Table.Type.Construct; // override default
profileDim = time.getDimension(0); // may be time(profile) or time(profile, z)
Variable parentId = identifyParent(ds, CF.FeatureType.trajectoryProfile);
TableConfig profileTable = makeStructTable(ds, FeatureType.SECTION, info, errlog);
profileTable.parentIndex = parentId.getName();
profileTable.feature_id = identifyParentId(ds, CF.FeatureType.profile);
parentTable.addChild(profileTable);
zDim = z.getDimension(z.getRank() - 1); // may be z(z) or z(profile, z)
TableConfig zTable = makeMultidimInner(ds, profileTable, zDim, errlog);
if (z.getRank() == 1) // z(z)
zTable.addJoin(new JoinArray(z, JoinArray.Type.raw, 0));
profileTable.addChild(zTable);
break; */
}
return parentTable;
}
/////////////////////////////////////////////////////////////////////
protected static class EncodingInfo {
Encoding encoding;
VariableDS lat, lon, alt, time;
Dimension parentDim, childDim, grandChildDim;
Variable instanceId;
Variable ragged_parentIndex, ragged_rowSize;
Structure parentStruct, childStruct, grandChildStruct;
EncodingInfo set(Encoding encoding, Dimension parentDim) {
this.encoding = encoding;
this.parentDim = parentDim;
return this;
}
EncodingInfo set(Encoding encoding, Dimension parentDim, Dimension childDim) {
this.encoding = encoding;
this.parentDim = parentDim;
this.childDim = childDim;
return this;
}
EncodingInfo set(Encoding encoding, Dimension parentDim, Dimension childDim, Dimension grandChildDim) {
this.encoding = encoding;
this.parentDim = parentDim;
this.childDim = childDim;
this.grandChildDim = grandChildDim;
return this;
}
}
/* given the feature type, figure out the encoding
private EncodingInfo identifyEncoding(NetcdfDataset ds, CF.FeatureType ftype, Formatter errlog) {
Variable ragged_rowSize = Evaluator.findVariableWithAttribute(ds, CF.RAGGED_ROWSIZE);
if (ragged_rowSize != null) {
if (ftype == CF.FeatureType.trajectoryProfile) {
Variable parentId = identifyIdVariable(ds, ftype);
if (parentId == null) {
errlog.format("Section ragged must have section_id variable%n");
return null;
}
return new EncodingInfo(Encoding.raggedContiguous, parentId);
}
return new EncodingInfo(Encoding.raggedContiguous, ragged_rowSize);
}
Variable ragged_parentIndex = Evaluator.findVariableWithAttribute(ds, CF.RAGGED_PARENTINDEX);
if (ragged_parentIndex != null) {
Variable ragged_parentId = identifyIdVariable(ds, ftype);
return new EncodingInfo(Encoding.raggedIndex, ragged_parentId);
}
Variable lat = CoordSysEvaluator.findCoordByType(ds, AxisType.Lat);
if (lat == null) {
errlog.format("Must have a Latitude coordinate%n");
return null;
}
switch (ftype) {
case point:
return new EncodingInfo(Encoding.multidim, (Dimension) null);
case timeSeries:
case profile:
case timeSeriesProfile:
if (lat.getRank() == 0)
return new EncodingInfo(Encoding.single, (Dimension) null);
else if (lat.getRank() == 1)
return new EncodingInfo(Encoding.multidim, lat);
errlog.format("CFpointObs %s Must have Lat/Lon coordinates of rank 0 or 1%n", ftype);
return null;
case trajectory:
case trajectoryProfile:
if (lat.getRank() == 1)
return new EncodingInfo(Encoding.single, (Dimension) null);
else if (lat.getRank() == 2)
return new EncodingInfo(Encoding.multidim, lat);
errlog.format("CFpointObs %s Must have Lat/Lon coordinates of rank 1 or 2%n", ftype);
return null;
}
return null;
} */
// for stations, figure out the encoding
protected boolean identifyEncodingStation(NetcdfDataset ds, EncodingInfo info, CF.FeatureType ftype, Formatter errlog) {
// find the obs dimension
Dimension obsDim = null;
if (info.time.getRank() > 0)
obsDim = info.time.getDimension(info.time.getRank() - 1); // may be time(time) or time(stn, obs)
else if (info.time.getParentStructure() != null) {
Structure parent = info.time.getParentStructure(); // if time axis is a structure member, try pulling dimension out of parent structure
obsDim = parent.getDimension(parent.getRank() - 1);
}
if (obsDim == null) {
errlog.format("CFpointObs: must have a non-scalar Time coordinate%n");
return false;
}
// find the station dimension
if (info.lat.getRank() == 0) {// scalar means single
info.set(Encoding.single, null, obsDim);
return true;
}
Dimension stnDim = info.lat.getDimension(0);
if (obsDim == stnDim) {
info.set(Encoding.flat, null, obsDim); // not used ?
return true;
}
// the raggeds
if (identifyRaggeds(ds, info, stnDim, obsDim, errlog))
return true;
// heres whats left
if (info.lat.getRank() == 1) {
//Encoding e = (info.time.getParentStructure() != null) ? Encoding.multiStructure : Encoding.multidim;
info.set(Encoding.multidim, stnDim, obsDim);
return true;
}
errlog.format("CFpointObs: %s Must have Lat/Lon coordinates of rank 0 or 1%n", ftype);
return false;
}
/**
* Identify ragged array representations for single nests (station, profile, trajectory)
*
* @param ds in this dataset
* @param info put info here
* @param instanceDim the instance dimension, null if not known yet
* @param sampleDim the sample dimension, null if not known yet
* @param errlog error go here
* @return true if ragged array representations is found; side effect: set (info.ragged_rowSize, info.parentStruct) or (info.ragged_parentIndex, info.childStruct)
*/
protected boolean identifyRaggeds(NetcdfDataset ds, EncodingInfo info, Dimension instanceDim, Dimension sampleDim, Formatter errlog) {
// check for contiguous
Evaluator.VarAtt varatt = Evaluator.findVariableWithAttribute(ds, CF.SAMPLE_DIMENSION); // CF 1.6
if (varatt == null) varatt = Evaluator.findVariableWithAttribute(ds, CF.RAGGED_ROWSIZE); // backwards compatibility
if (varatt != null) {
Variable ragged_rowSize = varatt.var;
String sampleDimName = varatt.att.getStringValue();
if (sampleDim != null && !sampleDimName.equals(sampleDim.getShortName())) {
errlog.format("CFpointObs: Contiguous ragged array representation: row_size variable has sample dimension %s must be %s%n", sampleDimName, sampleDim.getShortName());
return false;
}
if (sampleDim == null) {
sampleDim = ds.findDimension(sampleDimName);
if (sampleDim == null) {
errlog.format("CFpointObs: Contiguous ragged array representation: row_size variable has invalid sample dimension %s%n", sampleDimName);
return false;
}
}
Dimension rrDim;
if (ragged_rowSize.getRank() > 0)
rrDim = ragged_rowSize.getDimension(0); // nobs(station)
else if (ragged_rowSize.getParentStructure() != null) {
Structure parent = ragged_rowSize.getParentStructure(); // if ragged_rowSize is a structure member, use dimension of parent structure
rrDim = parent.getDimension(0);
} else {
errlog.format("CFpointObs: Contiguous ragged array representation: row_size variable (%s) must have rank 1%n", ragged_rowSize);
return false;
}
if (instanceDim != null && instanceDim != rrDim) {
errlog.format("CFpointObs: Contiguous ragged array representation: row_size variable has invalid instance dimension %s must be %s%n", rrDim, instanceDim);
return false;
}
instanceDim = rrDim;
if (ragged_rowSize.getDataType() != DataType.INT) {
errlog.format("CFpointObs: Contiguous ragged array representation: row_size variable must be of type integer%n");
return false;
}
info.set(Encoding.raggedContiguous, instanceDim, sampleDim);
info.ragged_rowSize = ragged_rowSize;
info.parentStruct = ragged_rowSize.getParentStructure();
return true;
} // rowsize was found
varatt = Evaluator.findVariableWithAttribute(ds, CF.INSTANCE_DIMENSION); // CF 1.6
if (varatt == null) varatt = Evaluator.findVariableWithAttribute(ds, CF.RAGGED_PARENTINDEX); // backwards compatibility
if (varatt != null) {
Variable ragged_parentIndex = varatt.var;
String instanceDimName = varatt.att.getStringValue();
if (instanceDim != null && !instanceDimName.equals(instanceDim.getShortName())) {
errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable has instance dimension %s must be %s%n", instanceDimName, instanceDim.getShortName());
return false;
}
if (instanceDim == null) {
instanceDim = ds.findDimension(instanceDimName);
if (instanceDim == null) {
errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable has invalid instance dimension %s%n", instanceDimName);
return false;
}
}
if (ragged_parentIndex.getDataType() != DataType.INT) {
errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable must be of type integer%n");
return false;
}
// allow netcdf-4 structures, eg kunicki
if (ragged_parentIndex.isMemberOfStructure()) {
Structure s = ragged_parentIndex.getParentStructure();
if (s.getRank() == 0 || !s.getDimension(0).equals(sampleDim)) {
errlog.format("CFpointObs: Indexed ragged array representation (structure): parent_index variable must be of form Struct { %s }(%s) %n", ragged_parentIndex.getFullName(), sampleDim.getShortName());
return false;
}
} else {
if (ragged_parentIndex.getRank() != 1 || !ragged_parentIndex.getDimension(0).equals(sampleDim)) {
errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable must be of form %s(%s) %n", ragged_parentIndex.getFullName(), sampleDim.getShortName());
return false;
}
}
info.set(Encoding.raggedIndex, instanceDim, sampleDim);
info.ragged_parentIndex = ragged_parentIndex;
info.childStruct = ragged_parentIndex.getParentStructure();
return true;
} // parent index was found
/* kunicki 10/21/2011
Variable ragged_parentIndex = Evaluator.getVariableWithAttributeValue(ds, CF.RAGGED_PARENTINDEX, parentDim.getShortName());
if ((ragged_parentIndex == null) ||
(!ragged_parentIndex.isMemberOfStructure() && (ragged_parentIndex.getRank() == 0 || ragged_parentIndex.getDimension(0).getShortName() != childDim.getShortName()) ||
(ragged_parentIndex.isMemberOfStructure() && (ragged_parentIndex.getParentStructure().getRank() == 0 || ragged_parentIndex.getParentStructure().getDimension(0).getShortName() != childDim.getShortName())))
) {
// if ((null == ragged_parentIndex) || (ragged_parentIndex.getRank() == 0) || (ragged_parentIndex.getDimension(0).getShortName() != childDim.getShortName())) {
errlog.format("there must be a ragged_parent_index variable with outer dimension that matches obs dimension %s%n", childDim.getShortName());
return null;
} */
return false;
}
/**
* Identify ragged array representations for double nests (timeSeries profile, timeSeries trajectory)
*
* This uses the contiguous ragged array representation for each profile (9.5.43.3), and the indexed ragged array
* representation to organise the profiles into time series (9.3.54). The canonical use case is when writing real-time
* data streams that contain profiles from many stations, arriving randomly, with the data for each entire profile written all at once.
*
* @param ds in this dataset
* @param info put info here
* @param errlog error go here
* @return EncodingInfo if ragged array representations is found
*/
protected boolean identifyDoubleRaggeds(NetcdfDataset ds, EncodingInfo info, Formatter errlog) {
// the timeseries are stored as ragged index
Evaluator.VarAtt varatt = Evaluator.findVariableWithAttribute(ds, CF.INSTANCE_DIMENSION);
if (varatt == null) varatt = Evaluator.findVariableWithAttribute(ds, CF.RAGGED_PARENTINDEX);
if (varatt == null) return false;
Variable ragged_parentIndex = varatt.var;
String instanceDimName = varatt.att.getStringValue();
Dimension stationDim = ds.findDimension(instanceDimName);
if (stationDim == null) {
errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable has illegal value for %s = %s%n", CF.INSTANCE_DIMENSION, instanceDimName);
return false;
}
if (ragged_parentIndex.getDataType() != DataType.INT) {
errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable must be of type integer%n");
return false;
}
if (ragged_parentIndex.getRank() != 1 && info.childStruct == null) {
errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable %s must be 1D %n", ragged_parentIndex);
return false;
}
Dimension profileDim = (info.childDim != null) ? info.childDim : ragged_parentIndex.getDimension(0);
// onto the profiles, stored contiguously
varatt = Evaluator.findVariableWithAttribute(ds, CF.SAMPLE_DIMENSION);
if (varatt == null) varatt = Evaluator.findVariableWithAttribute(ds, CF.RAGGED_ROWSIZE);
if (varatt == null) return false;
Variable ragged_rowSize = varatt.var;
String obsDimName = varatt.att.getStringValue();
Dimension obsDim = ds.findDimension(obsDimName);
if (obsDimName == null) {
errlog.format("CFpointObs: Contiguous ragged array representation: parent_index variable has illegal value for %s = %s%n", CF.SAMPLE_DIMENSION, obsDimName);
return false;
}
if (!obsDimName.equals(info.grandChildDim.getShortName())) {
errlog.format("CFpointObs: Contiguous ragged array representation: row_size variable has obs dimension %s must be %s%n", obsDimName, info.childDim);
return false;
}
if (ragged_rowSize.getDataType() != DataType.INT) {
errlog.format("CFpointObs: Contiguous ragged array representation: row_size variable must be of type integer%n");
return false;
}
if (info.childDim == null) { // nc4 ext
Dimension profileDim2 = ragged_rowSize.getDimension(0);
if (profileDim2 != profileDim) {
errlog.format("CFpointObs: Double ragged array representation dimensions do not agree: %s != %s%n", profileDim2.getShortName(), profileDim.getShortName());
return false;
}
}
info.set(Encoding.raggedIndex, stationDim, profileDim, obsDim);
info.ragged_parentIndex = ragged_parentIndex;
info.ragged_rowSize = ragged_rowSize;
return true;
}
protected boolean identifyEncodingProfile(NetcdfDataset ds, EncodingInfo info, Formatter errlog) {
// find the obs dimension
VariableDS z = CoordSysEvaluator.findCoordByType(ds, AxisType.Height);
if (z == null) z = CoordSysEvaluator.findCoordByType(ds, AxisType.Pressure);
if (z == null) z = CoordSysEvaluator.findCoordByType(ds, AxisType.GeoZ);
if (z == null) {
errlog.format("CFpointObs: Must have a Height coordinate%n");
return false;
}
info.alt = z;
Dimension obsDim = null;
if (z.getRank() > 0)
obsDim = z.getDimension(z.getRank() - 1); // may be z(z) or alt(profile, z)
else if (z.getParentStructure() != null) {
Structure parent = z.getParentStructure(); // if time axis is a structure member, try pulling dimension out of parent structure
obsDim = parent.getDimension(parent.getRank() - 1);
}
if (obsDim == null) {
errlog.format("CFpointObs: Must have a non-scalar Height coordinate%n");
return false;
}
if (identifyRaggeds(ds, info, null, obsDim, errlog)) return true;
// parent dimension
Dimension parentDim;
if (z.getRank() > 1) {
parentDim = z.getDimension(0);
info.set(Encoding.multidim, parentDim, obsDim);
return true;
}
VariableDS time = CoordSysEvaluator.findCoordByType(ds, AxisType.Time);
if (time == null) return false;
if (time.getRank() == 0 || time.getDimension(0) == obsDim) {
info.set(Encoding.single, null, obsDim);
return true;
}
parentDim = time.getDimension(0);
info.set(Encoding.multidim, parentDim, obsDim);
return true;
}
protected boolean identifyEncodingTraj(NetcdfDataset ds, EncodingInfo info, Formatter errlog) {
// find the obs dimension
Dimension obsDim = null;
if (info.time.getRank() > 0)
obsDim = info.time.getDimension(info.time.getRank() - 1); // may be time(time) or time(traj, obs)
else if (info.time.getParentStructure() != null) {
Structure parent = info.time.getParentStructure(); // if time axis is a structure member, try pulling dimension out of parent structure
obsDim = parent.getDimension(parent.getRank() - 1);
}
if (obsDim == null) {
errlog.format("CFpointObs: Must have a non-scalar Time coordinate%n");
return false;
}
if (identifyRaggeds(ds, info, null, obsDim, errlog)) return true;
// parent dimension
Dimension parentDim;
if (info.time.getRank() > 1) {
parentDim = info.time.getDimension(0);
info.set(Encoding.multidim, parentDim, obsDim);
return true;
}
if (info.lat.getRank() > 0) { // multidim case
for (Dimension d : info.lat.getDimensions()) {
if (!d.equals(obsDim)) {
info.set(Encoding.multidim, d, obsDim);
return true;
}
}
}
//otherwise its a single traj in the file
info.set(Encoding.single, null, obsDim);
return true;
}
protected boolean identifyEncodingSection(NetcdfDataset ds, EncodingInfo info, CF.FeatureType ftype, Formatter errlog) {
// find the non-station altitude
VariableDS z = findZAxisNotStationAlt(ds);
if (z == null) {
errlog.format("CFpointObs: section must have a z coordinate%n");
return false;
}
if (z.getRank() == 0) {
errlog.format("CFpointObs: section cannot have a scalar z coordinate%n");
return false;
}
info.alt = z;
Dimension obsDim = null;
if (z.getRank() > 0)
obsDim = z.getDimension(z.getRank() - 1); // may be z(z) or alt(profile, z)
else if (z.getParentStructure() != null) {
Structure parent = z.getParentStructure(); // if time axis is a structure member, try pulling dimension out of parent structure
obsDim = parent.getDimension(parent.getRank() - 1);
}
if (obsDim == null) {
errlog.format("CFpointObs: Must have a non-scalar Height coordinate%n");
return false;
}
info.grandChildDim = obsDim;
// parent dimension
Dimension trajDim;
Dimension profileDim;
if (z.getRank() > 2) {
trajDim = z.getDimension(0);
profileDim = z.getDimension(1);
info.set(Encoding.multidim, trajDim, profileDim, obsDim);
return true;
}
if (identifyDoubleRaggeds(ds, info, errlog))
return true;
if (info.time.getRank() > 2) {
trajDim = info.time.getDimension(0);
profileDim = info.time.getDimension(1);
info.set(Encoding.multidim, trajDim, profileDim, obsDim);
return true;
}
if (info.lat.getRank() == 1) {
profileDim = info.lat.getDimension(0);
info.set(Encoding.single, null, profileDim, obsDim);
return true;
}
if (info.lat.getRank() == 2) {
trajDim = info.lat.getDimension(0);
profileDim = info.lat.getDimension(0);
info.set(Encoding.multidim, trajDim, profileDim, obsDim);
return true;
}
// forget flat for now
errlog.format("CFpointObs %s unrecognized form%n", ftype);
return false;
}
protected boolean identifyEncodingTimeSeriesProfile(NetcdfDataset ds, EncodingInfo info, CF.FeatureType ftype, Formatter errlog) {
// find the non-station altitude
VariableDS z = findZAxisNotStationAlt(ds);
if (z == null) {
errlog.format("CFpointObs: timeSeriesProfile must have a z coordinate, not the station altitude%n");
return false;
}
if (z.getRank() == 0) {
errlog.format("CFpointObs: timeSeriesProfile cannot have a scalar z coordinate%n");
return false;
}
Dimension obsDim = z.getDimension(z.getRank() - 1); // may be z(z) or alt(profile, z) or alt(sta,prof,z)
info.alt = z;
info.grandChildDim = obsDim;
// alt(sta,prof,z)
if (z.getRank() > 2) {
Dimension stnDim = z.getDimension(0);
Dimension profileDim = z.getDimension(1);
info.set(Encoding.multidim, stnDim, profileDim, obsDim);
return true;
}
// raggeds
if (identifyDoubleRaggeds(ds, info, errlog))
return true;
Dimension profileDim;
Dimension stnDim;
// single
if (info.lat.getRank() == 0) {
profileDim = info.time.getDimension(0); // may be time(profile) or time(profile, z)
info.set(Encoding.single, null, profileDim, obsDim);
return true;
} else { // lat must use the station dim
stnDim = info.lat.getDimension(0);
}
// multidim from here on
// time(profile) or time(profile, z)
if ((info.time.getRank() == 1) || (info.time.getRank() == 2 && info.time.getDimension(1) == obsDim)) {
profileDim = info.time.getDimension(0);
info.set(Encoding.multidim, stnDim, profileDim, obsDim);
return true;
}
// time(station, profile, z)
if (info.time.getRank() > 2) {
profileDim = info.time.getDimension(1);
info.set(Encoding.multidim, stnDim, profileDim, obsDim);
return true;
}
// time(station, profile)
if (info.time.getRank() == 2 && info.time.getDimension(0) == stnDim) {
profileDim = info.time.getDimension(1);
info.set(Encoding.multidim, stnDim, profileDim, obsDim);
return true;
}
errlog.format("CFpointObs %s unrecognized form%n", ftype);
return false;
}
private String identifyIdVariableName(NetcdfDataset ds, CF.FeatureType ftype) {
Variable v = identifyIdVariable(ds, ftype);
return (v == null) ? null : v.getFullName();
}
private Variable identifyIdVariable(NetcdfDataset ds, CF.FeatureType ftype) {
Variable result;
switch (ftype) {
case timeSeriesProfile:
case timeSeries:
result = Evaluator.findVariableWithAttributeValue(ds, CF.CF_ROLE, CF.TIMESERIES_ID);
if (result != null) return result;
return Evaluator.findVariableWithAttributeValue(ds, CF.STANDARD_NAME, CF.STATION_ID); // old way for backwards compatibility
case trajectory:
case trajectoryProfile:
result = Evaluator.findVariableWithAttributeValue(ds, CF.CF_ROLE, CF.TRAJECTORY_ID);
if (result != null) return result;
return Evaluator.findVariableWithAttributeValue(ds, CF.STANDARD_NAME, CF.TRAJECTORY_ID); // old way for backwards compatibility
case profile:
result = Evaluator.findVariableWithAttributeValue(ds, CF.CF_ROLE, CF.PROFILE_ID);
if (result != null) return result;
return Evaluator.findVariableWithAttributeValue(ds, CF.STANDARD_NAME, CF.PROFILE_ID); // old way for backwards compatibility
default:
return null;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// for station and stationProfile, not flat
private TableConfig makeStationTable(NetcdfDataset ds, FeatureType ftype, EncodingInfo info, Formatter errlog) throws IOException {
Variable lat = CoordSysEvaluator.findCoordByType(ds, AxisType.Lat);
Variable lon = CoordSysEvaluator.findCoordByType(ds, AxisType.Lon);
//Dimension stationDim = (info.encoding == Encoding.single) ? null : lat.getDimension(0); // assumes outer dim of lat is parent dimension, single = scalar
Table.Type stationTableType = Table.Type.Structure;
if (info.encoding == Encoding.single) stationTableType = Table.Type.Top;
if (info.encoding == Encoding.flat) stationTableType = Table.Type.Construct;
Dimension stationDim = (info.encoding == Encoding.flat) ? info.childDim : info.parentDim;
String name = (stationDim == null) ? " single" : stationDim.getShortName();
TableConfig stnTable = new TableConfig(stationTableType, name);
stnTable.featureType = ftype;
// stnId
Variable stnIdVar = Evaluator.findVariableWithAttributeAndDimension(ds, CF.CF_ROLE, CF.TIMESERIES_ID, stationDim, errlog);
if (stnIdVar == null)
stnIdVar = Evaluator.findVariableWithAttributeAndDimension(ds, CF.STANDARD_NAME, CF.STATION_ID, stationDim, errlog);
if (stnIdVar == null) {
errlog.format("CFpointObs: must have a Station id variable with %s = %s%n", CF.CF_ROLE, CF.TIMESERIES_ID);
return null;
}
stnTable.stnId = stnIdVar.getFullName();
info.instanceId = stnIdVar;
stnTable.stnDesc = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.PLATFORM_NAME, stationDim, errlog);
if (stnTable.stnDesc == null)
stnTable.stnDesc = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.STATION_DESC, stationDim, errlog);
stnTable.stnWmoId = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.PLATFORM_ID, stationDim, errlog);
if (stnTable.stnWmoId == null)
stnTable.stnWmoId = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.STATION_WMOID, stationDim, errlog);
stnTable.stnAlt = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.SURFACE_ALTITUDE, stationDim, errlog);
if (stnTable.stnAlt == null)
stnTable.stnAlt = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.STATION_ALTITUDE, stationDim, errlog);
stnTable.lat = lat.getFullName();
stnTable.lon = lon.getFullName();
if (info.encoding != Encoding.single) {
stnTable.dimName = stationDim.getShortName();
makeStructureInfo(stnTable, ds, stnIdVar.getParentStructure(), stationDim);
}
// LOOK probably need a standard name here
// optional alt coord - detect if its a station height or actually associated with the obs, eg for a profile
if (stnTable.stnAlt == null) {
Variable alt = CoordSysEvaluator.findCoordByType(ds, AxisType.Height);
if (alt != null) {
if ((info.encoding == Encoding.single) && alt.getRank() == 0)
stnTable.stnAlt = alt.getFullName();
if ((info.encoding != Encoding.single) && (lat.getRank() == alt.getRank()) && alt.getRank() > 0 && alt.getDimension(0).equals(stationDim))
stnTable.stnAlt = alt.getFullName();
}
}
return stnTable;
}
private void makeStructureInfo(TableConfig tableConfig, NetcdfDataset ds, Structure parent, Dimension dim) {
tableConfig.dimName = dim.getShortName();
if (parent != null) {
tableConfig.structureType = TableConfig.StructureType.Structure;
tableConfig.structName = parent.getShortName();
} else {
boolean hasNetcdf3Struct = Evaluator.hasNetcdf3RecordStructure(ds) && dim.isUnlimited();
tableConfig.structureType = hasNetcdf3Struct ? TableConfig.StructureType.Structure : TableConfig.StructureType.PsuedoStructure;
tableConfig.structName = hasNetcdf3Struct ? "record" : dim.getShortName();
}
}
private TableConfig makeStructTable(NetcdfDataset ds, FeatureType ftype, EncodingInfo info, Formatter errlog) throws IOException {
Table.Type tableType = Table.Type.Structure;
if (info.encoding == Encoding.single) tableType = Table.Type.Top;
if (info.encoding == Encoding.flat) tableType = Table.Type.ParentId;
String name = (info.parentDim == null) ? " single" : info.parentDim.getShortName();
TableConfig tableConfig = new TableConfig(tableType, name);
tableConfig.lat = matchAxisTypeAndDimension(ds, AxisType.Lat, info.parentDim);
tableConfig.lon = matchAxisTypeAndDimension(ds, AxisType.Lon, info.parentDim);
tableConfig.elev = matchAxisTypeAndDimension(ds, AxisType.Height, info.parentDim);
if (tableConfig.elev == null) tableConfig.elev = matchAxisTypeAndDimension(ds, AxisType.Pressure, info.parentDim);
if (tableConfig.elev == null) tableConfig.elev = matchAxisTypeAndDimension(ds, AxisType.GeoZ, info.parentDim);
tableConfig.time = matchAxisTypeAndDimension(ds, AxisType.Time, info.parentDim);
tableConfig.featureType = ftype;
if (info.encoding != Encoding.single) {
tableConfig.dimName = name;
Structure parent = info.parentStruct;
if (parent == null) {
switch (info.encoding) {
case raggedContiguous:
parent = info.ragged_rowSize.getParentStructure();
break;
case raggedIndex:
parent = info.ragged_parentIndex.getParentStructure();
break;
}
}
makeStructureInfo(tableConfig, ds, parent, info.parentDim);
}
return tableConfig;
}
// test E:/work/signell/traj2D.ncml
private TableConfig makeStructTableTestTraj(NetcdfDataset ds, FeatureType ftype, EncodingInfo info, Formatter errlog) throws IOException {
Table.Type tableType = Table.Type.Structure;
if (info.encoding == Encoding.single) tableType = Table.Type.Top;
if (info.encoding == Encoding.flat) tableType = Table.Type.ParentId;
String name = (info.parentDim == null) ? " single" : info.parentDim.getShortName();
TableConfig tableConfig = new TableConfig(tableType, name);
tableConfig.lat = CoordSysEvaluator.findCoordNameByType(ds, AxisType.Lat);
tableConfig.lon = CoordSysEvaluator.findCoordNameByType(ds, AxisType.Lon);
tableConfig.elev = CoordSysEvaluator.findCoordNameByType(ds, AxisType.Height);
if (tableConfig.elev == null) tableConfig.elev = CoordSysEvaluator.findCoordNameByType(ds, AxisType.Pressure);
if (tableConfig.elev == null) tableConfig.elev = CoordSysEvaluator.findCoordNameByType(ds, AxisType.GeoZ);
tableConfig.time = CoordSysEvaluator.findCoordNameByType(ds, AxisType.Time);
tableConfig.featureType = ftype;
if (info.encoding != Encoding.single) {
tableConfig.dimName = name;
makeStructureInfo(tableConfig, ds, null, info.parentDim);
}
return tableConfig;
}
/////////////////////////////////////////////////////////////////////////////////
private TableConfig makeRaggedContiguousChildTable(NetcdfDataset ds, Dimension parentDim, Dimension childDim, Structure childStruct, Formatter errlog) throws IOException {
TableConfig childTable = new TableConfig(Table.Type.Contiguous, childDim.getShortName());
childTable.dimName = childDim.getShortName();
childTable.lat = matchAxisTypeAndDimension(ds, AxisType.Lat, childDim);
childTable.lon = matchAxisTypeAndDimension(ds, AxisType.Lon, childDim);
childTable.elev = matchAxisTypeAndDimension(ds, AxisType.Height, childDim);
if (childTable.elev == null) childTable.elev = matchAxisTypeAndDimension(ds, AxisType.Pressure, childDim);
if (childTable.elev == null) childTable.elev = matchAxisTypeAndDimension(ds, AxisType.GeoZ, childDim);
childTable.time = matchAxisTypeAndDimension(ds, AxisType.Time, childDim);
makeStructureInfo(childTable, ds, childStruct, childDim);
return childTable;
}
private TableConfig makeRaggedIndexChildTable(NetcdfDataset ds, Dimension parentDim, Dimension childDim, Variable ragged_parentIndex, Formatter errlog) throws IOException {
TableConfig childTable = new TableConfig(Table.Type.ParentIndex, childDim.getShortName());
childTable.dimName = childDim.getShortName();
childTable.lat = matchAxisTypeAndDimension(ds, AxisType.Lat, childDim);
childTable.lon = matchAxisTypeAndDimension(ds, AxisType.Lon, childDim);
childTable.elev = matchAxisTypeAndDimension(ds, AxisType.Height, childDim);
if (childTable.elev == null) childTable.elev = matchAxisTypeAndDimension(ds, AxisType.Pressure, childDim);
if (childTable.elev == null) childTable.elev = matchAxisTypeAndDimension(ds, AxisType.GeoZ, childDim);
childTable.time = matchAxisTypeAndDimension(ds, AxisType.Time, childDim);
makeStructureInfo(childTable, ds, ragged_parentIndex.getParentStructure(), childDim);
childTable.parentIndex = ragged_parentIndex.getFullName();
return childTable;
}
// the inner table of Structure(outer, inner) and middle table of Structure(outer, middle, inner)
private TableConfig makeMultidimInner(NetcdfDataset ds, TableConfig parentTable, Dimension obsDim, EncodingInfo info, Formatter errlog) throws IOException {
Dimension parentDim = ds.findDimension(parentTable.dimName);
Table.Type obsTableType = (parentTable.structureType == TableConfig.StructureType.PsuedoStructure) ? Table.Type.MultidimInnerPsuedo : Table.Type.MultidimInner;
// if (info.time.isMemberOfStructure()) obsTableType = Table.Type.Structure;
TableConfig obsTable = new TableConfig(obsTableType, obsDim.getShortName());
obsTable.lat = matchAxisTypeAndDimension(ds, AxisType.Lat, parentDim, obsDim);
obsTable.lon = matchAxisTypeAndDimension(ds, AxisType.Lon, parentDim, obsDim);
obsTable.elev = matchAxisTypeAndDimension(ds, AxisType.Height, parentDim, obsDim);
if (obsTable.elev == null) obsTable.elev = matchAxisTypeAndDimension(ds, AxisType.Pressure, parentDim, obsDim);
if (obsTable.elev == null) obsTable.elev = matchAxisTypeAndDimension(ds, AxisType.GeoZ, parentDim, obsDim);
obsTable.time = matchAxisTypeAndDimension(ds, AxisType.Time, parentDim, obsDim);
// divide up the variables between the parent and the obs
List obsVars;
List vars = ds.getVariables();
List parentVars = new ArrayList<>(vars.size());
obsVars = new ArrayList<>(vars.size());
for (Variable orgV : vars) {
if (orgV instanceof Structure) continue;
Dimension dim0 = orgV.getDimension(0);
if ((dim0 != null) && dim0.equals(parentDim)) {
if ((orgV.getRank() == 1) || ((orgV.getRank() == 2) && orgV.getDataType() == DataType.CHAR)) {
parentVars.add(orgV.getShortName());
} else {
Dimension dim1 = orgV.getDimension(1);
if ((dim1 != null) && dim1.equals(obsDim))
obsVars.add(orgV.getShortName());
}
}
}
parentTable.vars = parentVars;
// parentTable.vars = parentTable.isPsuedoStructure ? parentVars : null; // restrict to these if psuedoStruct
obsTable.structureType = parentTable.structureType;
obsTable.outerName = parentDim.getShortName();
obsTable.innerName = obsDim.getShortName();
obsTable.dimName = (parentTable.structureType == TableConfig.StructureType.PsuedoStructure) ? obsTable.outerName : obsTable.innerName;
obsTable.structName = obsDim.getShortName();
obsTable.vars = obsVars;
return obsTable;
}
// the inner table of Structure(outer, middle, inner)
private TableConfig makeMultidimInner3D(NetcdfDataset ds, TableConfig outerTable, TableConfig middleTable, Dimension innerDim, Formatter errlog) throws IOException {
Dimension outerDim = ds.findDimension(outerTable.dimName);
Dimension middleDim = ds.findDimension(middleTable.innerName);
Table.Type obsTableType = (outerTable.structureType == TableConfig.StructureType.PsuedoStructure) ? Table.Type.MultidimInnerPsuedo3D : Table.Type.MultidimInner3D;
TableConfig obsTable = new TableConfig(obsTableType, innerDim.getShortName());
obsTable.structureType = TableConfig.StructureType.PsuedoStructure2D;
obsTable.dimName = outerTable.dimName;
obsTable.outerName = middleTable.innerName;
obsTable.innerName = innerDim.getShortName();
obsTable.structName = innerDim.getShortName();
obsTable.lat = matchAxisTypeAndDimension(ds, AxisType.Lat, outerDim, middleDim, innerDim);
obsTable.lon = matchAxisTypeAndDimension(ds, AxisType.Lon, outerDim, middleDim, innerDim);
obsTable.elev = matchAxisTypeAndDimension(ds, AxisType.Height, outerDim, middleDim, innerDim);
if (obsTable.elev == null) obsTable.elev = matchAxisTypeAndDimension(ds, AxisType.Pressure, middleDim, innerDim);
if (obsTable.elev == null) obsTable.elev = matchAxisTypeAndDimension(ds, AxisType.GeoZ, middleDim, innerDim);
obsTable.time = matchAxisTypeAndDimension(ds, AxisType.Time, outerDim, middleDim, innerDim);
// divide up the variables between the 3 tables
List vars = ds.getVariables();
List outerVars = new ArrayList<>(vars.size());
List middleVars = new ArrayList<>(vars.size());
List innerVars = new ArrayList<>(vars.size());
for (Variable orgV : vars) {
if (orgV instanceof Structure) continue;
if ((orgV.getRank() == 1) || ((orgV.getRank() == 2) && orgV.getDataType() == DataType.CHAR)) {
if (outerDim.equals(orgV.getDimension(0)))
outerVars.add(orgV.getShortName());
} else if (orgV.getRank() == 2) {
if (outerDim.equals(orgV.getDimension(0)) && middleDim.equals(orgV.getDimension(1)))
middleVars.add(orgV.getShortName());
} else if (orgV.getRank() == 3) {
if (outerDim.equals(orgV.getDimension(0)) && middleDim.equals(orgV.getDimension(1)) && innerDim.equals(orgV.getDimension(2)))
innerVars.add(orgV.getShortName());
}
}
outerTable.vars = outerVars;
middleTable.vars = middleVars;
obsTable.vars = innerVars;
return obsTable;
}
private TableConfig makeSingle(NetcdfDataset ds, Dimension obsDim, Formatter errlog) throws IOException {
Table.Type obsTableType = Table.Type.Structure;
TableConfig obsTable = new TableConfig(obsTableType, "single");
obsTable.dimName = obsDim.getShortName();
obsTable.lat = matchAxisTypeAndDimension(ds, AxisType.Lat, obsDim);
obsTable.lon = matchAxisTypeAndDimension(ds, AxisType.Lon, obsDim);
obsTable.elev = matchAxisTypeAndDimension(ds, AxisType.Height, obsDim);
if (obsTable.elev == null) obsTable.elev = matchAxisTypeAndDimension(ds, AxisType.Pressure, obsDim);
if (obsTable.elev == null) obsTable.elev = matchAxisTypeAndDimension(ds, AxisType.GeoZ, obsDim);
obsTable.time = matchAxisTypeAndDimension(ds, AxisType.Time, obsDim);
makeStructureInfo(obsTable, ds, null, obsDim);
return obsTable;
}
private TableConfig makeMiddleTable(NetcdfDataset ds, TableConfig parentTable, Dimension obsDim, Formatter errlog) throws IOException {
throw new UnsupportedOperationException("CFpointObs: middleTable encoding");
}
// Adds check for dimensions against parent structure if applicable...
//
// Note to John. It may be that this implementation can be pushed into the super
// class, I don't understand enough of the code base to anticipate implementation artifacts.
protected String matchAxisTypeAndDimension(NetcdfDataset ds, AxisType type, final Dimension outer) {
Variable var = CoordSysEvaluator.findCoordByType(ds, type, new CoordSysEvaluator.Predicate() {
public boolean match(CoordinateAxis axis) {
if ((outer == null) && (axis.getRank() == 0))
return true;
if ((outer != null) && (axis.getRank() == 1) && (outer.equals(axis.getDimension(0))))
return true;
// if axis is structure member, try pulling dimension out of parent structure
if (axis.getParentStructure() != null) {
Structure parent = axis.getParentStructure();
if ((outer != null) && (parent.getRank() == 1) && (outer.equals(parent.getDimension(0))))
return true;
}
return false;
}
});
if (var == null) return null;
return var.getFullName();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy