Package ucar.nc2.ft.point.standard

Source Code of ucar.nc2.ft.point.standard.Table$TableStructure

/*
* Copyright 1998-2009 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<Join> extraJoins;

  String lat, lon, elev, time, timeNominal;
  String stnId, stnDesc, stnNpts, stnWmoId, stnAlt, limit;
  String feature_id, missingVar;

  List<VariableSimpleIF> cols = new ArrayList<VariableSimpleIF>();    // all variables
  List<String> nondataVars = new ArrayList<String>(); // 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
    /* checkNonDataVariable(config.lat);
    checkNonDataVariable(config.lon);
    checkNonDataVariable(config.elev);
    checkNonDataVariable(config.timeNominal);
    checkNonDataVariable(config.stnId);
    checkNonDataVariable(config.stnDesc);
    checkNonDataVariable(config.stnWmoId);
    checkNonDataVariable(config.stnAlt); */
    checkNonDataVariable(config.stnNpts);
    checkNonDataVariable(config.limit);
  }

  protected void checkNonDataVariable(String name) {
    if (name != null)
      nondataVars.add(name);
  }

  /**
   * 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.
   * <p/>
   * Structure: defined by config.structName.
   * if config.vars if not null restricts to list of vars, must be members.
   * <p/>
   * PsuedoStructure: defined by variables with outer dimension = config.dim
   * So we find all Variables with signature v(outDim, ...) and make them into
   * <pre>
   * Structure {
   *   v1(...);
   *   v2(...);
   * } s
   * </pre>
   * 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<String>();
      for (Variable v : struct.getVariables()) {
        // remove substructures
        if (v.getDataType() == DataType.STRUCTURE) {
          if (config.structureType == TableConfig.StructureType.PsuedoStructure)
            struct.removeMemberVariable(v);
        } else {
          this.cols.add(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.getName(), struct.getClass().getName());
    }

    @Override
    public VariableDS findVariable(String axisName) {
      return (VariableDS) struct.findVariable(axisName);
    }

    @Override
    public String showDimension() {
      return dim.getName();
    }

    public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
      return struct.getStructureIterator(bufferSize);
    }

    @Override
    public String getName() {
      return stype.toString()+"("+struct.getShortName()+")";
    }
  }

  ///////////////////////////////////////////////////////

  /**
   * 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);
      this.as = config.as;
      this.dim = new Dimension(config.structName, (int) config.as.getSize(), false);
      assert (this.as != null);

      for (StructureMembers.Member m : config.as.getStructureMembers().getMembers())
        cols.add(new VariableSimpleAdapter(m));
    }

    @Override
    protected void showTableExtraInfo(String indent, Formatter f) {
      f.format("%sArrayStruct=%s, dim=%s%n", indent, new Section(as.getShape()), dim.getName());
    }

    @Override
    public String showDimension() {
      return dim.getName();
    }

    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.
   * <p/>
   * 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.
   * TableContiguous is the children, config.struct describes the cols.
   * <p/>
   * 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;

    TableContiguous(NetcdfDataset ds, TableConfig config) {
      super(ds, config);
      this.startVarName = config.start;
      this.numRecordsVarName = config.numRecords;

      if (startVarName == null) {  // read numRecords when startVar is not known
        try {
          Variable v = ds.findVariable(config.numRecords);
          Array numRecords = v.read();
          int n = (int) v.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++;
          }
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      }

      checkNonDataVariable(config.start);
      checkNonDataVariable(config.numRecords);
    }

    @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 {
      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.
   * <p/>
   * Used by:
   * CFPointObs
   */
  public static class TableParentIndex extends TableStructure {
    private Map<Integer, List<Integer>> 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<Integer, List<Integer>>((int) (2 * index.getSize()));
        while (index.hasNext()) {
          int parent = index.nextInt();
          List<Integer> list = indexMap.get(parent);
          if (list == null) {
            list = new ArrayList<Integer>();
            indexMap.put(parent, list);
          }
          list.add(childIndex);
          childIndex++;
        }
      } catch (IOException e) {
        throw new RuntimeException(e);
      }

      checkNonDataVariable(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<Integer> index = indexMap.get(parentIndex);
      if (index == null) index = new ArrayList<Integer>();
      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.
   * <p/>
   * 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<Object, ParentInfo> parentHash;
      try {
        Variable rpIndex = ds.findVariable(parentIdName);
        if (rpIndex == null)
          rpIndex = struct.findVariable(parentIdName);

        Array index = rpIndex.read();
        if (index instanceof ArrayChar)
          index = ((ArrayChar)index).make1DStringArray();

        parentHash = new HashMap<Object, ParentInfo>((int) (2 * index.getSize()));

        int childIndex = 0;
        while (index.hasNext()) {
          Object parent = index.next();
          ParentInfo info = parentHash.get(parent);
          if (info == null) {
            info = new ParentInfo();
            parentHash.put(parent, info);
          }
          info.add(childIndex);
          childIndex++;
        }
      } catch (IOException e) {
        throw new RuntimeException(e);
      }

      // construct the indexMap and the ArrayStructure containing StructureData for the parents
      Collection<ParentInfo> parents = parentHash.values();
      int n = parents.size();
      this.indexMap = new ParentInfo[n];
      StructureData[] parentData = new StructureData[n];
      int count = 0;
      for (ParentInfo info : parents) {
        this.indexMap[count] = info;
        parentData[count++] = info.sdata;
      }
      ArrayStructure as = new ArrayStructureW(struct.makeStructureMembers(), new int[] {n}, parentData);

      // find the parent TableConstruct and inject the ArrayStructure
      Table t = this;
      while (t.parent != null) {
        t = t.parent;
        if (t instanceof TableConstruct) {
          ((TableConstruct) t).as = as;
          break;
        }
      }
      checkNonDataVariable(parentIdName);
    }

    private class ParentInfo {
      List<Integer> recnumList = new ArrayList<Integer>();
      StructureData sdata;

      void add(int recnum) throws IOException {
        recnumList.add(recnum);
        if (sdata != null) return;
        try {
          sdata = struct.readStructure( recnum);
        } catch (ucar.ma2.InvalidRangeException e) {
          log.error("TableParentId read recno=" + recnum, e);
          throw new RuntimeException(e.getMessage());
        }
      }
    }

    @Override
    protected void showTableExtraInfo(String indent, Formatter f) {
      f.format("%sparentIdName=%s, indexMap.size=%d%n", indent, parentIdName, indexMap.length);
    }

    public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
      int parentIndex = cursor.getParentRecnum();
      ParentInfo info = indexMap[parentIndex];
      List<Integer> index = (info == null) ? new ArrayList<Integer>() : info.recnumList;
      return new StructureDataIteratorIndexed(struct, index);
    }

    @Override
    public String getName() {
      return "ParentId("+parentIdName+")";
    }
  }

  ///////////////////////////////////////////////////////

  /**
   * Linked list of children, using start variable in the parent, and next in the child.
   * TableLinkedList is the children, config.struct describes the cols.
   * <p/>
   * Used by:
   * UnidataPointObs
   */
  public static class TableLinkedList extends TableStructure {
    private String start; // variable name holding the starting index in parent
    private String next; // variable name holding the next index in child

    TableLinkedList(NetcdfDataset ds, TableConfig config) {
      super(ds, config);
      this.start = config.start;
      this.next = config.next;

      checkNonDataVariable(config.start);
      checkNonDataVariable(config.next);
    }

    public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
      StructureData parentStruct = cursor.getParentStructure();
      int firstRecno = parentStruct.getScalarInt(start);
      return new StructureDataIteratorLinked(struct, firstRecno, -1, next);
    }

        @Override
    public String getName() {
      return "Linked("+start+"->"+next+")";
    }
  }

  ///////////////////////////////////////////////////////

  // the inner struct of a 2D multdim(outer, inner) with unlimited dimension
  public static class TableMultidimInner extends Table {
     StructureMembers sm; // the inner structure members
     Dimension inner, outer;
     NetcdfDataset ds;

     TableMultidimInner(NetcdfDataset ds, TableConfig config) {
       super(ds, config);
       this.ds = ds;
       assert config.outerName != null;
       assert config.innerName != null;
       this.inner = ds.findDimension(config.innerName);
       this.outer = ds.findDimension(config.outerName);
       assert this.inner != null : config.innerName;
       assert this.outer != null : config.outerName;

       sm = new StructureMembers(config.name);
       if (config.vars != null) {
         for (String name : config.vars) {
           Variable v = ds.findVariable(name);
           if (v == null) continue;
           cols.add(v);
           int rank = v.getRank();
           int[] shape = new int[rank - 2];
           System.arraycopy(v.getShape(), 2, shape, 0, rank - 2);
           sm.addMember(v.getShortName(), v.getDescription(), v.getUnitsString(), v.getDataType(), shape);
         }

       } else {
         for (Variable v : ds.getVariables()) {
           if (v.getRank() < 2) continue;
           if (v.getDimension(0).equals(this.outer) && v.getDimension(1).equals(this.inner)) {
             cols.add(v);
             int rank = v.getRank();
             int[] shape = new int[rank - 2];
             System.arraycopy(v.getShape(), 2, shape, 0, rank - 2);
             sm.addMember(v.getShortName(), v.getDescription(), v.getUnitsString(), v.getDataType(), shape);
           }
         }
       }
     }

     @Override
     protected void showTableExtraInfo(String indent, Formatter f) {
       f.format("%sStructureMembers=%s, dim=%s,%s%n", indent, sm.getName(), outer.getName(), inner.getName());
     }

     @Override
     public String showDimension() {
       return inner.getName();
     }

     @Override
     public VariableDS findVariable(String axisName) {
       return (VariableDS) ds.findVariable(axisName);
     }

     public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
       StructureData parentStruct = cursor.getParentStructure();
       ArrayStructureMA asma = new ArrayStructureMA(sm, new int[]{inner.getLength()});
       for (VariableSimpleIF v : cols) {
         Array data = parentStruct.getArray(v.getShortName());
         StructureMembers.Member childm = sm.findMember(v.getShortName());
         childm.setDataArray(data);
       }
       return asma.getStructureDataIterator();
     }

      @Override
      public String getName() {
        return "Multidim(" + outer.getName()+"," + inner.getName() + ")";
      }
   }

  public static class TableMultidimInner3D extends Table {
     StructureMembers sm; // the inner structure members
     Dimension dim, inner, middle;
     NetcdfDataset ds;

     TableMultidimInner3D(NetcdfDataset ds, TableConfig config) {
       super(ds, config);
       this.ds = ds;
       assert config.dimName != null;
       assert config.outerName != null;
       assert config.innerName != null;
       this.dim = ds.findDimension(config.dimName);
       this.inner = ds.findDimension(config.innerName);
       this.middle = ds.findDimension(config.outerName);

       sm = new StructureMembers(config.name);
       if (config.vars != null) {
         for (String name : config.vars) {
           Variable v = ds.findVariable(name);
           if (v == null) continue;
           cols.add(v);
           int rank = v.getRank();
           int[] shape = new int[rank - 3];
           System.arraycopy(v.getShape(), 3, shape, 0, rank - 3);
           sm.addMember(v.getShortName(), v.getDescription(), v.getUnitsString(), v.getDataType(), shape);
         }

       } else {
         for (Variable v : ds.getVariables()) {
           if (v.getRank() < 3) continue;
           if (v.getDimension(0).equals(dim) && v.getDimension(1).equals(middle&& v.getDimension(2).equals(inner )) {
             cols.add(v);
             int rank = v.getRank();
             int[] shape = new int[rank - 3];
             System.arraycopy(v.getShape(), 3, shape, 0, rank - 3);
             sm.addMember(v.getShortName(), v.getDescription(), v.getUnitsString(), v.getDataType(), shape);
           }
         }
       }
     }

     @Override
     protected void showTableExtraInfo(String indent, Formatter f) {
       f.format("%sStructureMembers=%s, dim=%s%n", indent, sm.getName(), dim.getName());
     }

     @Override
     public String showDimension() {
       return dim.getName();
     }

     @Override
     public VariableDS findVariable(String axisName) {
       return (VariableDS) ds.findVariable(axisName);
     }

     public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
       StructureData parentStruct = cursor.tableData[2];
       int middleIndex = cursor.recnum[1];
       ArrayStructureMA asma = new ArrayStructureMA(sm, new int[]{inner.getLength()});
       for (VariableSimpleIF v : cols) {
         Array data = parentStruct.getArray(v.getShortName());
         Array myData = data.slice(0, middleIndex);
         StructureMembers.Member childm = sm.findMember(v.getShortName());
         childm.setDataArray (myData.copy()); // must make copy - ARrayStucture doesnt deal with logical views
       }
       return asma.getStructureDataIterator();
     }

      @Override
      public String getName() {
        return "Multidim(" + dim.getName()+"," + middle.getName() +"," + inner.getName() + ")";
      }

   }

   /**
   * Used for PsuedoStructure(station, time).
   * This is used for the inner table.
   * Need: config.inner, config.outer = config.dim, config.vars
   * <p/>
   * Used by:
   * CFpointObs
   */
  public static class TableMultidimInnerPsuedo extends Table.TableStructure {
    Dimension inner, outer;
    StructureMembers sm;

    TableMultidimInnerPsuedo(NetcdfDataset ds, TableConfig config) {
      super(ds, config);
      assert config.outerName != null;
      assert config.innerName != null;
      this.inner = ds.findDimension(config.innerName);
      this.outer = ds.findDimension(config.outerName);

      sm = new StructureMembers(config.name);
      for (Variable v : struct.getVariables()) {
        int rank = v.getRank();
        int[] shape = new int[rank - 1];
        System.arraycopy(v.getShape(), 1, shape, 0, rank - 1);
        sm.addMember(v.getShortName(), v.getDescription(), v.getUnitsString(), v.getDataType(), shape);
      }
    }

    public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
      int recnum = cursor.getParentRecnum();
      try {
        StructureData parentStruct = struct.readStructure(recnum);
        ArrayStructureMA asma = new ArrayStructureMA(sm, new int[]{inner.getLength()});
        for (VariableSimpleIF v : cols) {
          Array data = parentStruct.getArray(v.getShortName());
          StructureMembers.Member childm = sm.findMember(v.getShortName());
          childm.setDataArray(data);
        }
        return asma.getStructureDataIterator();

      } catch (InvalidRangeException e) {
        throw new IllegalStateException(e);
      }
    }

           @Override
      public String getName() {
        return "MultidimPseudo(" + outer.getName()+"," + inner.getName() + ")";
      }

  }

  public static class TableMultidimInnerPsuedo3D extends Table.TableStructure {
    Dimension middle;
    Dimension inner;
    StructureMembers sm;

    TableMultidimInnerPsuedo3D(NetcdfDataset ds, TableConfig config) {
      super(ds, config);
      assert config.dimName != null;
      assert config.outerName != null; // middle
      assert config.innerName != null;
      this.dim = ds.findDimension(config.dimName);
      this.middle = ds.findDimension(config.outerName);
      this.inner = ds.findDimension(config.innerName);

      sm = new StructureMembers(config.name);
      for (Variable v : struct.getVariables()) {
        int rank = v.getRank();
        int[] shape = new int[rank - 1];
        System.arraycopy(v.getShape(), 1, shape, 0, rank - 1);
        sm.addMember(v.getShortName(), v.getDescription(), v.getUnitsString(), v.getDataType(), shape);
      }
    }

    public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
      int outerIndex = cursor.recnum[2];
      int middleIndex = cursor.recnum[1];
      try {
        Section s = new Section().appendRange(outerIndex,outerIndex).appendRange(middleIndex,middleIndex);
        ArrayStructure result = (ArrayStructure) struct.read(s);
        assert result.getSize() == 1;
        StructureData sdata = result.getStructureData(0); // should only be one
        ArrayStructureMA asma = new ArrayStructureMA(sm, new int[]{inner.getLength()});
        for (VariableSimpleIF v : cols) {
          Array data = sdata.getArray(v.getShortName());
          StructureMembers.Member childm = sm.findMember(v.getShortName());
          childm.setDataArray(data);
        }
        return asma.getStructureDataIterator();

      } catch (InvalidRangeException e) {
        throw new IllegalStateException(e);
      }
    }

      @Override
      public String getName() {
        return "MultidimPsuedo(" + dim.getName()+"," + middle.getName() +"," + inner.getName() + ")";
      }

  }

  ///////////////////////////////////////////////////////

  /**
   * Used for Structure(station, time).
   * This is used for the inner table, where the station index gets set, and all the structures for that
   * styation are read in at once. Then we just iterate over that ArrayStructure.
   * <p/>
   * Used by:
   * GempakCdm
   */
  public static class TableMultidimStructure extends Table.TableStructure {

    TableMultidimStructure(NetcdfDataset ds, TableConfig config) {
      super(ds, config);
    }

    public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
      int recnum = cursor.getParentRecnum();
      try {
        Section section = new Section().appendRange(recnum, recnum);
        int count = 1;
        while (count++ < struct.getRank()) // handles multidim case
          section.appendRange(null);
        ArrayStructure data = (ArrayStructure) struct.read(section); // read all the data for a fixed outer index
        return data.getStructureDataIterator();
      } catch (InvalidRangeException e) {
        throw new IllegalStateException(e);
      }
    }

    @Override
    public String getName() {
      return "MultidimStructure(" + struct.getFullName() + ")";
    }

  }


  ///////////////////////////////////////////////////////

  /**
   * A Structure inside of a parent Structure.
   * Name of child member inside parent Structure is config.nestedTableName
    obsTable.structName = obsStruct.getName();
    obsTable.nestedTableName = obsStruct.getShortName();
   * <p/>
   * Used by:
   * BufrCdm
   */
  public static class TableNestedStructure extends Table {
    String nestedTableName; // short name of structure
    Structure struct;

    TableNestedStructure(NetcdfDataset ds, TableConfig config) {
      super(ds, config);
      this.nestedTableName = config.nestedTableName;
      struct = (Structure) ds.findVariable(config.structName);
      assert (struct != null) : config.structName;

      for (Variable v : struct.getVariables())
        cols.add(v);
    }

    @Override
    protected void showTableExtraInfo(String indent, Formatter f) {
      f.format("%sstruct=%s, nestedTableName=%s%n", indent, struct.getNameAndDimensions(), nestedTableName);
    }

    public VariableDS findVariable(String axisName) {
      return (VariableDS) struct.findVariable(axisName);
    }

    public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
      StructureData parentStruct = cursor.getParentStructure();

      StructureMembers members = parentStruct.getStructureMembers();
      StructureMembers.Member m = members.findMember(nestedTableName);
      members.hideMember(m); // LOOK ??
      if (m.getDataType() == DataType.SEQUENCE) {
        ArraySequence seq = parentStruct.getArraySequence(m);
        return seq.getStructureDataIterator();

      } else if (m.getDataType() == DataType.STRUCTURE) {
        ArrayStructure as = parentStruct.getArrayStructure(m);
        return as.getStructureDataIterator();
      }

      throw new IllegalStateException("Cant find nested table member = " + nestedTableName);
    }

        @Override
    public String getName() {
      return "NestedStructure(" + nestedTableName + ")";
    }
  }

  ///////////////////////////////////////////////////////

  /**
   * Table is a single StructureData, passed in as config.sdata.
   * Ok for sdata to be null
   * <p/>
   * Used by:
   * FslWindProfiler
   */
  public static class TableSingleton extends Table {
    StructureData sdata;

    TableSingleton(NetcdfDataset ds, TableConfig config) {
      super(ds, config);
      this.sdata = config.sdata;
      if (sdata == null) return;

      for (StructureMembers.Member m : sdata.getStructureMembers().getMembers())
        cols.add(new VariableSimpleAdapter(m));
    }

    @Override
    protected void showTableExtraInfo(String indent, Formatter f) {
      f.format("%sStructureData=%s%n", indent, sdata);
    }

    public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
      return new SingletonStructureDataIterator(sdata);
    }

    @Override
    public String getName() {
      return "Singleton";
    }
  }

  /**
   * Table is a single StructureData, which is empty.
   * NestedTable looks for instance of this, and
   * 1) increments the nesting level
   * 2) looks for coordinat variables at the top level.
   * <p/>
   * Essentialy adds a table at top of the tree, constisting only of coordinate variables
   * <p/>
   * Used by:
   * CFpointObs
   * GempakCdm
   * Ndbc
   */
  public static class TableTop extends Table {
    NetcdfDataset ds;

    TableTop(NetcdfDataset ds, TableConfig config) {
      super(ds, config);
      this.ds = ds;
    }

    @Override
    protected void showTableExtraInfo(String indent, Formatter f) {
    }

    public StructureDataIterator getStructureDataIterator(Cursor cursor, int bufferSize) throws IOException {
      return new SingletonStructureDataIterator(null);
    }

        @Override
    public String getName() {
      return "TopScalars";
    }
  }

  // ok for sdata to be null
  private static class SingletonStructureDataIterator implements StructureDataIterator {
    private int count = 0;
    private StructureData sdata;

    SingletonStructureDataIterator(StructureData sdata) {
      this.sdata = sdata;
    }

    @Override
    public boolean hasNext() throws IOException {
      return (count == 0);
    }

    @Override
    public StructureData next() throws IOException {
      count++;
      return sdata;
    }

    @Override
    public void setBufferSize(int bytes) {
    }

    @Override
    public StructureDataIterator reset() {
      count = 0;
      return this;
    }


    @Override
    public int getCurrentRecno() {
      return count - 1;
    }
  }

  ////////////////////////////////////////////////////////////////

  public String getName() {
    return name;
  }

  public FeatureType getFeatureType() {
    return featureType;
  }

  /* public List<? super VariableSimpleIF> getDataVariables() {
    return cols;
  } */

  // LOOK others should override
  public VariableDS findVariable(String axisName) {
    return null;
  }

  public String showDimension() {
    return "";
  }

  public String toString() {
    Formatter formatter = new Formatter();
    formatter.format(" Table %s on dimension %s type=%s\n", getName(), showDimension(), getClass().toString());
    formatter.format("  Coordinates=");
    formatter.format("\n  Data Variables= %d\n", cols.size());
    formatter.format("  Parent= %s\n", ((parent == null) ? "none" : parent.getName()));
    return formatter.toString();
  }

  public String showAll() {
    StringBuilder sbuff = new StringBuilder();
    sbuff.append("Table on dimension ").append(showDimension()).append("\n");
    for (VariableSimpleIF v : cols) {
      sbuff.append("  ").append(v.getShortName()).append("\n");
    }
    return sbuff.toString();
  }

  public int show(Formatter f, int indent) {
    if (parent != null)
      indent = parent.show(f, indent);

    String s = indent(indent);
    String ftDesc = (featureType == null) ? "" : "featureType=" + featureType.toString();
    f.format("%n%sTable %s: type=%s %s%n", s, getName(), getClass().toString(), ftDesc);
    if (extraJoins != null) {
      f.format("  %sExtraJoins:\n", s);
      for (Join j : extraJoins)
        f.format("   %s  %s \n", s, j);
    }
    showTableExtraInfo(indent(indent + 2), f);
    showCoords(s, f);
    f.format("  %sVariables:\n", s);
    for (VariableSimpleIF v : cols) {
      f.format("   %s  %s %s\n", s, v.getShortName(), getKind(v.getShortName()));
    }
    return indent + 2;
  }

  String indent(int n) {
    StringBuilder sbuff = new StringBuilder();
    for (int i = 0; i < n; i++) sbuff.append(' ');
    return sbuff.toString();
  }

  protected abstract void showTableExtraInfo(String indent, Formatter f);

  String getKind(String v) {
    if (v.equals(lat)) return "[Lat]";
    if (v.equals(lon)) return "[Lon]";
    if (v.equals(elev)) return "[Elev]";
    if (v.equals(time)) return "[Time]";
    if (v.equals(timeNominal)) return "[timeNominal]";
    if (v.equals(stnId)) return "[stnId]";
    if (v.equals(stnDesc)) return "[stnDesc]";
    if (v.equals(stnNpts)) return "[stnNpts]";
    if (v.equals(stnWmoId)) return "[stnWmoId]";
    if (v.equals(stnAlt)) return "[stnAlt]";
    if (v.equals(limit)) return "[limit]";

    return "";
  }

  private void showCoords(String indent, Formatter out) {
    boolean gotSome = false;
    for (CoordName coord : CoordName.values()) {
      String varName = findCoordinateVariableName(coord);
      if (varName != null) {
        gotSome = true;
        out.format(" %s Coord %s [%s]\n", indent, varName, coord);
      }
    }
    if (gotSome) out.format("\n");
  }

}
TOP

Related Classes of ucar.nc2.ft.point.standard.Table$TableStructure

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.