/* * 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.constants.FeatureType; import ucar.nc2.constants.CF; import ucar.nc2.constants.AxisType; import ucar.nc2.dataset.NetcdfDataset; import ucar.nc2.dataset.StructurePseudoDS; import ucar.nc2.dataset.VariableDS; import ucar.nc2.dataset.StructureDS; import ucar.nc2.ft.point.standard.*; import ucar.nc2.*; import ucar.ma2.DataType; import java.util.*; import java.io.IOException; /** * Gempak Point Obs data. * * @author caron * @since Mar 3, 2009 */ public class GempakCdm extends TableConfigurerImpl { private static final String Convention = "GEMPAK/CDM"; public boolean isMine(FeatureType wantFeatureType, NetcdfDataset ds) { boolean ok = false; String conv = ds.findAttValueIgnoreCase(null, CDM.CONVENTIONS, null); if (conv == null) return false; if (conv.equals(Convention)) ok = true; StringTokenizer stoke = new StringTokenizer(conv, ","); while (stoke.hasMoreTokens()) { String toke = stoke.nextToken().trim(); if (toke.equals(Convention)) ok = true; } if (!ok) return false; CF.FeatureType ftype = CF.FeatureType.getFeatureTypeFromGlobalAttribute(ds); if (ftype == null) ftype = CF.FeatureType.point; return (ftype == CF.FeatureType.timeSeries) || (ftype == CF.FeatureType.timeSeriesProfile); } public TableConfig getConfig(FeatureType wantFeatureType, NetcdfDataset ds, Formatter errlog) throws IOException { CF.FeatureType ftype = CF.FeatureType.getFeatureTypeFromGlobalAttribute(ds); if (ftype == null) ftype = CF.FeatureType.point; switch (ftype) { case point: return null; // use default handler case timeSeries: if (wantFeatureType == FeatureType.POINT) return getStationAsPointConfig(ds, errlog); else return getStationConfig(ds, errlog); case timeSeriesProfile: return getStationProfileConfig(ds, errlog); default: throw new IllegalStateException("unimplemented feature ftype= " + ftype); } } protected TableConfig getStationConfig(NetcdfDataset ds, Formatter errlog) throws IOException { final boolean needFinish = false; // find lat coord Variable lat = CoordSysEvaluator.findCoordByType(ds, AxisType.Lat); if (lat == null) { errlog.format("GempakCdm: Must have a Latitude coordinate"); return null; } // find lon coord Variable lon = CoordSysEvaluator.findCoordByType(ds, AxisType.Lon); if (lon == null) { errlog.format("GempakCdm: Must have a Longitude coordinate"); return null; } if (lat.getRank() != lon.getRank()) { errlog.format("GempakCdm: Lat and Lon coordinate must have same rank"); return null; } // check dimensions boolean stnIsScalar = (lat.getRank() == 0); boolean stnIsSingle = (lat.getRank() == 1) && (lat.getSize() == 1); Dimension stationDim = null; if (!stnIsScalar) { if (lat.getDimension(0) != lon.getDimension(0)) { errlog.format("GempakCdm: Lat and Lon coordinate must have same size"); return null; } stationDim = lat.getDimension(0); } boolean hasStruct = Evaluator.hasNetcdf3RecordStructure(ds); Table.Type stationTableType = stnIsScalar ? Table.Type.Top : Table.Type.Structure; TableConfig stnTable = new TableConfig(stationTableType, "station"); stnTable.featureType = FeatureType.STATION; stnTable.structureType = hasStruct ? TableConfig.StructureType.Structure : TableConfig.StructureType.PsuedoStructure; if (!stnIsScalar) stnTable.dimName = stationDim.getShortName(); stnTable.lat= lat.getFullName(); stnTable.lon= lon.getFullName(); // optional alt coord Variable alt = CoordSysEvaluator.findCoordByType(ds, AxisType.Height); if (alt != null) stnTable.stnAlt = alt.getFullName(); // station id stnTable.stnId = Evaluator.findNameOfVariableWithAttributeValue(ds, "standard_name", "station_id"); if (stnTable.stnId == null) { errlog.format("Must have a Station id variable with standard name station_id"); return null; } Variable stnId = ds.findVariable(stnTable.stnId); if (!stnIsScalar) { if (!stnId.getDimension(0).equals(stationDim)) { errlog.format("GempakCdm: Station id (%s) outer dimension must match latitude/longitude dimension (%s)", stnTable.stnId, stationDim); return null; } } // obs table VariableDS time = CoordSysEvaluator.findCoordByType(ds, AxisType.Time); if (time == null) { errlog.format("GempakCdm: Must have a Time coordinate"); return null; } Dimension obsDim = time.getDimension(time.getRank()-1); // may be time(time) or time(stn, obs) Table.Type obsTableType = null; Structure multidimStruct = null; if (obsTableType == null) { // Structure(station, time) multidimStruct = Evaluator.findStructureWithDimensions(ds, stationDim, obsDim); if (multidimStruct != null) { obsTableType = Table.Type.MultidimStructure; } } // multidim case if (obsTableType == null) { // time(station, time) if (time.getRank() == 2) { obsTableType = Table.Type.MultidimInner; } } if (obsTableType == null) { errlog.format("GempakCdm: Cannot figure out Station/obs table structure"); return null; } TableConfig obs = new TableConfig(obsTableType, obsDim.getShortName()); obs.dimName = obsDim.getShortName(); obs.time = time.getFullName(); obs.missingVar = "_isMissing"; stnTable.addChild(obs); if (obsTableType == Table.Type.MultidimStructure) { obs.structName = multidimStruct.getFullName(); obs.structureType = TableConfig.StructureType.Structure; // if time is not in this structure, need to join it if (multidimStruct.findVariable( time.getShortName()) == null) { obs.addJoin(new JoinArray( time, JoinArray.Type.raw, 0)); } } if (obsTableType == Table.Type.MultidimInner) { obs.dimName = obsDim.getShortName(); } if (needFinish) ds.finish(); return stnTable; } protected TableConfig getStationAsPointConfig(NetcdfDataset ds, Formatter errlog) throws IOException { final boolean needFinish = false; // find lat coord Variable lat = CoordSysEvaluator.findCoordByType(ds, AxisType.Lat); if (lat == null) { errlog.format("GempakCdm: Must have a Latitude coordinate"); return null; } // find lon coord Variable lon = CoordSysEvaluator.findCoordByType(ds, AxisType.Lon); if (lon == null) { errlog.format("GempakCdm: Must have a Longitude coordinate"); return null; } if (lat.getRank() != lon.getRank()) { errlog.format("GempakCdm: Lat and Lon coordinate must have same rank"); return null; } // check dimensions boolean stnIsScalar = (lat.getRank() == 0); boolean stnIsSingle = (lat.getRank() == 1) && (lat.getSize() == 1); Dimension stationDim = null; if (!stnIsScalar) { if (lat.getDimension(0) != lon.getDimension(0)) { errlog.format("Lat and Lon coordinate must have same size"); return null; } stationDim = lat.getDimension(0); } // optional alt coord Variable alt = CoordSysEvaluator.findCoordByType(ds, AxisType.Height); // obs table VariableDS time = CoordSysEvaluator.findCoordByType(ds, AxisType.Time); if (time == null) { errlog.format("GempakCdm: Must have a Time coordinate"); return null; } Dimension obsDim = time.getDimension(time.getRank()-1); // may be time(time) or time(stn, obs) Table.Type obsTableType = Table.Type.Structure; Structure multidimStruct = Evaluator.findStructureWithDimensions(ds, stationDim, obsDim); if (multidimStruct == null) { errlog.format("GempakCdm: Cannot figure out StationAsPoint table structure"); return null; } TableConfig obs = new TableConfig(obsTableType, obsDim.getShortName()); obs.dimName = obsDim.getShortName(); obs.structName = multidimStruct.getFullName(); obs.structureType = TableConfig.StructureType.Structure; obs.featureType = FeatureType.POINT; obs.lat= lat.getFullName(); obs.lon= lon.getFullName(); obs.time= time.getFullName(); if (alt != null) obs.elev = alt.getFullName(); List<String> vars = new ArrayList<String>(30); for (Variable v : ds.getVariables()) { if ((v.getDimension(0) == stationDim) && ((v.getRank() == 1) || ((v.getRank() == 2) && (v.getDataType() == DataType.CHAR)))) vars.add(v.getShortName()); } StructureDS s = new StructurePseudoDS(ds, null, "stnStruct", vars, stationDim); obs.addJoin(new JoinMuiltdimStructure(s, obsDim.getLength())); obs.addJoin(new JoinArray( time, JoinArray.Type.modulo, obsDim.getLength())); if (needFinish) ds.finish(); return obs; } protected TableConfig getStationProfileConfig(NetcdfDataset ds, Formatter errlog) throws IOException { TableConfig stnTable = makeStationTable(ds, errlog); if (stnTable == null) return null; Dimension stationDim = ds.findDimension( stnTable.dimName); stnTable.featureType = FeatureType.STATION_PROFILE; // obs table VariableDS time = CoordSysEvaluator.findCoordByType(ds, AxisType.Time); if (time == null) { errlog.format("GempakCdm: Must have a Time coordinate"); return null; } Dimension obsDim = time.getDimension(time.getRank()-1); // may be time(time) or time(stn, obs) Structure multidimStruct = Evaluator.findStructureWithDimensions(ds, stationDim, obsDim); if (multidimStruct == null) { errlog.format("GempakCdm: Cannot figure out Station/obs table structure"); return null; } TableConfig timeTable = new TableConfig(Table.Type.MultidimStructure, obsDim.getShortName()); timeTable.missingVar = "_isMissing"; timeTable.structName = multidimStruct.getFullName(); timeTable.structureType = TableConfig.StructureType.Structure; timeTable.addJoin(new JoinArray(time, JoinArray.Type.level, 1)); timeTable.time = time.getFullName(); timeTable.feature_id = time.getFullName(); stnTable.addChild(timeTable); TableConfig obsTable = new TableConfig(Table.Type.NestedStructure, obsDim.getShortName()); Structure nestedStruct = Evaluator.findNestedStructure(multidimStruct); if (nestedStruct == null) { errlog.format("GempakCdm: Cannot find nested Structure for profile"); return null; } obsTable.structName = nestedStruct.getFullName(); obsTable.nestedTableName = nestedStruct.getShortName(); Variable elev = findZAxisNotStationAlt(ds); if (elev == null) { errlog.format("GempakCdm: Cannot find profile elevation variable"); return null; } obsTable.elev = elev.getShortName(); timeTable.addChild(obsTable); return stnTable; } protected TableConfig makeStationTable(NetcdfDataset ds, Formatter errlog) throws IOException { // find lat coord Variable lat = CoordSysEvaluator.findCoordByType(ds, AxisType.Lat); if (lat == null) { errlog.format("GempakCdm: Must have a Latitude coordinate"); return null; } // find lon coord Variable lon = CoordSysEvaluator.findCoordByType(ds, AxisType.Lon); if (lon == null) { errlog.format("GempakCdm: Must have a Longitude coordinate"); return null; } if (lat.getRank() != lon.getRank()) { errlog.format("GempakCdm: Lat and Lon coordinate must have same rank"); return null; } // check dimensions Dimension stationDim = null; if (lat.getDimension(0) != lon.getDimension(0)) { errlog.format("GempakCdm: Lat and Lon coordinate must have same size"); return null; } stationDim = lat.getDimension(0); Table.Type stationTableType = Table.Type.Structure; TableConfig stnTable = new TableConfig(stationTableType, "station"); stnTable.structureType = TableConfig.StructureType.PsuedoStructure; stnTable.dimName = stationDim.getShortName(); stnTable.lat= lat.getFullName(); stnTable.lon= lon.getFullName(); stnTable.stnId = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.STATION_ID, stationDim, errlog); stnTable.stnDesc = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.STATION_DESC, stationDim, errlog); stnTable.stnWmoId = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.STATION_WMOID, stationDim, errlog); stnTable.stnAlt = Evaluator.findNameVariableWithStandardNameAndDimension(ds, CF.STATION_ALTITUDE, stationDim, errlog); if (stnTable.stnId == null) { errlog.format("Must have a Station id variable with standard name station_id"); return null; } Variable stnId = ds.findVariable(stnTable.stnId); if (!stnId.getDimension(0).equals(stationDim)) { errlog.format("GempakCdm: Station id (%s) outer dimension must match latitude/longitude dimension (%s)", stnTable.stnId, stationDim); return null; } return stnTable; } }