cdm/src/main/java/ucar/nc2/ft/point/standard/plug/CFpointObs.java
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));
          profileTable.time = time.getFullName();
        }

        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));
          zTable.elev = z.getFullName();
        }
        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.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 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));
          profileTable.time = time.getFullName();
        }

        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));
          zTable.elev = z.getFullName();
        }
        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.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 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 ) ) ; profileTable . time = time . getFullName ( ) ; } 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 ) ) ; zTable . elev = z . getFullName ( ) ; } 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 . 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 ; }
//
//