cdm/src/main/java/ucar/nc2/ft/point/standard/plug/CFpointObs.java
protected boolean identifyDoubleRaggeds(NetcdfDataset ds, EncodingInfo info, Formatter errlog) {
    // the timeseries are stored as ragged index
    Evaluator.VarAtt varatt = Evaluator.findVariableWithAttribute(ds, CF.INSTANCE_DIMENSION);
    if (varatt == null) varatt = Evaluator.findVariableWithAttribute(ds, CF.RAGGED_PARENTINDEX);
    if (varatt == null) return false;

    Variable ragged_parentIndex = varatt.var;
    String instanceDimName = varatt.att.getStringValue();
    Dimension stationDim = ds.findDimension(instanceDimName);

    if (stationDim == null) {
      errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable has illegal value for %s = %s%n", CF.INSTANCE_DIMENSION, instanceDimName);
      return false;
    }

    if (ragged_parentIndex.getDataType() != DataType.INT) {
      errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable must be of type integer%n");
      return false;
    }

    if (ragged_parentIndex.getRank() != 1 && info.childStruct == null) {
      errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable %s must be 1D %n", ragged_parentIndex);
      return false;
    }
    Dimension profileDim = (info.childDim != null) ? info.childDim : ragged_parentIndex.getDimension(0);

    // onto the profiles, stored contiguously
    varatt = Evaluator.findVariableWithAttribute(ds, CF.SAMPLE_DIMENSION);
    if (varatt == null) varatt = Evaluator.findVariableWithAttribute(ds, CF.RAGGED_ROWSIZE);
    if (varatt == null) return false;

    Variable ragged_rowSize = varatt.var;
    String obsDimName = varatt.att.getStringValue();
    Dimension obsDim = ds.findDimension(obsDimName);

    if (obsDimName == null) {
      errlog.format("CFpointObs: Contiguous ragged array representation: parent_index variable has illegal value for %s = %s%n", CF.SAMPLE_DIMENSION, obsDimName);
      return false;
    }

    if (!obsDimName.equals(info.grandChildDim.getShortName())) {
      errlog.format("CFpointObs: Contiguous ragged array representation: row_size variable has obs dimension %s must be %s%n", obsDimName, info.childDim);
      return false;
    }

    if (ragged_rowSize.getDataType() != DataType.INT) {
      errlog.format("CFpointObs: Contiguous ragged array representation: row_size variable must be of type integer%n");
      return false;
    }

    if (info.childDim == null) {  // nc4 ext
      Dimension profileDim2 = ragged_rowSize.getDimension(0);
      if (profileDim2 != profileDim) {
        errlog.format("CFpointObs: Double ragged array representation dimensions do not agree: %s != %s%n", profileDim2.getShortName(), profileDim.getShortName());
        return false;
      }
    }

    info.set(Encoding.raggedIndex, stationDim, profileDim, obsDim);
    info.ragged_parentIndex = ragged_parentIndex;
    info.ragged_rowSize = ragged_rowSize;
    return true;
  }
protected boolean identifyDoubleRaggeds(NetcdfDataset ds, EncodingInfo info, Formatter errlog) {
    // the timeseries are stored as ragged index
    Evaluator.VarAtt varatt = Evaluator.findVariableWithAttribute(ds, CF.INSTANCE_DIMENSION);
    if (varatt == null) varatt = Evaluator.findVariableWithAttribute(ds, CF.RAGGED_PARENTINDEX);
    if (varatt == null) return false;

    Variable ragged_parentIndex = varatt.var;
    String instanceDimName = varatt.att.getStringValue();
    Dimension stationDim = ds.findDimension(instanceDimName);

    if (stationDim == null) {
      errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable has illegal value for %s = %s%n", CF.INSTANCE_DIMENSION, instanceDimName);
      return false;
    }

    if (ragged_parentIndex.getDataType() != DataType.INT) {
      errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable must be of type integer%n");
      return false;
    }

    if (ragged_parentIndex.getRank() != 1 && info.childStruct == null) {
      errlog.format("CFpointObs: Indexed ragged array representation: parent_index variable %s must be 1D %n", ragged_parentIndex);
      return false;
    }
    Dimension profileDim = (info.childDim != null) ? info.childDim : ragged_parentIndex.getDimension(0);

    // onto the profiles, stored contiguously
    varatt = Evaluator.findVariableWithAttribute(ds, CF.SAMPLE_DIMENSION);
    if (varatt == null) varatt = Evaluator.findVariableWithAttribute(ds, CF.RAGGED_ROWSIZE);
    if (varatt == null) return false;

    Variable ragged_rowSize = varatt.var;
    String obsDimName = varatt.att.getStringValue();
    Dimension obsDim = ds.findDimension(obsDimName);

    if (obsDimName == null) {
      errlog.format("CFpointObs: Contiguous ragged array representation: parent_index variable has illegal value for %s = %s%n", CF.SAMPLE_DIMENSION, obsDimName);
      return false;
    }

    if (!obsDimName.equals(info.grandChildDim.getShortName())) {
      errlog.format("CFpointObs: Contiguous ragged array representation: row_size variable has obs dimension %s must be %s%n", obsDimName, info.childDim);
      return false;
    }

    if (ragged_rowSize.getDataType() != DataType.INT) {
      errlog.format("CFpointObs: Contiguous ragged array representation: row_size variable must be of type integer%n");
      return false;
    }

    if (info.childDim == null) {  // nc4 ext
      Dimension profileDim2 = ragged_rowSize.getDimension(0);
      if (profileDim2 != profileDim) {
        errlog.format("CFpointObs: Double ragged array representation dimensions do not agree: %s != %s%n", profileDim2.getShortName(), profileDim.getShortName());
        return false;
      }
    }

    info.set(Encoding.raggedIndex, stationDim, profileDim, obsDim);
    info.ragged_parentIndex = ragged_parentIndex;
    info.ragged_rowSize = ragged_rowSize;
    return true;
  }
Identify ragged array representations for double nests (timeSeries profile, timeSeries trajectory)
<p/>
This uses the contiguous ragged array representation for each profile (9.5.43.3), and the indexed ragged array
representation to organise the profiles into time series (9.3.54). The canonical use case is when writing real-time
data streams that contain profiles from many stations, arriving randomly, with the data for each entire profile written all at once.

@param ds          in this dataset
@param info        put info here
@param errlog      error go here
@return EncodingInfo if ragged array representations is found