ucar.nc2.ft.point.standard.Table 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;
import ucar.nc2.*;
import ucar.nc2.ft.point.StructureDataIteratorLinked;
import ucar.nc2.ft.point.StructureDataIteratorIndexed;
import ucar.nc2.dataset.*;
import ucar.nc2.constants.FeatureType;
import ucar.ma2.*;
import java.util.*;
import java.io.IOException;
/**
* A generalization of a Structure. Main function is to return a StructureDataIterator,
* iterating over its table rows
*
* @author caron
* @since Jan 20, 2009
*/
public abstract class Table {
static private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Table.class);
public enum CoordName {
Lat, Lon, Elev, Time, TimeNominal, StnId, StnDesc, WmoId, StnAlt, FeatureId, MissingVar
}
public enum Type {
ArrayStructure, Construct, Contiguous, LinkedList,
MultidimInner, MultidimInner3D, MultidimInnerPsuedo, MultidimInnerPsuedo3D, MultidimStructure,
NestedStructure, ParentId, ParentIndex, Singleton, Structure, Top
}
public static Table factory(NetcdfDataset ds, TableConfig config) {
switch (config.type) {
case ArrayStructure: // given array of StructureData, stored in config.as
return new TableArrayStructure(ds, config);
case Construct: // construct the table from its children - theres no seperate station table, stn info is duplicated in the obs structure.
return new TableConstruct(ds, config);
case Contiguous: // contiguous list of child record, using indexes
return new TableContiguous(ds, config);
case LinkedList: // linked list of child records, using indexes
return new TableLinkedList(ds, config);
case MultidimInner: // the inner struct of a 2D multdim(outer, inner) with unlimited dimension
return new TableMultidimInner(ds, config);
case MultidimInner3D: // the inner struct of a 3D multdim(outer, middle, inner) with unlimited dimension
return new TableMultidimInner3D(ds, config);
case MultidimStructure: // the outer struct of a multidim structure
return new TableMultidimStructure(ds, config);
case MultidimInnerPsuedo: // the inner struct of a 2D multdim(outer, inner) without the unlimited dimension
// the middle struct of a 3D multdim(outer, middle, inner) without the unlimited dimension
return new TableMultidimInnerPsuedo(ds, config);
case MultidimInnerPsuedo3D: // the inner struct of a 3D multdim(outer, middle, inner) without the unlimited dimension
return new TableMultidimInnerPsuedo3D(ds, config);
case NestedStructure: // Structure or Sequence is nested in the parent
return new TableNestedStructure(ds, config);
case ParentId: // child record has an id for the parent.
return new TableParentId(ds, config);
case ParentIndex: // child record has the record index of the parent.
return new TableParentIndex(ds, config);
case Singleton: // singleton row, with given StructureData
return new TableSingleton(ds, config);
case Structure: // Structure or PsuedoStructure
return new TableStructure(ds, config);
case Top: // singleton consisting of top variables and constants
return new TableTop(ds, config);
}
throw new IllegalStateException("Unimplemented Table type = " + config.type);
}
////////////////////////////////////////////////////////////////////////////////////////
String name;
FeatureType featureType;
Table parent, child;
List extraJoins;
String lat, lon, elev, time, timeNominal;
String stnId, stnDesc, stnNpts, stnWmoId, stnAlt, limit;
String feature_id, missingVar;
Map cols = new HashMap<>(); // all variables
Set nondataVars = new HashSet<>(); // exclude these from the getDataVariables() list
protected Table(NetcdfDataset ds, TableConfig config) {
this.name = config.name;
this.featureType = config.featureType;
this.lat = config.lat;
this.lon = config.lon;
this.elev = config.elev;
this.time = config.time;
this.timeNominal = config.timeNominal;
this.stnId = config.stnId;
this.stnDesc = config.stnDesc;
this.stnNpts = config.stnNpts;
this.stnWmoId = config.stnWmoId;
this.stnAlt = config.stnAlt;
this.limit = config.limit;
this.feature_id = config.feature_id;
this.missingVar = config.missingVar;
if (config.parent != null) {
parent = Table.factory(ds, config.parent);
parent.child = this;
}
this.extraJoins = config.extraJoin;
// try to exclude coordinate vars and "structural data" from the list of data variables
addNonDataVariable(config.time);
addNonDataVariable(config.lat);
addNonDataVariable(config.lon);
addNonDataVariable(config.elev);
addNonDataVariable(config.timeNominal);
addNonDataVariable(config.stnId);
addNonDataVariable(config.stnDesc);
addNonDataVariable(config.stnWmoId);
addNonDataVariable(config.stnAlt);
addNonDataVariable(config.stnNpts);
addNonDataVariable(config.limit);
addNonDataVariable(config.feature_id);
addNonDataVariable(config.parentIndex);
addNonDataVariable(config.start);
addNonDataVariable(config.next);
addNonDataVariable(config.numRecords);
}
protected void addNonDataVariable(String name) {
if (name != null)
nondataVars.add(name);
}
// change shape of the data variables
protected void replaceDataVars(StructureMembers sm) {
for (StructureMembers.Member m : sm.getMembers()) {
VariableSimpleIF curr = this.cols.get(m.getName());
this.cols.put(m.getName(), VariableSimpleImpl.changeShape(curr, Dimension.makeDimensionsAnon(m.getShape())));
}
}
/**
* Iterate over the rows of this table. Subclasses must implement this.
*
* @param cursor state of comlpete iteration. Table implementations may not modify.
* @param bufferSize hit on how much memory (in bytes) can be used to buffer.
* @return iterater over the rows of this table.
* @throws IOException on read error
*/
abstract public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException;
String findCoordinateVariableName(CoordName coordName) {
switch (coordName) {
case Elev:
return elev;
case Lat:
return lat;
case Lon:
return lon;
case Time:
return time;
case TimeNominal:
return timeNominal;
case StnId:
return stnId;
case StnDesc:
return stnDesc;
case WmoId:
return stnWmoId;
case StnAlt:
return stnAlt;
case FeatureId:
return feature_id;
case MissingVar:
return missingVar;
}
return null;
}
///////////////////////////////////////////////////////
/**
* A Structure, PsuedoStructure, or Sequence.
*
* Structure: defined by config.structName.
* if config.vars if not null restricts to list of vars, must be members.
*
* PsuedoStructure: defined by variables with outer dimension = config.dim
* So we find all Variables with signature v(outDim, ...) and make them into
*
* Structure {
* v1(...);
* v2(...);
* } s
*
* config.vars if not null restricts to list of vars, must be members.
*/
public static class TableStructure extends Table {
StructureDS struct;
Dimension dim, outer;
TableConfig.StructureType stype;
TableStructure(NetcdfDataset ds, TableConfig config) {
super(ds, config);
this.stype = config.structureType;
switch (config.structureType) {
case Structure:
struct = (StructureDS) ds.findVariable(config.structName);
if (struct == null)
throw new IllegalStateException("Cant find Structure " + config.structName);
dim = struct.getDimension(0);
if (config.vars != null)
struct = (StructureDS) struct.select(config.vars); // limit to list of vars
break;
case PsuedoStructure:
this.dim = ds.findDimension(config.dimName);
assert dim != null;
String name = config.structName == null ? "anon" : config.structName;
struct = new StructurePseudoDS(ds, dim.getGroup(), name, config.vars, this.dim);
break;
case PsuedoStructure2D:
this.dim = ds.findDimension(config.dimName);
this.outer = ds.findDimension(config.outerName);
assert dim != null;
assert config.outerName != null;
struct = new StructurePseudo2Dim(ds, dim.getGroup(), config.structName, config.vars, this.dim, this.outer);
break;
}
config.vars = new ArrayList<>();
for (Variable v : struct.getVariables()) {
// remove substructures
if (v.getDataType() == DataType.STRUCTURE) {
if (config.structureType == TableConfig.StructureType.PsuedoStructure)
struct.removeMemberVariable(v);
} else {
this.cols.put(v.getShortName(), v);
config.vars.add(v.getShortName());
}
}
}
@Override
protected void showTableExtraInfo(String indent, Formatter f) {
f.format("%sstruct=%s, dim=%s type=%s%n", indent, struct.getNameAndDimensions(), dim.getShortName(), struct.getClass().getName());
}
@Override
public VariableDS findVariable(String axisName) {
String structPrefix = struct.getShortName() +".";
if (axisName.startsWith(structPrefix))
axisName = axisName.substring(structPrefix.length());
return (VariableDS) struct.findVariable(axisName);
}
@Override
public String showDimension() {
return dim.getShortName();
}
@Override
public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
return new StructureDataIteratorMediated(struct.getStructureIterator(bufferSize), new RestrictToColumns());
}
@Override
public String getName() {
return stype.toString()+"("+struct.getShortName()+")";
}
}
private class RestrictToColumns implements StructureDataMediator {
StructureMembers members;
@Override
public StructureData modify(StructureData sdata) {
// make members restricted to column names
if (members == null) {
StructureMembers orgMembers = sdata.getStructureMembers();
members = new StructureMembers(orgMembers.getName()+"RestrictToColumns");
for (String colName : cols.keySet()) {
StructureMembers.Member m = orgMembers.findMember(colName);
if (m == null)
throw new IllegalStateException("Cant find "+colName);
members.addMember(m);
}
}
return new StructureDataProxy(members, sdata);
}
}
///////////////////////////////////////////////////////
/**
* ArrayStructure is passed in config.as
* Used by
* UnidataPointFeature: type StationProfile (deprecated)
*/
public static class TableArrayStructure extends Table {
ArrayStructure as;
Dimension dim;
TableArrayStructure(NetcdfDataset ds, TableConfig config) {
super(ds, config);
assert (config.as != null);
this.as = config.as;
this.dim = new Dimension(config.structName, (int) config.as.getSize(), false);
for (StructureMembers.Member m : config.as.getStructureMembers().getMembers())
cols.put(m.getName(), new VariableSimpleAdapter(m));
}
@Override
protected void showTableExtraInfo(String indent, Formatter f) {
f.format("%sArrayStruct=%s, dim=%s%n", indent, new Section(as.getShape()), dim.getShortName());
}
@Override
public String showDimension() {
return dim.getShortName();
}
public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
return as.getStructureDataIterator();
}
@Override
public String getName() {
return "ArrayStructure("+name+")";
}
}
///////////////////////////////////////////////////////
/**
* When theres no seperate station table, but info is duplicated in the obs structure.
* Must have a ParentId child table
* No variables are added to cols.
*
* Used by:
* BufrCdm StationProfile type
*/
public static class TableConstruct extends Table {
ArrayStructure as; // injected by TableParentId
TableConstruct(NetcdfDataset ds, TableConfig config) {
super(ds, config);
}
@Override
protected void showTableExtraInfo(String indent, Formatter f) {
}
@Override
public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
return as.getStructureDataIterator();
}
@Override
public String getName() {
return "Constructed";
}
}
///////////////////////////////////////////////////////
/**
* Contiguous children, using start and numRecords variables in the parent. This assumes column store.
* TableContiguous is the children, config.struct describes the cols.
*
* Used by:
* UnidataPointObs
* CFPointObs
*/
public static class TableContiguous extends TableStructure {
private String startVarName; // variable name holding the starting index in parent
private String numRecordsVarName; // variable name holding the number of children in parent
private int[] startIndex, numRecords;
private NetcdfDataset ds;
private boolean isInit;
TableContiguous(NetcdfDataset ds, TableConfig config) {
super(ds, config);
this.ds = ds;
startVarName = config.getStart();
numRecordsVarName = config.getNumRecords();
addNonDataVariable(startVarName);
addNonDataVariable(numRecordsVarName);
}
private void init() {
if (startVarName == null) { // read numRecords when startVar is not known LOOK this should be deffered
try {
Variable v = ds.findVariable(numRecordsVarName);
Array numRecords = v.read();
int n = (int) numRecords.getSize();
// construct the start variable
this.numRecords = new int[n];
this.startIndex = new int[n];
int i = 0;
int count = 0;
while (numRecords.hasNext()) {
this.startIndex[i] = count;
this.numRecords[i] = numRecords.nextInt();
count += this.numRecords[i];
i++;
}
isInit = true;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
protected void showTableExtraInfo(String indent, Formatter f) {
f.format("%sstart=%s, numRecords=%s%n", indent, startVarName, numRecordsVarName);
}
public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
if (!isInit) init();
int firstRecno, numrecs;
StructureData parentStruct = cursor.getParentStructure();
if (startIndex != null) {
int parentIndex = cursor.getParentRecnum();
firstRecno = startIndex[parentIndex];
numrecs = numRecords[parentIndex];
} else {
firstRecno = parentStruct.getScalarInt(startVarName);
numrecs = parentStruct.getScalarInt(numRecordsVarName);
}
return new StructureDataIteratorLinked(struct, firstRecno, numrecs, null);
}
@Override
public String getName() {
return "Contig("+numRecordsVarName+")";
}
}
///////////////////////////////////////////////////////
/**
* The children have a field containing the index of the parent.
* For efficiency, we scan this data and construct an IndexMap( parentIndex -> list of children),
* i.e. we compute the inverse link, parent -> children.
* TableParentIndex is the children, config.struct describes the cols.
*
* Used by:
* CFPointObs
*/
public static class TableParentIndex extends TableStructure {
private Map> indexMap;
private String parentIndexName;
TableParentIndex(NetcdfDataset ds, TableConfig config) {
super(ds, config);
this.parentIndexName = config.parentIndex;
// construct the map
try {
Variable rpIndex = ds.findVariable(config.parentIndex);
Array index = rpIndex.read();
int childIndex = 0;
this.indexMap = new HashMap<>((int) (2 * index.getSize()));
while (index.hasNext()) {
int parent = index.nextInt();
List list = indexMap.get(parent);
if (list == null) {
list = new ArrayList<>();
indexMap.put(parent, list);
}
list.add(childIndex);
childIndex++;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
addNonDataVariable(config.parentIndex);
}
@Override
protected void showTableExtraInfo(String indent, Formatter f) {
f.format("%sparentIndexName=%s, indexMap.size=%d%n", indent, parentIndexName, indexMap.size());
}
public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
int parentIndex = cursor.getParentRecnum();
List index = indexMap.get(parentIndex);
if (index == null) index = new ArrayList<>();
return new StructureDataIteratorIndexed(struct, index);
}
@Override
public String getName() {
return "Indexed("+parentIndexName+")";
}
}
///////////////////////////////////////////////////////
/**
* The children have a field containing the id of the parent.
* For efficiency, we scan this data and construct an IndexMap( parentIndex -> list of children),
* i.e. we compute the inverse link, parent -> children.
* TableParentIndex is the children, config.struct describes the cols.
*
* Used by:
* CFPointObs
*/
public static class TableParentId extends TableStructure {
private ParentInfo[] indexMap;
private String parentIdName;
TableParentId(NetcdfDataset ds, TableConfig config) {
super(ds, config);
this.parentIdName = config.parentIndex;
// construct the hash of unique parents, based on the id variable
Map
© 2015 - 2024 Weber Informatics LLC | Privacy Policy