public void layoutContainer(Container target) {
      synchronized (target.getTreeLock()) {
        if (debug) System.out.println(name+ " layoutContainer ");

        // first layout any nested LayoutM components
        // it seems that generally Swing laysout from outer to inner ???
        int n = target.getComponentCount();
        for (int i=0 ; i<n ; i++) {
          Component comp = target.getComponent(i);
          if (comp instanceof Container) {
            Container c = (Container) comp;
            LayoutManager m = c.getLayout();
            if (m instanceof LayoutM)
              m.layoutContainer( c);
          }
        }

        // now layout this container
        reset( target);
        globalBounds = new Rectangle(0,0,0,0);
        while ( !layoutPass( target))
          target.setPreferredSize( globalBounds.getSize()); // ??
      }
    }

Lays out the specified container.
@param target the container to be laid out


public static boolean isRadialCoordSys( Formatter parseInfo, CoordinateSystem cs) {
    return (cs.getAzimuthAxis() != null) && (cs.getRadialAxis() != null) && (cs.getElevationAxis() != null);
  }

public static boolean isRadialCoordSys ( Formatter parseInfo , CoordinateSystem cs ) { return ( cs . getAzimuthAxis ( ) != null ) && ( cs . getRadialAxis ( ) != null ) && ( cs . getElevationAxis ( ) != null ) ; }

Determine if this CoordinateSystem can be made into a RadialCoordSys.
@param parseInfo put debug information into this Formatter; may be null.
@param cs the CoordinateSystem to test
@return true if it can be made into a RadialCoordSys.

Determine if this CoordinateSystem can be made into a RadialCoordSys .


public double getMaximumRadial() {
    if (maxRadial == 0.0) {
      try {
        Array radialData = getRadialAxisDataCached();
        maxRadial = MAMath.getMaximum( radialData);

        String units = getRadialAxis().getUnitsString();
        SimpleUnit radialUnit = SimpleUnit.factory(units);
        maxRadial = radialUnit.convertTo(maxRadial, SimpleUnit.kmUnit); // convert to km

      } catch (IOException e) {
        e.printStackTrace();
      } catch (IllegalArgumentException e) {
        e.printStackTrace();
      }
    }
    return maxRadial;
  }

public
double
getMaximumRadial
(
)
{
if
(
maxRadial
==
0.0
)
{
try
{
Array
radialData
=
getRadialAxisDataCached
(
)
;
maxRadial
=
MAMath
.
getMaximum
(
radialData
)
;
String
units
=
getRadialAxis
(
)
.
getUnitsString
(
)
;
SimpleUnit
radialUnit
=
SimpleUnit
.
factory
(
units
)
;
maxRadial
=
radialUnit
.
convertTo
(
maxRadial
,
SimpleUnit
.
kmUnit
)
;
// convert to km
}
catch
(
IOException
e
)
{
e
.
printStackTrace
(
)
;
}
catch
(
IllegalArgumentException
e
)
{
e
.
printStackTrace
(
)
;
}
}
return
maxRadial
;
}


private void openURL(String urlString, Command command) {
    try {
      //Open the URLConnection for reading
      URL u = new URL(urlString);
      currentConnection = (HttpURLConnection) u.openConnection();
      currentConnection.setRequestMethod(command.toString()); // GET or HEAD
      currentConnection.setAllowUserInteraction(true);

      clear();
      appendLine(command + " request for " + urlString);

      // request headers
      Map<String, List<String>> reqs = currentConnection.getRequestProperties();
      for (Map.Entry<String, List<String>> ent : reqs.entrySet()) {
        append(" " + ent.getKey() + ": ");
        for (String v : ent.getValue())
          append(v + " ");
        appendLine("");
      }
      appendLine("");
      appendLine("getFollowRedirects=" + HttpURLConnection.getFollowRedirects());
      appendLine("getInstanceFollowRedirects=" + currentConnection.getInstanceFollowRedirects());
      appendLine("AllowUserInteraction=" + currentConnection.getAllowUserInteraction());
      appendLine("");

      int code = currentConnection.getResponseCode();
      String response = currentConnection.getResponseMessage();

      // response headers
      appendLine(" HTTP/1.x " + code + " " + response);
      appendLine(" content-length: " + currentConnection.getContentLength());
      appendLine(" content-encoding: " + currentConnection.getContentEncoding());
      appendLine(" content-type: " + currentConnection.getContentType());
      appendLine("\nHeaders: ");

      for (int j = 1; true; j++) {
        String header = currentConnection.getHeaderField(j);
        String key = currentConnection.getHeaderFieldKey(j);
        if (header == null || key == null) break;
        appendLine(" " + key + ": " + header);
      }

      appendLine("");
      appendLine("contents:");

      // read it
      java.io.InputStream is = currentConnection.getInputStream();
      ByteArrayOutputStream bout = new ByteArrayOutputStream(200000);
      IO.copy(is, bout);
      is.close();

      append(new String(bout.toByteArray(), CDM.utf8Charset));
      appendLine("end contents");

    } catch (MalformedURLException e) {
      append(urlString + " is not a parseable URL");
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }

private
void
openURL
(
String
urlString
,
Command
command
)
{
try
{
//Open the URLConnection for reading
URL
u
=
new
URL
(
urlString
)
;
currentConnection
=
(
HttpURLConnection
)
u
.
openConnection
(
)
;
currentConnection
.
setRequestMethod
(
command
.
toString
(
)
)
;
// GET or HEAD
currentConnection
.
setAllowUserInteraction
(
true
)
;
clear
(
)
;
appendLine
(
command
+
" request for "
+
urlString
)
;
// request headers
Map
<
String
,
List
<
String
>
>
reqs
=
currentConnection
.
getRequestProperties
(
)
;
for
(
Map
.
Entry
<
String
,
List
<
String
>
>
ent
:
reqs
.
entrySet
(
)
)
{
append
(
" "
+
ent
.
getKey
(
)
+
": "
)
;
for
(
String
v
:
ent
.
getValue
(
)
)
append
(
v
+
" "
)
;
appendLine
(
""
)
;
}
appendLine
(
""
)
;
appendLine
(
"getFollowRedirects="
+
HttpURLConnection
.
getFollowRedirects
(
)
)
;
appendLine
(
"getInstanceFollowRedirects="
+
currentConnection
.
getInstanceFollowRedirects
(
)
)
;
appendLine
(
"AllowUserInteraction="
+
currentConnection
.
getAllowUserInteraction
(
)
)
;
appendLine
(
""
)
;
int
code
=
currentConnection
.
getResponseCode
(
)
;
String
response
=
currentConnection
.
getResponseMessage
(
)
;
// response headers
appendLine
(
" HTTP/1.x "
+
code
+
" "
+
response
)
;
appendLine
(
" content-length: "
+
currentConnection
.
getContentLength
(
)
)
;
appendLine
(
" content-encoding: "
+
currentConnection
.
getContentEncoding
(
)
)
;
appendLine
(
" content-type: "
+
currentConnection
.
getContentType
(
)
)
;
appendLine
(
"\nHeaders: "
)
;
for
(
int
j
=
1
;
true
;
j
++
)
{
String
header
=
currentConnection
.
getHeaderField
(
j
)
;
String
key
=
currentConnection
.
getHeaderFieldKey
(
j
)
;
if
(
header
==
||
key
==
)
break
;
appendLine
(
" "
+
key
+
": "
+
header
)
;
}
appendLine
(
""
)
;
appendLine
(
"contents:"
)
;
// read it
java
.
io
.
InputStream
is
=
currentConnection
.
getInputStream
(
)
;
ByteArrayOutputStream
bout
=
new
ByteArrayOutputStream
(
200000
)
;
IO
.
copy
(
is
,
bout
)
;
is
.
close
(
)
;
append
(
new
String
(
bout
.
toByteArray
(
)
,
CDM
.
utf8Charset
)
)
;
appendLine
(
"end contents"
)
;
}
catch
(
MalformedURLException
e
)
{
append
(
urlString
+
" is not a parseable URL"
)
;
}
catch
(
IOException
e
)
{
e
.
printStackTrace
(
)
;
}
}


public double[] earthToSat(double geographic_lon, double geographic_lat) {

    geographic_lat = geographic_lat * DEG_TO_RAD;
    geographic_lon = geographic_lon * DEG_TO_RAD;

    double geocentric_lat = Math.atan(((r_pol * r_pol) / (r_eq * r_eq)) * Math.tan(geographic_lat));

    double r_earth = r_pol / Math.sqrt(1.0 - ((r_eq * r_eq - r_pol * r_pol) / (r_eq * r_eq)) * Math.cos(geocentric_lat) * Math.cos(geocentric_lat));

    double r_1 = h - r_earth * Math.cos(geocentric_lat) * Math.cos(geographic_lon - sub_lon);
    double r_2 = -r_earth * Math.cos(geocentric_lat) * Math.sin(geographic_lon - sub_lon);
    double r_3 = r_earth * Math.sin(geocentric_lat);

    if (r_1 > h) { // often two geoid intersect points, use the closer one.
      return new double[]{Double.NaN, Double.NaN};
    }

    double lamda_sat = Double.NaN;
    double theta_sat = Double.NaN;

    if (scan_geom.equals(GEOS)) { // GEOS (eg. SEVIRI, MSG)  CGMS 03, 4.4.3.2, Normalized Geostationary Projection
      lamda_sat = Math.atan(-r_2 / r_1);
      theta_sat = Math.asin(r_3 / Math.sqrt(r_1 * r_1 + r_2 * r_2 + r_3 * r_3));
    } else if (scan_geom.equals(GOES)) { // GOES (eg. GOES-R ABI)
      lamda_sat = Math.asin(-r_2 / Math.sqrt(r_1 * r_1 + r_2 * r_2 + r_3 * r_3));
      theta_sat = Math.atan(r_3 / r_1);
    }

    return new double[]{lamda_sat, theta_sat};
  }

Transform geographic Earth coordinates to satellite view angle coordinate system
also known as the "intermediate" coordinate system in CGMS Normalized Geostationary Projection.

@param geographic_lon longitude, units: degrees
@param geographic_lat latitude, units: degrees
@return (lamda, theta) units: radian. This is the (x,y) or (East-West, North_South) view angle.

Transform geographic Earth coordinates to satellite view angle coordinate system also known as the intermediate coordinate system in CGMS Normalized Geostationary Projection .


public double[] satToEarth(double x, double y) {

    if (scan_geom.equals(GOES)) { // convert from GOES to GEOS for transfrom below
      double[] lambda_theta_geos = GOES_to_GEOS(x, y);
      x = lambda_theta_geos[0];
      y = lambda_theta_geos[1];
    }

    double c1 = (h * Math.cos(x) * Math.cos(y)) * (h * Math.cos(x) * Math.cos(y));
    double c2 = (Math.cos(y) * Math.cos(y) + fp * Math.sin(y) * Math.sin(y)) * d;

    if (c1 < c2) {
      return new double[]{Double.NaN, Double.NaN};
    }

    double s_d = Math.sqrt(c1 - c2);

    double s_n = (h * Math.cos(x) * Math.cos(y) - s_d) / (Math.cos(y) * Math.cos(y) + fp * Math.sin(y) * Math.sin(y));

    double s_1 = h - s_n * Math.cos(x) * Math.cos(y);
    double s_2 = s_n * Math.sin(x) * Math.cos(y);
    double s_3 = -s_n * Math.sin(y);

    double s_xy = Math.sqrt(s_1 * s_1 + s_2 * s_2);
    double geographic_lon = Math.atan(s_2 / s_1) + sub_lon;

    double geographic_lat = Math.atan(-fp * (s_3 / s_xy));

    double lonDegrees = RAD_TO_DEG * geographic_lon;
    double latDegrees = RAD_TO_DEG * geographic_lat;

    // force output longitude to -180 to 180 range
    if (lonDegrees < -180.0) lonDegrees += 360.0;
    if (lonDegrees > 180.0) lonDegrees -= 360.0;

    return new double[]{lonDegrees, latDegrees};
  }

Transform satellite view angle coordinates, known as the "intermeidate" coordinates in the
CGMS Normalized Geostationary Projection, to geographic Earth coordinates.

@param x is lamda (East-West) angle, units: radians
@param y is theta (Norht-South) angle, units: radians
@return (Longitude, Latitude), units degrees

Transform satellite view angle coordinates known as the intermeidate coordinates in the CGMS Normalized Geostationary Projection to geographic Earth coordinates .


public double[] GOES_to_GEOS(double lamda_goes, double theta_goes) {
    double theta_geos = Math.asin(Math.sin(theta_goes) * Math.cos(lamda_goes));
    double lamda_geos = Math.atan(Math.tan(lamda_goes) / Math.cos(theta_goes));

    return new double[]{lamda_geos, theta_geos};
  }

public double [ ] GOES_to_GEOS ( double lamda_goes , double theta_goes ) { double theta_geos = Math . asin ( Math . sin ( theta_goes ) * Math . cos ( lamda_goes ) ) ; double lamda_geos = Math . atan ( Math . tan ( lamda_goes ) / Math . cos ( theta_goes ) ) ; return new double [ ] { lamda_geos , theta_geos } ; }

Transform view angle coordinates in the GOES scan geometry frame to view angle coordinates
in the GEOS scan geometry frame.

Transform view angle coordinates in the GOES scan geometry frame to view angle coordinates in the GEOS scan geometry frame .


public static String scanGeomToSweepAngleAxis(String scanGeometry) {

    String sweepAngleAxis = "y";
    if (scanGeometry.equals(GOES)) {
      sweepAngleAxis = "x";
    }

    return sweepAngleAxis;
  }

public static String scanGeomToSweepAngleAxis ( String scanGeometry ) { String sweepAngleAxis = "y" ; if ( scanGeometry . equals ( GOES ) ) { sweepAngleAxis = "x" ; } return sweepAngleAxis ; }

Find sweep_angle_axis associated with a scan geometry

@param scanGeometry scanning geometry (GOES or GEOS)
@return sweep_angle_axis (x or y)


public static String sweepAngleAxisToScanGeom(String sweepAngleAxis) {

    String scanGeom = GOES;
    if (sweepAngleAxis.equals("y")) {
      scanGeom = GEOS;
    }

    return scanGeom;
  }

public static String sweepAngleAxisToScanGeom ( String sweepAngleAxis ) { String scanGeom = GOES ; if ( sweepAngleAxis . equals ( "y" ) ) { scanGeom = GEOS ; } return scanGeom ; }

Find scan geometry associated with sweep_angle_axis

@param sweepAngleAxis sweep_angle_axis (x or y)
@return scan_geom scanning geometry (GOES or GEOS)


void setRuntimeCoords(CoordinateRuntime runtimes) {
    for (int idx=0; idx<runtimes.getSize(); idx++) {
      CalendarDate cd = runtimes.getRuntimeDate(idx);
      long runtime = runtimes.getRuntime(idx);
      CoordinateTimeAbstract time = timeMap.get(runtime);
      if (time == null) {
        time = isTimeInterval ? new CoordinateTimeIntv(this.code, this.timeUnit, cd, new ArrayList<>(0), null) :
                new CoordinateTime(this.code, this.timeUnit, cd, new ArrayList<>(0), null);
        timeMap.put(runtime, time);
      }
    }
  }

void setRuntimeCoords ( CoordinateRuntime runtimes ) { for ( int idx = 0 ; idx < runtimes . getSize ( ) ; idx ++ ) { CalendarDate cd = runtimes . getRuntimeDate ( idx ) ; long runtime = runtimes . getRuntime ( idx ) ; CoordinateTimeAbstract time = timeMap . get ( runtime ) ; if ( time == null ) { time = isTimeInterval ? new CoordinateTimeIntv ( this . code , this . timeUnit , cd , new ArrayList <> ( 0 ) , null ) : new CoordinateTime ( this . code , this . timeUnit , cd , new ArrayList <> ( 0 ) , null ) ; timeMap . put ( runtime , time ) ; } } }

set the list of runtime coordinates; add any that are not already present, and make an empty CoordinateTimeAbstract for it

set the list of runtime coordinates ; add any that are not already present and make an empty CoordinateTimeAbstract for it


public static void writePointObsDataset(PointObsDataset pobsDataset, String fileOut) throws IOException {

    // see if we have an altitude
    String altUnits = null;
    DataIterator iterOne = pobsDataset.getDataIterator(-1);
    while (iterOne.hasNext()) {
      PointObsDatatype pobsData = (PointObsDatatype) iterOne.nextData();
      ucar.unidata.geoloc.EarthLocation loc = pobsData.getLocation();
      altUnits = Double.isNaN(loc.getAltitude()) ? null : "meters";
      break;
    }

    List<VariableSimpleIF> vars = pobsDataset.getDataVariables();
    List<PointObVar> nvars = new ArrayList<PointObVar>(vars.size());

    // put vars in order
    for (VariableSimpleIF v : vars) {
      if (v.getDataType().isNumeric())
        nvars.add(new PointObVar(v));
    }
    int ndoubles = vars.size();
    double[] dvals = new double[ndoubles];

    for (VariableSimpleIF v : vars) {
      if (v.getDataType().isString())
        nvars.add(new PointObVar(v));
    }
    String[] svals = new String[vars.size() - ndoubles];

    FileOutputStream fos = new FileOutputStream(fileOut);
    DataOutputStream out = new DataOutputStream(fos);
    CFPointObWriter writer = new CFPointObWriter(out, pobsDataset.getGlobalAttributes(), altUnits, nvars, -1);

    DataIterator iter = pobsDataset.getDataIterator(1000 * 1000);
    while (iter.hasNext()) {
      PointObsDatatype pobsData = (PointObsDatatype) iter.nextData();
      StructureData sdata = pobsData.getData();

      int dcount = 0;
      int scount = 0;
      for (PointObVar v : nvars) {
        if (v.getDataType().isNumeric()) {
          Array data = sdata.getArray(v.getName());
          data.resetLocalIterator();
          if (data.hasNext())
            dvals[dcount++] = data.nextDouble();

        } else if (v.getDataType().isString()) {
          ArrayChar data = (ArrayChar) sdata.getArray(v.getName());
          svals[scount++] = data.getString();
        }
      }

      ucar.unidata.geoloc.EarthLocation loc = pobsData.getLocation();
      writer.addPoint(loc.getLatitude(), loc.getLongitude(), loc.getAltitude(), pobsData.getObservationTimeAsDate(),
          dvals, svals);
    }

    writer.finish();
  }

public
static
void
writePointObsDataset
(
PointObsDataset
pobsDataset
,
String
fileOut
)
throws
IOException
{
// see if we have an altitude
String
altUnits
=
;
DataIterator
iterOne
=
pobsDataset
.
getDataIterator
(
1
)
;
while
(
iterOne
.
hasNext
(
)
)
{
PointObsDatatype
pobsData
=
(
PointObsDatatype
)
iterOne
.
nextData
(
)
;
ucar
.
unidata
.
geoloc
.
EarthLocation
loc
=
pobsData
.
getLocation
(
)
;
altUnits
=
Double
.
isNaN
(
loc
.
getAltitude
(
)
)
:
"meters"
;
break
;
}
List
<
VariableSimpleIF
>
vars
=
pobsDataset
.
getDataVariables
(
)
;
List
<
PointObVar
>
nvars
=
new
ArrayList
<
PointObVar
>
(
vars
.
size
(
)
)
;
// put vars in order
for
(
VariableSimpleIF
v
:
vars
)
{
if
(
v
.
getDataType
(
)
.
isNumeric
(
)
)
nvars
.
add
(
new
PointObVar
(
v
)
)
;
}
int
ndoubles
=
vars
.
size
(
)
;
double
[
]
dvals
=
new
double
[
ndoubles
]
;
for
(
VariableSimpleIF
v
:
vars
)
{
if
(
v
.
getDataType
(
)
.
isString
(
)
)
nvars
.
add
(
new
PointObVar
(
v
)
)
;
}
String
[
]
svals
=
new
String
[
vars
.
size
(
)
ndoubles
]
;
FileOutputStream
fos
=
new
FileOutputStream
(
fileOut
)
;
DataOutputStream
out
=
new
DataOutputStream
(
fos
)
;
CFPointObWriter
writer
=
new
CFPointObWriter
(
out
,
pobsDataset
.
getGlobalAttributes
(
)
,
altUnits
,
nvars
,
1
)
;
DataIterator
iter
=
pobsDataset
.
getDataIterator
(
1000
*
1000
)
;
while
(
iter
.
hasNext
(
)
)
{
PointObsDatatype
pobsData
=
(
PointObsDatatype
)
iter
.
nextData
(
)
;
StructureData
sdata
=
pobsData
.
getData
(
)
;
int
dcount
=
0
;
int
scount
=
0
;
for
(
PointObVar
v
:
nvars
)
{
if
(
v
.
getDataType
(
)
.
isNumeric
(
)
)
{
Array
data
=
sdata
.
getArray
(
v
.
getName
(
)
)
;
data
.
resetLocalIterator
(
)
;
if
(
data
.
hasNext
(
)
)
dvals
[
dcount
++
]
=
data
.
nextDouble
(
)
;
}
else
if
(
v
.
getDataType
(
)
.
isString
(
)
)
{
ArrayChar
data
=
(
ArrayChar
)
sdata
.
getArray
(
v
.
getName
(
)
)
;
svals
[
scount
++
]
=
data
.
getString
(
)
;
}
}
ucar
.
unidata
.
geoloc
.
EarthLocation
loc
=
pobsData
.
getLocation
(
)
;
writer
.
addPoint
(
loc
.
getLatitude
(
)
,
loc
.
getLongitude
(
)
,
loc
.
getAltitude
(
)
,
pobsData
.
getObservationTimeAsDate
(
)
,
dvals
,
svals
)
;
}
writer
.
finish
(
)
;
}

write data from a ucar.nc2.dt.PointObsDataset into CF point format.

@param pobsDataset rewrite data from here
@param fileOut     write to tehis netcdf-3 file
@throws IOException on read/write error

write data from a ucar . nc2 . dt . PointObsDataset into CF point format .


public static boolean rewritePointFeatureDataset(String fileIn, String fileOut, boolean inMemory) throws IOException {
    System.out.println("Rewrite2 .nc files from " + fileIn + " to " + fileOut + " inMemory= " + inMemory);

    long start = System.currentTimeMillis();

    // do it in memory for speed
    NetcdfFile ncfile = inMemory ? NetcdfFile.openInMemory(fileIn) : NetcdfFile.open(fileIn);
    NetcdfDataset ncd = new NetcdfDataset(ncfile);

    Formatter errlog = new Formatter();
    FeatureDataset fd = FeatureDatasetFactoryManager.wrap(FeatureType.ANY_POINT, ncd, null, errlog);
    if (fd == null) return false;

    if (fd instanceof FeatureDatasetPoint) {
      writePointFeatureCollection((FeatureDatasetPoint) fd, fileOut);
      fd.close();
      long took = System.currentTimeMillis() - start;
      System.out.println(" that took " + (took - start) + " msecs");
      return true;
    }

    return false;

  }

public
static
boolean
rewritePointFeatureDataset
(
String
fileIn
,
String
fileOut
,
boolean
inMemory
)
throws
IOException
{
System
.
out
.
println
(
"Rewrite2 .nc files from "
+
fileIn
+
" to "
+
fileOut
+
" inMemory= "
+
inMemory
)
;
long
start
=
System
.
currentTimeMillis
(
)
;
// do it in memory for speed
NetcdfFile
ncfile
=
inMemory
NetcdfFile
.
openInMemory
(
fileIn
)
:
NetcdfFile
.
open
(
fileIn
)
;
NetcdfDataset
ncd
=
new
NetcdfDataset
(
ncfile
)
;
Formatter
errlog
=
new
Formatter
(
)
;
FeatureDataset
fd
=
FeatureDatasetFactoryManager
.
wrap
(
FeatureType
.
ANY_POINT
,
ncd
,
,
errlog
)
;
if
(
fd
==
)
return
false
;
if
(
fd
instanceof
FeatureDatasetPoint
)
{
writePointFeatureCollection
(
(
FeatureDatasetPoint
)
fd
,
fileOut
)
;
fd
.
close
(
)
;
long
took
=
System
.
currentTimeMillis
(
)
start
;
System
.
out
.
println
(
" that took "
+
(
took
start
)
+
" msecs"
)
;
return
true
;
}
return
false
;
}

Open a ucar.nc2.ft.PointFeatureCollection, write out in CF point format.

@param fileIn   open through TypedDatasetFactory.open(FeatureType.POINT, ..)
@param fileOut  write to this netcdf-3 file
@param inMemory if true, read file into memory for efficiency
@return true on success
@throws IOException on read/write error

Open a ucar . nc2 . ft . PointFeatureCollection write out in CF point format .


public ArraySequence getArraySequence(String memberName) {
    StructureMembers.Member m = members.findMember(memberName);
    if (m == null) throw new IllegalArgumentException("illegal member name =" + memberName);
    return getArraySequence(m);
  }

public
ArraySequence
getArraySequence
(
String
memberName
)
{
StructureMembers
.
Member
m
=
members
.
findMember
(
memberName
)
;
if
(
m
==
)
throw
new
IllegalArgumentException
(
"illegal member name ="
+
memberName
)
;
return
getArraySequence
(
m
)
;
}

Get ArraySequence for a member of type Sequence.
@param memberName name of member Variable. Must be of type Sequence.
@return ArrayStructure

Get ArraySequence for a member of type Sequence .


public String getFullName() {
    return (parent == null)
        ? name
        : (parent.getFullName() == null || parent.getFullName().length() == 0)
        ? name
        : parent.getFullName() + "/" + name;
  }

public String getFullName ( ) { return ( parent == null ) ? name : ( parent . getFullName ( ) == null || parent . getFullName ( ) . length ( ) == 0 ) ? name : parent . getFullName ( ) + "/" + name ; }

Get the full, heirarchical name of the dataset, which has all parent collection names.

@return full, heirarchical name of the dataset, which has all parent collection names.

Get the full heirarchical name of the dataset which has all parent collection names .


public String getUniqueID() {
    String authority = getAuthority();
    if ((authority != null) && (getID() != null))
      return authority + ":" + getID();
    else if (getID() != null)
      return getID();
    else
      return null;
  }

public String getUniqueID ( ) { String authority = getAuthority ( ) ; if ( ( authority != null ) && ( getID ( ) != null ) ) return authority + ":" + getID ( ) ; else if ( getID ( ) != null ) return getID ( ) ; else return null ; }

If this dataset has an authority and an ID, then the concatenation of them is the
globally unique ID.

@return globally unique ID, or null if missing authority or ID.

If this dataset has an authority and an ID then the concatenation of them is the globally unique ID .


public InvAccess getAccess(thredds.catalog.ServiceType type) {
    for (InvAccess a : getAccess()) {
      InvService s = a.getService();
      if (s.getServiceType() == type)
        return a;
    }
    return null;
  }

public InvAccess getAccess ( thredds . catalog . ServiceType type ) { for ( InvAccess a : getAccess ( ) ) { InvService s = a . getService ( ) ; if ( s . getServiceType ( ) == type ) return a ; } return null ; }

Get access element of the specified service type for this dataset.
If more than one, get the first one.

@param type find this ServiceType
@return InvAccess or null if there is not one.

Get access element of the specified service type for this dataset . If more than one get the first one .


public InvDatasetImpl findDatasetByName(String name) {
    for (InvDataset ds : getDatasets()) {
      if (ds.getName().equals(name))
        return (InvDatasetImpl) ds;
    }
    return null;
  }

public InvDatasetImpl findDatasetByName ( String name ) { for ( InvDataset ds : getDatasets ( ) ) { if ( ds . getName ( ) . equals ( name ) ) return ( InvDatasetImpl ) ds ; } return null ; }

Find an immediate child dataset by its name.

@param name match on this name
@return dataset if found or null if not exist.

Find an immediate child dataset by its name .


public InvCatalog getParentCatalog() {
    if (catalog != null) return catalog;
    return (parent != null) ? parent.getParentCatalog() : null;
  }

public InvCatalog getParentCatalog ( ) { if ( catalog != null ) return catalog ; return ( parent != null ) ? parent . getParentCatalog ( ) : null ; }

Get containing catalog.

@return containing catalog.


public java.util.List<InvMetadata> getMetadata(thredds.catalog.MetadataType want) {
    List<InvMetadata> result = new ArrayList<InvMetadata>();
    for (InvMetadata m : getMetadata()) {
      MetadataType mtype = MetadataType.getType(m.getMetadataType());
      if (mtype == want)
        result.add(m);
    }
    return result;
  }

public java . util . List < InvMetadata > getMetadata ( thredds . catalog . MetadataType want ) { List < InvMetadata > result = new ArrayList < InvMetadata > ( ) ; for ( InvMetadata m : getMetadata ( ) ) { MetadataType mtype = MetadataType . getType ( m . getMetadataType ( ) ) ; if ( mtype == want ) result . add ( m ) ; } return result ; }

Get the metadata elements of the specified type.

@param want find this metadata type
@return List of InvMetadata objects. List may be empty but not null.

Get the metadata elements of the specified type .


public InvService findService(String name) {
    if (name == null) return null;

    // search local (but expanded) services
    for (InvService p : services) {
      if (p.getName().equals(name))
        return p;
    }

    // not found, look in parent
    if (parent != null)
      return parent.findService(name);
    return (catalog == null) ? null : catalog.findService(name);
  }

public
InvService
findService
(
String
name
)
{
if
(
name
==
)
return
;
// search local (but expanded) services
for
(
InvService
p
:
services
)
{
if
(
p
.
getName
(
)
.
equals
(
name
)
)
return
p
;
}
// not found, look in parent
if
(
parent
!=
)
return
parent
.
findService
(
name
)
;
return
(
catalog
==
)
:
catalog
.
findService
(
name
)
;
}

Find the named service declared in this dataset or one of its parents.

@param name match this name
@return first service that matches the given name, or null if none found.

Find the named service declared in this dataset or one of its parents .


public ThreddsMetadata.Variables getVariables(String vocab) {
    ThreddsMetadata.Variables result = new ThreddsMetadata.Variables(vocab, null, null, null, null);
    if (variables == null) return result;

    for (ThreddsMetadata.Variables vs : variables) {
      if (vs.getVocabulary().equals(vocab))
        result.getVariableList().addAll(vs.getVariableList());
    }
    return result;
  }

public ThreddsMetadata . Variables getVariables ( String vocab ) { ThreddsMetadata . Variables result = new ThreddsMetadata . Variables ( vocab , null , null , null , null ) ; if ( variables == null ) return result ; for ( ThreddsMetadata . Variables vs : variables ) { if ( vs . getVocabulary ( ) . equals ( vocab ) ) result . getVariableList ( ) . addAll ( vs . getVariableList ( ) ) ; } return result ; }

get Variables from the specified vocabulary

@param vocab look for this vocabulary
@return Variables from the specified vocabulary, may be null


public static List<InvCatalogRef> findAllCatRefsInDatasetTree( List<InvDataset> datasets, StringBuilder log, boolean onlyRelativeUrls )
    {
        List<InvCatalogRef> catRefList = new ArrayList<InvCatalogRef>();
        for ( InvDataset invds : datasets )
        {
            InvDatasetImpl curDs = (InvDatasetImpl) invds;

            if ( curDs instanceof InvDatasetScan)
                continue;

            if ( curDs instanceof InvCatalogRef )
            {
                InvCatalogRef catRef = (InvCatalogRef) curDs;
                String name = catRef.getName();
                String href = catRef.getXlinkHref();
                URI uri;
                try
                {
                    uri = new URI( href );
                }
                catch ( URISyntaxException e )
                {
                    log.append( log.length() > 0 ? "\n" : "" )
                            .append( "***WARN - CatalogRef [").append(name)
                            .append("] with bad HREF [" ).append( href ).append( "] " );
                    continue;
                }
                if ( onlyRelativeUrls && uri.isAbsolute() )
                    continue;

                catRefList.add( catRef );
                continue;
            }

            if ( curDs.hasNestedDatasets() )
                catRefList.addAll( findAllCatRefsInDatasetTree( curDs.getDatasets(), log, onlyRelativeUrls ) );
        }
        return catRefList;
    }

public
static
List
<
InvCatalogRef
>
findAllCatRefsInDatasetTree
(
List
<
InvDataset
>
datasets
,
StringBuilder
log
,
boolean
onlyRelativeUrls
)
{
List
<
InvCatalogRef
>
catRefList
=
new
ArrayList
<
InvCatalogRef
>
(
)
;
for
(
InvDataset
invds
:
datasets
)
{
InvDatasetImpl
curDs
=
(
InvDatasetImpl
)
invds
;
if
(
curDs
instanceof
InvDatasetScan
)
continue
;
if
(
curDs
instanceof
InvCatalogRef
)
{
InvCatalogRef
catRef
=
(
InvCatalogRef
)
curDs
;
String
name
=
catRef
.
getName
(
)
;
String
href
=
catRef
.
getXlinkHref
(
)
;
URI
uri
;
try
{
uri
=
new
URI
(
href
)
;
}
catch
(
URISyntaxException
e
)
{
log
.
append
(
log
.
length
(
)
>
0
"\n"
:
""
)
.
append
(
"***WARN - CatalogRef ["
)
.
append
(
name
)
.
append
(
"] with bad HREF ["
)
.
append
(
href
)
.
append
(
"] "
)
;
continue
;
}
if
(
onlyRelativeUrls
&&
uri
.
isAbsolute
(
)
)
continue
;
catRefList
.
add
(
catRef
)
;
continue
;
}
if
(
curDs
.
hasNestedDatasets
(
)
)
catRefList
.
addAll
(
findAllCatRefsInDatasetTree
(
curDs
.
getDatasets
(
)
,
log
,
onlyRelativeUrls
)
)
;
}
return
catRefList
;
}

Find all catalogRef elements in the dataset tree formed by the given dataset list.

@param datasets         the list of datasets from which to find all the catalogRefs
@param log              StringBuilder into which any messages will be written
@param onlyRelativeUrls only include catalogRefs with relative HREF URLs if true, otherwise include all catalogRef datasets
@return the list of catalogRef datasets

Find all catalogRef elements in the dataset tree formed by the given dataset list .


static public String escapePathForURL(String path) {
        try {
            return new URI(null, null, path, null).toString();
        } catch (URISyntaxException e) {
            return path;
        }
    }

static public String escapePathForURL ( String path ) { try { return new URI ( null , null , path , null ) . toString ( ) ; } catch ( URISyntaxException e ) { return path ; } }

Escape the characters necessary for a path to be valid for a URL


private ArrayDouble.D3 addStagger(ArrayDouble.D3 array, int dimIndex) {

    //ADD: assert 0<=dimIndex<=2

    int[] shape = array.getShape();
    int[] newShape = new int[3];
    System.arraycopy(shape, 0, newShape, 0, 3);

    newShape[dimIndex]++;
    int ni = newShape[0];
    int nj = newShape[1];
    int nk = newShape[2];
    ArrayDouble.D3 newArray = new ArrayDouble.D3(ni, nj, nk);
    //Index newIndex = newArray.getIndex();

    //extract 1d array to be extended
    int n = shape[dimIndex];  //length of extracted array
    double[] d = new double[n];  //tmp array to hold extracted values
    int[] eshape = new int[3];       //shape of extracted array
    int[] neweshape = new int[3];  //shape of new array slice to write into
    for (int i = 0; i < 3; i++) {
      eshape[i] = (i == dimIndex)
          ? n
          : 1;
      neweshape[i] = (i == dimIndex)
          ? n + 1
          : 1;
    }
    int[] origin = new int[3];

    try {

      //loop through the other 2 dimensions and "extrapinterpolate" the other
      for (int i = 0; i < ((dimIndex == 0)
          ? 1
          : ni); i++) {
        for (int j = 0; j < ((dimIndex == 1)
            ? 1
            : nj); j++) {
          for (int k = 0; k < ((dimIndex == 2)
              ? 1
              : nk); k++) {
            origin[0] = i;
            origin[1] = j;
            origin[2] = k;
            IndexIterator it = array.section(origin,
                eshape).getIndexIterator();
            for (int l = 0; l < n; l++) {
              d[l] = it.getDoubleNext();  //get the original values
            }
            double[] d2 = extrapinterpolate(d);  //compute new values
            //define slice of new array to write into
            IndexIterator newit =
                newArray.section(origin,
                    neweshape).getIndexIterator();
            for (int l = 0; l < n + 1; l++) {
              newit.setDoubleNext(d2[l]);
            }
          }
        }
      }
    } catch (InvalidRangeException e) {
      //ADD: report error?
      return null;
    }

    return newArray;
  }

Add 1 to the size of the array for the given dimension.
Use linear average and interpolation to fill in the values.

@param array    use this array
@param dimIndex use this dimension
@return new array with stagger

Add 1 to the size of the array for the given dimension . Use linear average and interpolation to fill in the values .


private double[] extrapinterpolate(double[] array) {
    int n = array.length;
    double[] d = new double[n + 1];

    //end points from linear extrapolation
    //equations confirmed by Christopher Lindholm
    d[0] = 1.5 * array[0] - 0.5 * array[1];
    d[n] = 1.5 * array[n - 1] - 0.5 * array[n - 2];

    //inner points from simple average
    for (int i = 1; i < n; i++) {
      d[i] = 0.5 * (array[i - 1] + array[i]);
    }

    return d;
  }

Add one element to the array by linear interpolation
and extrapolation at the ends.

@param array input array
@return extrapolated/interpolated array

Add one element to the array by linear interpolation and extrapolation at the ends .


private double computeRho(double lat) {
    return earth_radius * Math.sqrt(C - 2 * n * Math.sin(lat)) / n;
  }

private double computeRho ( double lat ) { return earth_radius * Math . sqrt ( C - 2 * n * Math . sin ( lat ) ) / n ; }

Compute the RHO parameter

@param lat latitude
@return the rho parameter


public String getDetailInfo() {
    Formatter ff = new Formatter();
    ff.format("%s", super.getDetailInfo());
    ff.format("%s", parseInfo);
    return ff.toString();
  }

public String getDetailInfo ( ) { Formatter ff = new Formatter ( ) ; ff . format ( "%s" , super . getDetailInfo ( ) ) ; ff . format ( "%s" , parseInfo ) ; return ff . toString ( ) ; }

Get the detail information

@return the detail info


protected Structure makeStructure(String partName, List<Dimension> dimensions, boolean includeMissing) {
    List<GempakParameter> params = gemreader.getParameters(partName);
    if (params == null) {
      return null;
    }
    Structure sVar = new Structure(ncfile, null, null, partName);
    sVar.setDimensions(dimensions);
    for (GempakParameter param : params) {
      sVar.addMemberVariable(makeParamVariable(param, null));
    }
    if (includeMissing) {
      sVar.addMemberVariable(makeMissingVariable());
    }
    return sVar;
  }

protected Structure makeStructure ( String partName , List < Dimension > dimensions , boolean includeMissing ) { List < GempakParameter > params = gemreader . getParameters ( partName ) ; if ( params == null ) { return null ; } Structure sVar = new Structure ( ncfile , null , null , partName ) ; sVar . setDimensions ( dimensions ) ; for ( GempakParameter param : params ) { sVar . addMemberVariable ( makeParamVariable ( param , null ) ) ; } if ( includeMissing ) { sVar . addMemberVariable ( makeMissingVariable ( ) ) ; } return sVar ; }

Make a structure for the part

@param partName       partname
@param dimensions     dimensions for the structure
@param includeMissing true to include the missing variable
@return a Structure


protected Variable makeMissingVariable() {
    Variable var = new Variable(ncfile, null, null, MISSING_VAR);
    var.setDataType(DataType.BYTE);
    var.setDimensions((List<Dimension>) null);
    var.addAttribute(new Attribute("description", "missing flag - 1 means all params are missing"));
    var.addAttribute(new Attribute(CDM.MISSING_VALUE, (byte) 1));
    return var;
  }

Make the missing variable

@return the missing variable


protected Variable makeParamVariable(GempakParameter param, List<Dimension> dims) {
    Variable var = new Variable(ncfile, null, null, param.getName());
    var.setDataType(DataType.FLOAT);
    var.setDimensions(dims);
    var.addAttribute(new Attribute(CDM.LONG_NAME, param.getDescription()));
    String units = param.getUnit();
    if ((units != null) && !units.equals("")) {
      var.addAttribute(new Attribute(CDM.UNITS, units));
    }
    var.addAttribute(new Attribute(CDM.MISSING_VALUE, RMISS));
    return var;
  }

protected Variable makeParamVariable ( GempakParameter param , List < Dimension > dims ) { Variable var = new Variable ( ncfile , null , null , param . getName ( ) ) ; var . setDataType ( DataType . FLOAT ) ; var . setDimensions ( dims ) ; var . addAttribute ( new Attribute ( CDM . LONG_NAME , param . getDescription ( ) ) ) ; String units = param . getUnit ( ) ; if ( ( units != null ) && ! units . equals ( "" ) ) { var . addAttribute ( new Attribute ( CDM . UNITS , units ) ) ; } var . addAttribute ( new Attribute ( CDM . MISSING_VALUE , RMISS ) ) ; return var ; }

Make a variable from a GempakParmaeter

@param param GempakParameter
@param dims  Variable dimensions
@return the Variable


protected void addGlobalAttributes() {
    // global stuff
    ncfile.addAttribute(null, new Attribute(CDM.CONVENTIONS, getConventions()));
    String fileType = "GEMPAK " + gemreader.getFileType();
    ncfile.addAttribute(null, new Attribute("file_format", fileType));
    ncfile.addAttribute(null, new Attribute("history", "Direct read of " + fileType + " into NetCDF-Java API"));
    ncfile.addAttribute(null, new Attribute(CF.FEATURE_TYPE, getCFFeatureType()));
  }

protected
void
addGlobalAttributes
(
)
{
// global stuff
ncfile
.
addAttribute
(
,
new
Attribute
(
CDM
.
CONVENTIONS
,
getConventions
(
)
)
)
;
String
fileType
=
"GEMPAK "
+
gemreader
.
getFileType
(
)
;
ncfile
.
addAttribute
(
,
new
Attribute
(
"file_format"
,
fileType
)
)
;
ncfile
.
addAttribute
(
,
new
Attribute
(
"history"
,
"Direct read of "
+
fileType
+
" into NetCDF-Java API"
)
)
;
ncfile
.
addAttribute
(
,
new
Attribute
(
CF
.
FEATURE_TYPE
,
getCFFeatureType
(
)
)
)
;
}


protected int getStnVarSize(String name) {
    int size = -1;
    for (int i = 0; i < stnVarNames.length; i++) {
      if (name.equals(stnVarNames[i])) {
        size = stnVarSizes[i];
        break;
      }
    }
    return size;
  }

protected int getStnVarSize ( String name ) { int size = - 1 ; for ( int i = 0 ; i < stnVarNames . length ; i ++ ) { if ( name . equals ( stnVarNames [ i ] ) ) { size = stnVarSizes [ i ] ; break ; } } return size ; }

Get the size of a particular station variable

@param name name of the variable (key)
@return size or -1


private Array get1DArray(DataType type, int len) {
    Array varArray = null;
    if (type.equals(DataType.FLOAT)) {
      varArray = new ArrayFloat.D1(len);
    } else if (type.equals(DataType.DOUBLE)) {
      varArray = new ArrayDouble.D1(len);
    } else if (type.equals(DataType.INT)) {
      varArray = new ArrayInt.D1(len, false);
    }
    return varArray;
  }

private Array get1DArray ( DataType type , int len ) { Array varArray = null ; if ( type . equals ( DataType . FLOAT ) ) { varArray = new ArrayFloat . D1 ( len ) ; } else if ( type . equals ( DataType . DOUBLE ) ) { varArray = new ArrayDouble . D1 ( len ) ; } else if ( type . equals ( DataType . INT ) ) { varArray = new ArrayInt . D1 ( len , false ) ; } return varArray ; }

Get a 1DArray for the type and length

@param type DataType
@param len  length
@return the array


private int yy_lr_goto_state_ (int yystate, int yysym)
  {
    int yyr = yypgoto_[yysym - yyntokens_] + yystate;
    if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate)
      return yytable_[yyr];
    else
      return yydefgoto_[yysym - yyntokens_];
  }

private int yy_lr_goto_state_ ( int yystate , int yysym ) { int yyr = yypgoto_ [ yysym - yyntokens_ ] + yystate ; if ( 0 <= yyr && yyr <= yylast_ && yycheck_ [ yyr ] == yystate ) return yytable_ [ yyr ] ; else return yydefgoto_ [ yysym - yyntokens_ ] ; }

Compute post-reduction state.
@param yystate   the current state
@param yysym     the nonterminal to push on the stack


private String yysyntax_error (int yystate, int tok)
  {
    if (yyErrorVerbose)
      {
        /* There are many possibilities here to consider:
           - If this state is a consistent state with a default action,
             then the only way this function was invoked is if the
             default action is an error action.  In that case, don't
             check for expected tokens because there are none.
           - The only way there can be no lookahead present (in tok) is
             if this state is a consistent state with a default action.
             Thus, detecting the absence of a lookahead is sufficient to
             determine that there is no unexpected or expected token to
             report.  In that case, just report a simple "syntax error".
           - Don't assume there isn't a lookahead just because this
             state is a consistent state with a default action.  There
             might have been a previous inconsistent state, consistent
             state with a non-default action, or user semantic action
             that manipulated yychar.  (However, yychar is currently out
             of scope during semantic actions.)
           - Of course, the expected token list depends on states to
             have correct lookahead information, and it depends on the
             parser not to perform extra reductions after fetching a
             lookahead from the scanner and before detecting a syntax
             error.  Thus, state merging (from LALR or IELR) and default
             reductions corrupt the expected token list.  However, the
             list is correct for canonical LR with one exception: it
             will still contain any token that will not be accepted due
             to an error action in a later state.
        */
        if (tok != yyempty_)
          {
            /* FIXME: This method of building the message is not compatible
               with internationalization.  */
            StringBuffer res =
              new StringBuffer ("syntax error, unexpected ");
            res.append (yytnamerr_ (yytname_[tok]));
            int yyn = yypact_[yystate];
            if (!yy_pact_value_is_default_ (yyn))
              {
                /* Start YYX at -YYN if negative to avoid negative
                   indexes in YYCHECK.  In other words, skip the first
                   -YYN actions for this state because they are default
                   actions.  */
                int yyxbegin = yyn < 0 ? -yyn : 0;
                /* Stay within bounds of both yycheck and yytname.  */
                int yychecklim = yylast_ - yyn + 1;
                int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_;
                int count = 0;
                for (int x = yyxbegin; x < yyxend; ++x)
                  if (yycheck_[x + yyn] == x && x != yyterror_
                      && !yy_table_value_is_error_ (yytable_[x + yyn]))
                    ++count;
                if (count < 5)
                  {
                    count = 0;
                    for (int x = yyxbegin; x < yyxend; ++x)
                      if (yycheck_[x + yyn] == x && x != yyterror_
                          && !yy_table_value_is_error_ (yytable_[x + yyn]))
                        {
                          res.append (count++ == 0 ? ", expecting " : " or ");
                          res.append (yytnamerr_ (yytname_[x]));
                        }
                  }
              }
            return res.toString ();
          }
      }

    return "syntax error";
  }


private void yy_reduce_print (int yyrule, YYStack yystack)
  {
    if (yydebug == 0)
      return;

    int yylno = yyrline_[yyrule];
    int yynrhs = yyr2_[yyrule];
    /* Print the symbols being reduced, and their result.  */
    yycdebug ("Reducing stack by rule " + (yyrule - 1)
              + " (line " + yylno + "), ");

    /* The symbols being reduced.  */
    for (int yyi = 0; yyi < yynrhs; yyi++)
      yy_symbol_print ("   $" + (yyi + 1) + " =",
                       yystos_[yystack.stateAt(yynrhs - (yyi + 1))],
                       ((yystack.valueAt (yynrhs-(yyi + 1)))));
  }

Report on the debug stream that the rule yyrule is going to be reduced.

Report on the debug stream that the rule yyrule is going to be reduced .


public String
    readDMR()
            throws DapException
    {
        try {
            if(state != State.INITIAL)
                throw new DapException("Attempt to read DMR twice");

            byte[] dmr8 = null;

            if(requestmode == RequestMode.DMR) {
                // The whole buffer is the dmr;
                // but we do not know the length
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int c;
                while((c = input.read()) >= 0) {
                    baos.write(c);
                }
                baos.close();
                dmr8 = baos.toByteArray();
            } else if(requestmode == RequestMode.DAP) {
                // Pull in the DMR chunk header
                if(!readHeader(input))
                    throw new DapException("Malformed chunk count");
                // Read the DMR databuffer
                dmr8 = new byte[this.chunksize];
                int red = read(dmr8, 0, this.chunksize);
                if(red < this.chunksize)
                    throw new DapException("Short chunk");
            } else
                assert false : "Internal error";

            // Convert DMR to a string
            String dmr = new String(dmr8, DapUtil.UTF8);
            // Clean it up
            dmr = dmr.trim();
            // Make sure it has trailing \r\n"
            if(dmr.endsWith("\r\n")) {
                // do nothing
            } else if(dmr.endsWith("\n"))
                dmr = dmr.substring(0,dmr.length()-2) + "\r\n";
            else
                dmr = dmr + "\r\n";

            // Figure out the endian-ness of the response
            this.remoteorder = (flags & DapUtil.CHUNK_LITTLE_ENDIAN) == 0 ? ByteOrder.BIG_ENDIAN
                    : ByteOrder.LITTLE_ENDIAN;
            this.nochecksum = (flags & DapUtil.CHUNK_NOCHECKSUM) != 0;

            // Set the state
            if((flags & DapUtil.CHUNK_ERROR) != 0)
                state = State.ERROR;
            else if((flags & DapUtil.CHUNK_END) != 0)
                state = State.END;
            else
                state = State.DATA;
            return dmr; //return the DMR

        } catch (IOException ioe) {
            throw new DapException(ioe.getMessage());
        }
    }

Read the DMR, trimmed.

@return the DMR as a Java String


public String
    readError()
            throws IOException
    {
        state = State.ERROR;
        // Read the error body databuffer
        byte[] bytes = new byte[this.chunksize];
        try {
            if(read(bytes, 0, this.chunksize) < this.chunksize)
                throw new ErrorException("Short chunk");
        } catch (IOException ioe) {
            throw new ErrorException(ioe);
        }
        String document = new String(bytes, DapUtil.UTF8);
        return document;
    }

public
String
readError
(
)
throws
IOException
{
state
=
State
.
ERROR
;
// Read the error body databuffer
byte
[
]
bytes
=
new
byte
[
this
.
chunksize
]
;
try
{
if
(
read
(
bytes
,
0
,
this
.
chunksize
)
<
this
.
chunksize
)
throw
new
ErrorException
(
"Short chunk"
)
;
}
catch
(
IOException
ioe
)
{
throw
new
ErrorException
(
ioe
)
;
}
String
document
=
new
String
(
bytes
,
DapUtil
.
UTF8
)
;
return
document
;
}

Read an error chunk

@return the error document as a string


public int
    read(byte[] buf, int off, int len)
            throws IOException
    {
        // Sanity check
        if(off < 0 || len < 0)
            throw new IndexOutOfBoundsException();// Runtime
        if(off >= buf.length || buf.length < (off + len))
            throw new IndexOutOfBoundsException(); //Runtime
        if(requestmode == RequestMode.DMR)
            throw new UnsupportedOperationException("Attempt to read databuffer when DMR only"); // Runtime

        // Attempt to read len bytes out of a sequence of chunks
        int count = len;
        int pos = off;
        while(count > 0) {
            if(avail <= 0) {
                if((flags & DapUtil.CHUNK_END) != 0
                        || !readHeader(input))
                    return (len - count); // return # databuffer read
                // See if we have an error chunk,
                // and if so, turn it into an exception
                if((flags & DapUtil.CHUNK_ERROR) != 0) {
                    String document = readError();
                    throwError(document);
                }
            } else {
                int actual = (this.avail < count ? this.avail : count);
                int red = input.read(buf, pos, actual);
                if(red < 0)
                    throw new IOException("Unexpected EOF");
                pos += red;
                count -= red;
                this.avail -= red;
            }
        }
        return len;
    }

Reads up to len databuffer of databuffer from the input stream into an
array of databuffer. An attempt is made to read as many as len
databuffer, but a smaller number may be read. The number of databuffer
actually read is returned as an integer.

@param buf the byte array into which databuffer is read
@param off the offset in the byte array at which to write
@param len the amount to read
@return the actual number of databuffer read
@throws IOException

Reads up to len databuffer of databuffer from the input stream into an array of databuffer . An attempt is made to read as many as len databuffer but a smaller number may be read . The number of databuffer actually read is returned as an integer .


boolean
    readHeader(InputStream input)
            throws IOException
    {
        byte[] bytehdr = new byte[4];
        int red = input.read(bytehdr);
        if(red == -1) return false;
        if(red < 4)
            throw new IOException("Short binary chunk count");
        this.flags = ((int) bytehdr[0]) & 0xFF; // Keep unsigned
        bytehdr[0] = 0;
        ByteBuffer buf = ByteBuffer.wrap(bytehdr).order(ByteOrder.BIG_ENDIAN);
        this.chunksize = buf.getInt();
        this.avail = this.chunksize;
        return true;
    }

boolean
readHeader
(
InputStream
input
)
throws
IOException
{
byte
[
]
bytehdr
=
new
byte
[
4
]
;
int
red
=
input
.
read
(
bytehdr
)
;
if
(
red
==
1
)
return
false
;
if
(
red
<
4
)
throw
new
IOException
(
"Short binary chunk count"
)
;
this
.
flags
=
(
(
int
)
bytehdr
[
0
]
)
&
0xFF
;
// Keep unsigned
bytehdr
[
0
]
=
0
;
ByteBuffer
buf
=
ByteBuffer
.
wrap
(
bytehdr
)
.
order
(
ByteOrder
.
BIG_ENDIAN
)
;
this
.
chunksize
=
buf
.
getInt
(
)
;
this
.
avail
=
this
.
chunksize
;
return
true
;
}

Read the size+flags header from the input stream and use it to
initialize the chunk state

@param input The input streamfrom which to read
@return true if header read false if immediate eof encountered

Read the size + flags header from the input stream and use it to initialize the chunk state


static public Date isoStringToDate(String iso) throws IllegalArgumentException {
    CalendarDate dt = isoStringToCalendarDate(null, iso);
	  return dt.toDate();
  }

static public Date isoStringToDate ( String iso ) throws IllegalArgumentException { CalendarDate dt = isoStringToCalendarDate ( null , iso ) ; return dt . toDate ( ) ; }

Does not handle non-standard Calendars
@param iso iso formatted string
@return Date
@throws IllegalArgumentException
@deprecated use isoStringToCalendarDate

Does not handle non - standard Calendars


static public List<Record> readTable(String urlString, String format, int maxLines) throws IOException, NumberFormatException {

    InputStream ios;
    if (urlString.startsWith("http:")) {
      URL url = new URL(urlString);
      ios = url.openStream();
    } else {
      ios = new FileInputStream(urlString);
    }

    return readTable(ios, format, maxLines);
  }

static public List < Record > readTable ( String urlString , String format , int maxLines ) throws IOException , NumberFormatException { InputStream ios ; if ( urlString . startsWith ( "http:" ) ) { URL url = new URL ( urlString ) ; ios = url . openStream ( ) ; } else { ios = new FileInputStream ( urlString ) ; } return readTable ( ios , format , maxLines ) ; }

Reads a URL or file in as a table.

@param urlString starts with http, read URL contenets, else read file.
@param format    describe format of each line.
@param maxLines  maximum number of lines to parse, set to < 0 to read all
@return List of TableParser.Record
@throws IOException           on read error
@throws NumberFormatException on parse number error
@see #readTable(InputStream ios, String format, int maxLines)


static private void transferGroup(NetcdfFile ds, NetcdfDataset targetDs, Group src, Group targetGroup, ReplaceVariableCheck replaceCheck) {
    boolean unlimitedOK = true; // LOOK why not allowed?

    // group attributes
    transferGroupAttributes(src, targetGroup);

    // dimensions
    for (Dimension d : src.getDimensions()) {
      if (null == targetGroup.findDimensionLocal(d.getShortName())) {
        Dimension newd = new Dimension(d.getShortName(), d.getLength(), d.isShared(), unlimitedOK && d.isUnlimited(), d.isVariableLength());
        targetGroup.addDimension(newd);
      }
    }

    // variables
    for (Variable v : src.getVariables()) {
      Variable targetV = targetGroup.findVariable(v.getShortName());
      VariableEnhanced targetVe = (VariableEnhanced) targetV;
      boolean replace = (replaceCheck != null) && replaceCheck.replace(v); // replaceCheck not currently used

      if (replace || (null == targetV)) { // replace it
        if ((v instanceof Structure) && !(v instanceof StructureDS)) {
           v = new StructureDS(targetGroup, (Structure) v);

          // else if (!(v instanceof VariableDS) && !(v instanceof StructureDS)) Doug Lindolm
        } else if (!(v instanceof VariableDS)) {
          v = new VariableDS(targetGroup, v, false);  // enhancement done by original variable, this is just to reparent to target dataset.
        }

        if (null != targetV) targetGroup.remove(targetV);
        targetGroup.addVariable(v); // reparent group
        v.resetDimensions(); // dimensions will be different

      } else if (!targetV.hasCachedData() && (targetVe.getOriginalVariable() == null)) {
        // this is the case where we defined the variable, but didnt set its data. we now set it with the first nested
        // dataset that has a variable with the same name
        targetVe.setOriginalVariable(v);
      }
    }

    // nested groups - check if target already has it
    for (Group srcNested : src.getGroups()) {
      Group nested = targetGroup.findGroup(srcNested.getShortName());
      if (null == nested) {
        nested = new Group(ds, targetGroup, srcNested.getShortName());
        targetGroup.addGroup(nested);
      }
      transferGroup(ds, targetDs, srcNested, nested, replaceCheck);
    }
  }

transfer the objects in src group to the target group


private File getStnFile(String location) {
    File file = new File(location);
    File stnFile = new File(file.getParentFile(), STN_FILE);
    if (!stnFile.exists()) {
      if (file.getParentFile() == null) return null;
      stnFile = new File(file.getParentFile().getParentFile(), STN_FILE);
      if (!stnFile.exists()) return null;
    }
    return stnFile;
  }

private File getStnFile ( String location ) { File file = new File ( location ) ; File stnFile = new File ( file . getParentFile ( ) , STN_FILE ) ; if ( ! stnFile . exists ( ) ) { if ( file . getParentFile ( ) == null ) return null ; stnFile = new File ( file . getParentFile ( ) . getParentFile ( ) , STN_FILE ) ; if ( ! stnFile . exists ( ) ) return null ; } return stnFile ; }

stn file must be in the same directory or one up


@Override
  public void open(RandomAccessFile raff, NetcdfFile ncfile, CancelTask cancelTask) throws IOException {
    super.open(raff, ncfile, cancelTask);
    int pos = location.lastIndexOf(".");
    String ext = location.substring(pos);

    File file = new File(location);
    File stnFile = getStnFile(location);
    if (stnFile == null)
      throw new FileNotFoundException("Station File does not exist="+location);

    if (ext.equals(IDX_EXT)) {
      stnRaf = RandomAccessFile.acquire(stnFile.getPath());

    } else if (ext.equals(DAT_EXT)) {
      stnRaf = RandomAccessFile.acquire(stnFile.getPath());
      dataRaf = raff;

      //extract the station id
      String name = file.getName();
      stationId = name.substring(0, name.length() - DAT_EXT.length());

    } else { // pointed to the station file
      stnRaf = raff;
      dataDir = new File(file.getParentFile(), DAT_DIR);
    }

    NcmlConstructor ncmlc = new NcmlConstructor();
    if (!ncmlc.populateFromResource("resources/nj22/iosp/igra-por.ncml", ncfile)) {
      throw new IllegalStateException(ncmlc.getErrlog().toString());
    }
    ncfile.finish();

    //dataVinfo = setVinfo(dataRaf, ncfile, dataPattern, "all_data");
    stnVinfo = setVinfo(stnRaf, ncfile, stnPattern, "station");
    seriesVinfo = setVinfo(stnRaf, ncfile, dataHeaderPattern, "station.time_series");
    profileVinfo = setVinfo(stnRaf, ncfile, dataPattern, "station.time_series.levels");

    StructureMembers.Member m = stnVinfo.sm.findMember(STNID);
    StructureDataRegexp.VinfoField f = (StructureDataRegexp.VinfoField) m.getDataObject();
    stn_fldno = f.fldno;

    /* make index file if needed
    File idxFile = new File(base + IDX_EXT);
    if (!idxFile.exists())
      makeIndex(stnVinfo, dataVinfo, idxFile);
    else
      readIndex(idxFile.getPath());  */
  }


public int getBeginning(int index) {

		//Test if the last end is the new beginning
		if(index == (pastIndex + 1 ))
		{
			return previousEnd + 1;
		}

		// Otherwise, find it!
		int newBeginning = 0;
		for(int i = 0; i < index; i++) {
			newBeginning += getNodeCount(i);
		}

		pastIndex = index;
		previousBegin = newBeginning;
		return newBeginning;
	}

Gets the beginning index of a geometry's points given the index of the geometry within the array.

@param index
@return beginning of the range

Gets the beginning index of a geometry s points given the index of the geometry within the array .


public int getEnd(int index) {

		// Test if the last beginning is the new end
		if(index == (pastIndex - 1))
		{
			return previousBegin - 1;
		}

		// Otherwise find it!
		int new_end = 0;
		for(int i = 0; i < index + 1; i++) {
			new_end += getNodeCount(i);
		}

		pastIndex = index;
		previousEnd = new_end;
		return new_end - 1;
	}

Gets the ending index of a geometry's points given the index of the geometry within the array.

@param index of the geometry within the array
@return end of the range

Gets the ending index of a geometry s points given the index of the geometry within the array .


private boolean createAllRuntimeCollections(Formatter errlog) throws IOException {
    long start = System.currentTimeMillis();
    this.type =  GribCollectionImmutable.Type.SRC;
    boolean ok = true;

    List<MFile> files = new ArrayList<>();
    List<? extends Group> groups = makeGroups(files, true, errlog);
    List<MFile> allFiles = Collections.unmodifiableList(files);

    // gather into collections with a single runtime
    Map<Long, List<Group>> runGroups = new HashMap<>();
    for (Group g : groups) {
      List<Group> runGroup = runGroups
          .computeIfAbsent(g.getRuntime().getMillis(), k -> new ArrayList<>());
      runGroup.add(g);
    }

    // write each rungroup separately
    boolean multipleRuntimes = runGroups.values().size() > 1;
    List<MFile> partitions = new ArrayList<>();
    for (List<Group> runGroupList : runGroups.values()) {
      Group g = runGroupList.get(0);
      // if multiple Runtimes, we will write a partition. otherwise, we need to use the standard name (without runtime) so we know the filename from the collection
      String gcname = multipleRuntimes ? GribCollectionMutable.makeName(this.name, g.getRuntime()) : this.name;
      MFile indexFileForRuntime = GribCollectionMutable.makeIndexMFile(gcname, directory); // not using disk cache LOOK why ?
      partitions.add(indexFileForRuntime);

     // create the master runtimes, consisting of the single runtime
      List<Long> runtimes = new ArrayList<>(1);
      runtimes.add(g.getRuntime().getMillis());
      CoordinateRuntime masterRuntimes = new CoordinateRuntime(runtimes, null);

      CalendarDateRange calendarDateRangeAll = null;
      for (Coordinate coord : g.getCoordinates()) {
        if (coord instanceof CoordinateTimeAbstract) {
          CalendarDateRange calendarDateRange = ((CoordinateTimeAbstract) coord).makeCalendarDateRange(null);
          if (calendarDateRangeAll == null) calendarDateRangeAll = calendarDateRange;
          else calendarDateRangeAll = calendarDateRangeAll.extend(calendarDateRange);
        }
      }
      assert calendarDateRangeAll != null;

      // for each Group write an index file
      ok &= writeIndex(gcname, indexFileForRuntime.getPath(), masterRuntimes, runGroupList, allFiles, calendarDateRangeAll);
      logger.info("GribCollectionBuilder write {} ok={}", indexFileForRuntime.getPath(), ok);
    }

    // if theres more than one runtime, create a partition collection to collect all the runtimes together
    if (multipleRuntimes) {
      Collections.sort(partitions); // ??
      PartitionManager part = new PartitionManagerFromIndexList(dcm, partitions, logger);
      part.putAuxInfo(FeatureCollectionConfig.AUX_CONFIG, dcm.getAuxInfo(FeatureCollectionConfig.AUX_CONFIG));
      ok &= GribCdmIndex.updateGribCollectionFromPCollection(isGrib1, part, CollectionUpdateType.always, errlog, logger);
    }

    long took = System.currentTimeMillis() - start;
    logger.debug("That took {} msecs", took);
    return ok;
  }

creates seperate collection and index for each runtime.

creates seperate collection and index for each runtime .


protected void setEditValue(Object value) {
    if (value == null)
      tf.setText("");
    else
      tf.setText(value.toString());
    // tf.repaint();
  }

protected
void
setEditValue
(
Object
value
)
{
if
(
value
==
)
tf
.
setText
(
""
)
;
else
tf
.
setText
(
value
.
toString
(
)
)
;
// tf.repaint();
}


DataType getDataType(int format) {
    DataType p;

    switch (format) {
      case 1:    // 8-bit signed integer format.
        p = DataType.SHORT;
        break;
      case 2:  // 16-bit signed integer format.
        p = DataType.FLOAT;
        break;
      case 3:    // 32-bit signed integer format.
        p = DataType.LONG;
        break;
      case 4:   // 32-bit IEEE float format.
        p = DataType.FLOAT;
        break;
      case 5:   //  16-bit IEEE float format.
        p = DataType.DOUBLE;
        break;
      default:
        p = null;
        break;
    } //end of switch
    return p;
  }

DataType
getDataType
(
int
format
)
{
DataType
p
;
switch
(
format
)
{
case
1
:
// 8-bit signed integer format.
p
=
DataType
.
SHORT
;
break
;
case
2
:
// 16-bit signed integer format.
p
=
DataType
.
FLOAT
;
break
;
case
3
:
// 32-bit signed integer format.
p
=
DataType
.
LONG
;
break
;
case
4
:
// 32-bit IEEE float format.
p
=
DataType
.
FLOAT
;
break
;
case
5
:
//  16-bit IEEE float format.
p
=
DataType
.
DOUBLE
;
break
;
default
:
p
=
;
break
;
}
//end of switch
return
p
;
}

Return the string of entity ID for the Dorade image file


public static double[] ECFtoLLA(double x, double y, double z,
                                  double a, double b) {

    double longitude = Math.atan2(y, x);
    double ePrimeSquared = (a * a - b * b) / (b * b);
    double p = Math.sqrt(x * x + y * y);
    double theta = Math.atan((z * a) / (p * b));
    double sineTheta = Math.sin(theta);
    double cosTheta = Math.cos(theta);
    double f = 1 / 298.257223563;
    double e2 = 2 * f - f * f;
    double top = z + ePrimeSquared * b * sineTheta * sineTheta
            * sineTheta;
    double bottom = p - e2 * a * cosTheta * cosTheta * cosTheta;
    double geodeticLat = Math.atan(top / bottom);
    double sineLat = Math.sin(geodeticLat);
    double N = a / Math.sqrt(1 - e2 * sineLat * sineLat);
    double altitude = (p / Math.cos(geodeticLat)) - N;

    // maintain longitude btw -PI and PI
    if (longitude > Math.PI) {
      longitude -= 2 * Math.PI;

    } else if (longitude < -Math.PI) {
      longitude += 2 * Math.PI;
    }

    return new double[]{geodeticLat, longitude, altitude};
  }

public
static
double
[
]
ECFtoLLA
(
double
x
,
double
y
,
double
z
,
double
a
,
double
b
)
{
double
longitude
=
Math
.
atan2
(
y
,
x
)
;
double
ePrimeSquared
=
(
a
*
a
b
*
b
)
/
(
b
*
b
)
;
double
p
=
Math
.
sqrt
(
x
*
x
+
y
*
y
)
;
double
theta
=
Math
.
atan
(
(
z
*
a
)
/
(
p
*
b
)
)
;
double
sineTheta
=
Math
.
sin
(
theta
)
;
double
cosTheta
=
Math
.
cos
(
theta
)
;
double
f
=
1
/
298.257223563
;
double
e2
=
2
*
f
f
*
f
;
double
top
=
z
+
ePrimeSquared
*
b
*
sineTheta
*
sineTheta
*
sineTheta
;
double
bottom
=
p
e2
*
a
*
cosTheta
*
cosTheta
*
cosTheta
;
double
geodeticLat
=
Math
.
atan
(
top
/
bottom
)
;
double
sineLat
=
Math
.
sin
(
geodeticLat
)
;
double
N
=
a
/
Math
.
sqrt
(
1
e2
*
sineLat
*
sineLat
)
;
double
altitude
=
(
p
/
Math
.
cos
(
geodeticLat
)
)
N
;
// maintain longitude btw -PI and PI
if
(
longitude
>
Math
.
PI
)
{
longitude
-=
2
*
Math
.
PI
;
}
else
if
(
longitude
<
Math
.
PI
)
{
longitude
+=
2
*
Math
.
PI
;
}
return
new
double
[
]
{
geodeticLat
,
longitude
,
altitude
}
;
}

comparing api to others

@param x _more_
@param y _more_
@param z _more_
@param a _more_
@param b _more_
@return _more_


public static String cleanUnit(String unit) {
    if (unit == null) return null;
    // These specific words become dimensionless
    if (unit.equalsIgnoreCase("Proportion") || unit.equalsIgnoreCase("Numeric"))
      unit = "";
    // So does '-'
    else if (unit.equalsIgnoreCase("-")) {
      unit = "";
    // Make sure degree(s) true gets concatenated with '_'
    } else if (unit.startsWith("degree") && unit.endsWith("true")) {
      unit = unit.replace(' ', '_');
    // And only do the rest of the conversion if it's not a "* table *" entry
    } else if (!unit.contains(" table ")) {
      if (unit.startsWith("/")) unit = "1" + unit;
      unit = unit.trim();
      unit = StringUtil2.remove(unit, "**");
      StringBuilder sb = new StringBuilder(unit);
      StringUtil2.remove(sb, "^[]");
      StringUtil2.replace(sb, ' ', ".");
      StringUtil2.replace(sb, '*', ".");
      unit = sb.toString();
    }
    return unit;
  }

Clean up strings to be used for unit string
@param unit original
@return cleaned up


public static String cleanName(String name) {
    if (name == null) return null;
    int pos = name.indexOf("(see");
    if (pos < 0) pos = name.indexOf("(See");
    if (pos > 0) name = name.substring(0,pos);

    name = StringUtil2.replace(name, '/', "-");
    StringBuilder sb = new StringBuilder(name);
    StringUtil2.replace(sb, '+', "plus");
    StringUtil2.remove(sb, ".;,=[]()/*\"");
    return StringUtil2.collapseWhitespace(sb.toString().trim());
  }

public static String cleanName ( String name ) { if ( name == null ) return null ; int pos = name . indexOf ( "(see" ) ; if ( pos < 0 ) pos = name . indexOf ( "(See" ) ; if ( pos > 0 ) name = name . substring ( 0 , pos ) ; name = StringUtil2 . replace ( name , ' ' , "-" ) ; StringBuilder sb = new StringBuilder ( name ) ; StringUtil2 . replace ( sb , ' ' , "plus" ) ; StringUtil2 . remove ( sb , ".;,=[]()/*\"" ) ; return StringUtil2 . collapseWhitespace ( sb . toString ( ) . trim ( ) ) ; }

Clean up strings to be used in Netcdf Object names
@param name original name
@return cleaned up name


public static boolean isUnitless(String unit) {
    if (unit == null) return true;
    String munge = unit.toLowerCase().trim();
    munge = StringUtil2.remove(munge, '(');
    return munge.length()  == 0 ||
        munge.startsWith("numeric") || munge.startsWith("non-dim") || munge.startsWith("see") ||
        munge.startsWith("proportion") || munge.startsWith("code") || munge.startsWith("0=") ||
        munge.equals("1") ;
  }

public static boolean isUnitless ( String unit ) { if ( unit == null ) return true ; String munge = unit . toLowerCase ( ) . trim ( ) ; munge = StringUtil2 . remove ( munge , ' ' ) ; return munge . length ( ) == 0 || munge . startsWith ( "numeric" ) || munge . startsWith ( "non-dim" ) || munge . startsWith ( "see" ) || munge . startsWith ( "proportion" ) || munge . startsWith ( "code" ) || munge . startsWith ( "0=" ) || munge . equals ( "1" ) ; }


static Notes
    factory(NoteSort ns, int g, int id, Nc4DSP dsp)
    {
        Notes note = null;
        switch (ns) {
        case TYPE:
            note = new TypeNotes(g, id, dsp);
            break;
        case VAR:
            note = new VarNotes(g, id, dsp);
            break;
        case DIM:
            note = new DimNotes(g, id, dsp);
            break;
        case GROUP:
            note = new GroupNotes(g, id, dsp);
            break;
        }
        return note;
    }

static Notes factory ( NoteSort ns , int g , int id , Nc4DSP dsp ) { Notes note = null ; switch ( ns ) { case TYPE : note = new TypeNotes ( g , id , dsp ) ; break ; case VAR : note = new VarNotes ( g , id , dsp ) ; break ; case DIM : note = new DimNotes ( g , id , dsp ) ; break ; case GROUP : note = new GroupNotes ( g , id , dsp ) ; break ; } return note ; }

Use a factory so we can debug constructor calls


static public long
    getVarId(VarNotes note)
    {
        return getVarId(note.gid, note.id, note.getFieldIndex());
    }

static public long getVarId ( VarNotes note ) { return getVarId ( note . gid , note . id , note . getFieldIndex ( ) ) ; }


void parseDAS(DAS das) throws IOException {
    Enumeration tableNames = das.getNames();
    while (tableNames.hasMoreElements()) {
      String tableName = (String) tableNames.nextElement();
      AttributeTable attTable = das.getAttributeTableN(tableName);

      if (tableName.equals("NC_GLOBAL") || tableName.equals("HDF_GLOBAL")) {
        addAttributeTable(this, attTable, tableName, true);

      } else if (tableName.equals("DODS_EXTRA") || tableName.equals("EXTRA_DIMENSION")) {
        // handled seperately in DODSNetcdfFile
        continue;

      } else {
        DodsV dodsV = findDodsV(tableName, false); // short name matches the table name
        if (dodsV != null) {
          addAttributeTable(dodsV, attTable, tableName, true);
        } else {
          dodsV = findTableDotDelimited(tableName);
          if (dodsV != null) {
            addAttributeTable(dodsV, attTable, tableName, true);
          } else {
            if (debugAttributes) System.out.println("DODSNetcdf getAttributes CANT find <" + tableName + "> add to globals");
            addAttributeTable(this, attTable, tableName, false);
          }
        }
      }
    }
  }

Parse the DAS, assign attribute tables to the DodsV objects.
Nested attribute tables are supposed to follow the tree we construct with dodsV, so its easy to assign to correct dodsV.

@param das parse this DAS
@throws IOException on io error

Parse the DAS assign attribute tables to the DodsV objects . Nested attribute tables are supposed to follow the tree we construct with dodsV so its easy to assign to correct dodsV .


DodsV findDodsV(String name, boolean useDone) {
    for (DodsV dodsV : children) {
      if (useDone && dodsV.isDone) continue; // LOOK useDone ??
      if ((name == null) || (dodsV == null) || (dodsV.bt == null)) {
        logger.warn("Corrupted structure");
        continue;
      }
      if (name.equals(dodsV.bt.getEncodedName()))
        return dodsV;
    }
    return null;
  }

DodsV
findDodsV
(
String
name
,
boolean
useDone
)
{
for
(
DodsV
dodsV
:
children
)
{
if
(
useDone
&&
dodsV
.
isDone
)
continue
;
// LOOK useDone ??
if
(
(
name
==
)
||
(
dodsV
==
)
||
(
dodsV
.
bt
==
)
)
{
logger
.
warn
(
"Corrupted structure"
)
;
continue
;
}
if
(
name
.
equals
(
dodsV
.
bt
.
getEncodedName
(
)
)
)
return
dodsV
;
}
return
;
}

Search the immediate children for a BaseType with given name.

@param name    look for this name
@param useDone
@return child that matches if found, else null

Search the immediate children for a BaseType with given name .


DodsV findDataV(DodsV ddsV) {
    if (ddsV.parent.bt != null) {
      DodsV parentV = findDataV(ddsV.parent);
      if (parentV == null) // dataDDS may not have the structure wrapper
        return findDodsV(ddsV.bt.getEncodedName(), true);
      return parentV.findDodsV(ddsV.bt.getEncodedName(), true);
    }

    DodsV dataV = findDodsV(ddsV.bt.getEncodedName(), true);
    /* if ((dataV == null) && (ddsV.bt instanceof DGrid)) { // when asking for the Grid array
      DodsV gridArray = (DodsV) ddsV.children.get(0);
      return findDodsV( gridArray.bt.getName(), dataVlist, true);
    } */
    return dataV;
  }

find the DodsV object in the dataVlist corresponding to the ddsV


DodsV findByIndex(int index) {
    if (children.size() <= index) return null;
    return children.get(index);
  }

DodsV findByIndex ( int index ) { if ( children . size ( ) <= index ) return null ; return children . get ( index ) ; }

Return a child by index

@param index return index'th child
@return index'th child or null if index is too large


public Group getParentGroup() {
    Group g = super.getParentGroup();
    if (g == null) {
      g = ncfile.getRootGroup();
      super.setParentGroup(g);
    }

    assert g != null;
    return g;
  }

public Group getParentGroup ( ) { Group g = super . getParentGroup ( ) ; if ( g == null ) { g = ncfile . getRootGroup ( ) ; super . setParentGroup ( g ) ; } assert g != null ; return g ; }

Get the parent group.

@return group of this variable; if null return rootgroup


public Dimension getDimension(int i) {
    if ((i < 0) || (i >= getRank())) return null;
    return dimensions.get(i);
  }

public Dimension getDimension ( int i ) { if ( ( i < 0 ) || ( i >= getRank ( ) ) ) return null ; return dimensions . get ( i ) ; }

Get the ith dimension.

@param i index of the dimension.
@return requested Dimension, or null if i is out of bounds.


public int findDimensionIndex(String name) {
    for (int i = 0; i < dimensions.size(); i++) {
      Dimension d = dimensions.get(i);
      if (name.equals(d.getShortName()))
        return i;
    }
    return -1;
  }

public int findDimensionIndex ( String name ) { for ( int i = 0 ; i < dimensions . size ( ) ; i ++ ) { Dimension d = dimensions . get ( i ) ; if ( name . equals ( d . getShortName ( ) ) ) return i ; } return - 1 ; }

Find the index of the named Dimension in this Variable.

@param name the name of the dimension
@return the index of the named Dimension, or -1 if not found.

Find the index of the named Dimension in this Variable .


public String getUnitsString() {
    String units = null;
    Attribute att = findAttribute(CDM.UNITS);
    if (att == null) att = findAttributeIgnoreCase(CDM.UNITS);
    if ((att != null) && att.isString()) {
      units = att.getStringValue();
      if (units != null) units = units.trim();
    }
    return units;
  }

public String getUnitsString ( ) { String units = null ; Attribute att = findAttribute ( CDM . UNITS ) ; if ( att == null ) att = findAttributeIgnoreCase ( CDM . UNITS ) ; if ( ( att != null ) && att . isString ( ) ) { units = att . getStringValue ( ) ; if ( units != null ) units = units . trim ( ) ; } return units ; }

Get the Unit String for the Variable.
Looks for the CDM.UNITS attribute value

@return unit string, or null if not found.

Get the Unit String for the Variable . Looks for the CDM . UNITS attribute value


public Section getShapeAsSection() {
    if (shapeAsSection == null) {
      try {
        List<Range> list = new ArrayList<>();
        for (Dimension d : dimensions) {
          int len = d.getLength();
          if (len > 0)
            list.add(new Range(d.getShortName(), 0, len - 1));
          else if (len == 0)
            list.add( Range.EMPTY); // LOOK empty not named
          else {
            assert d.isVariableLength();
            list.add( Range.VLEN); // LOOK vlen not named
          }
        }
        shapeAsSection = new Section(list).makeImmutable();

      } catch (InvalidRangeException e) {
        log.error("Bad shape in variable " + getFullName(), e);
        throw new IllegalStateException(e.getMessage());
      }
    }
    return shapeAsSection;
  }

public
Section
getShapeAsSection
(
)
{
if
(
shapeAsSection
==
)
{
try
{
List
<
Range
>
list
=
new
ArrayList
<>
(
)
;
for
(
Dimension
d
:
dimensions
)
{
int
len
=
d
.
getLength
(
)
;
if
(
len
>
0
)
list
.
add
(
new
Range
(
d
.
getShortName
(
)
,
0
,
len
1
)
)
;
else
if
(
len
==
0
)
list
.
add
(
Range
.
EMPTY
)
;
// LOOK empty not named
else
{
assert
d
.
isVariableLength
(
)
;
list
.
add
(
Range
.
VLEN
)
;
// LOOK vlen not named
}
}
shapeAsSection
=
new
Section
(
list
)
.
makeImmutable
(
)
;
}
catch
(
InvalidRangeException
e
)
{
log
.
error
(
"Bad shape in variable "
+
getFullName
(
)
,
e
)
;
throw
new
IllegalStateException
(
e
.
getMessage
(
)
)
;
}
}
return
shapeAsSection
;
}

Get shape as a Section object.

@return Section containing List<Range>, one for each Dimension.


public Variable slice(int dim, int value) throws InvalidRangeException {
    if ((dim < 0) || (dim >= shape.length))
      throw new InvalidRangeException("Slice dim invalid= " + dim);

    // ok to make slice of record dimension with length 0
    boolean recordSliceOk = false;
    if ((dim == 0) && (value == 0)) {
      Dimension d = getDimension(0);
      recordSliceOk = d.isUnlimited();
    }

    // otherwise check slice in range
    if (!recordSliceOk) {
      if ((value < 0) || (value >= shape[dim]))
        throw new InvalidRangeException("Slice value invalid= " + value + " for dimension " + dim);
    }

    // create a copy of this variable with a proxy reader
    Variable sliceV = copy(); // subclasses must override
    Section slice = new Section(getShapeAsSection());
    slice.replaceRange(dim, new Range(value, value)).makeImmutable();
    sliceV.setProxyReader(new SliceReader(this, dim, slice));
    sliceV.createNewCache(); // dont share the cache
    sliceV.setCaching(false); // dont cache

    // remove that dimension - reduce rank
    sliceV.dimensions.remove(dim);
    sliceV.resetShape();
    return sliceV;
  }

Create a new Variable that is a logical slice of this Variable, by
fixing the specified dimension at the specified index value. This reduces rank by 1.
No data is read until a read method is called on it.

@param dim   which dimension to fix
@param value at what index value
@return a new Variable which is a logical slice of this Variable.
@throws InvalidRangeException if dimension or value is illegal

Create a new Variable that is a logical slice of this Variable by fixing the specified dimension at the specified index value . This reduces rank by 1 . No data is read until a read method is called on it .


public void setEnumTypedef(EnumTypedef enumTypedef) {
    if (immutable) throw new IllegalStateException("Cant modify");
    if (!dataType.isEnum())
      throw new UnsupportedOperationException("Can only call Variable.setEnumTypedef() on enum types");
    this.enumTypedef = enumTypedef;
  }

Public by accident.

@param enumTypedef set the EnumTypedef, only use if getDataType.isEnum()


public Array read(List<Range> ranges) throws IOException, InvalidRangeException {
    if (null == ranges)
      return _read();

    return read(new Section(ranges));
  }

public Array read ( List < Range > ranges ) throws IOException , InvalidRangeException { if ( null == ranges ) return _read ( ) ; return read ( new Section ( ranges ) ) ; }

Read a section of the data for this Variable from the netcdf file and return a memory resident Array.

@param ranges list of Range specifying the section of data to read.
@return the requested data in a memory-resident Array
@throws IOException           if error
@throws InvalidRangeException if ranges is invalid
@see #read(Section)

Read a section of the data for this Variable from the netcdf file and return a memory resident Array .


public String readScalarString() throws IOException {
    Array data = getScalarData();
    if (dataType == DataType.STRING)
      return (String) data.getObject(Index.scalarIndexImmutable);
    else if (dataType == DataType.CHAR) {
      ArrayChar dataC = (ArrayChar) data;
      return dataC.getString();
    } else
      throw new IllegalArgumentException("readScalarString not STRING or CHAR " + getFullName());
  }

public
String
readScalarString
(
)
throws
IOException
{
Array
data
=
getScalarData
(
)
;
if
(
dataType
==
DataType
.
STRING
)
return
(
String
)
data
.
getObject
(
Index
.
scalarIndexImmutable
)
;
else
if
(
dataType
==
DataType
.
CHAR
)
{
ArrayChar
dataC
=
(
ArrayChar
)
data
;
return
dataC
.
getString
(
)
;
}
else
throw
new
IllegalArgumentException
(
"readScalarString not STRING or CHAR "
+
getFullName
(
)
)
;
}

Get the value as a String for a scalar Variable.  May also be one-dimensional of length 1.
May also be one-dimensional of type CHAR, which wil be turned into a scalar String.

@throws IOException                   if theres an IO Error
@throws UnsupportedOperationException if not a scalar or one-dimensional.
@throws ClassCastException            if data type not DataType.STRING or DataType.CHAR.

Get the value as a String for a scalar Variable . May also be one - dimensional of length 1 . May also be one - dimensional of type CHAR which wil be turned into a scalar String .


protected Array _read() throws IOException {
    // caching overrides the proxyReader
    // check if already cached
    if (cache.data != null) {
      if (debugCaching) System.out.println("got data from cache " + getFullName());
      return cache.data.copy();
    }

    Array data = proxyReader.reallyRead(this, null);

    // optionally cache it
    if (isCaching()) {
      setCachedData(data);
      if (debugCaching) System.out.println("cache " + getFullName());
      return cache.data.copy(); // dont let users get their nasty hands on cached data
    } else {
      return data;
    }
  }


protected Array _read(Section section) throws IOException, InvalidRangeException {
    // check if its really a full read
    if ((null == section) || section.computeSize() == getSize())
      return _read();

    // full read was cached
    if (isCaching()) {
      if (cache.data == null) {
        setCachedData(_read()); // read and cache entire array
        if (debugCaching) System.out.println("cache " + getFullName());
      }
      if (debugCaching) System.out.println("got data from cache " + getFullName());
      return cache.data.sectionNoReduce(section.getRanges()).copy(); // subset it, return copy
    }

    return proxyReader.reallyRead(this, section, null);
  }

protected
Array
_read
(
Section
section
)
throws
IOException
,
InvalidRangeException
{
// check if its really a full read
if
(
(
==
section
)
||
section
.
computeSize
(
)
==
getSize
(
)
)
return
_read
(
)
;
// full read was cached
if
(
isCaching
(
)
)
{
if
(
cache
.
data
==
)
{
setCachedData
(
_read
(
)
)
;
// read and cache entire array
if
(
debugCaching
)
System
.
out
.
println
(
"cache "
+
getFullName
(
)
)
;
}
if
(
debugCaching
)
System
.
out
.
println
(
"got data from cache "
+
getFullName
(
)
)
;
return
cache
.
data
.
sectionNoReduce
(
section
.
getRanges
(
)
)
.
copy
(
)
;
// subset it, return copy
}
return
proxyReader
.
reallyRead
(
this
,
section
,
)
;
}


public String writeCDL(boolean useFullName, boolean strict) {
    Formatter buf = new Formatter();
    writeCDL(buf, new Indent(2), useFullName, strict);
    return buf.toString();
  }

public String writeCDL ( boolean useFullName , boolean strict ) { Formatter buf = new Formatter ( ) ; writeCDL ( buf , new Indent ( 2 ) , useFullName , strict ) ; return buf . toString ( ) ; }

CDL representation of a Variable.

@param useFullName use full name, else use short name
@param strict      strictly comply with ncgen syntax
@return CDL representation of the Variable.


public String toStringDebug() {
    Formatter f = new Formatter();
    f.format("Variable %s", getFullName());
    if (ncfile != null) {
      f.format(" in file %s", getDatasetLocation());
      String extra = ncfile.toStringDebug(this);
      if (extra != null)
        f.format(" %s", extra);
    }
    return f.toString();
  }

public
String
toStringDebug
(
)
{
Formatter
f
=
new
Formatter
(
)
;
f
.
format
(
"Variable %s"
,
getFullName
(
)
)
;
if
(
ncfile
!=
)
{
f
.
format
(
" in file %s"
,
getDatasetLocation
(
)
)
;
String
extra
=
ncfile
.
toStringDebug
(
this
)
;
if
(
extra
!=
)
f
.
format
(
" %s"
,
extra
)
;
}
return
f
.
toString
(
)
;
}

String representation of Variable and its attributes.

String representation of Variable and its attributes .


public void setDataType(DataType dataType) {
    if (immutable) throw new IllegalStateException("Cant modify");
    this.dataType = dataType;
    this.elementSize = getDataType().getSize();

    /* why is this needed ??
    EnumTypedef etd = getEnumTypedef();
    if (etd != null) {
      DataType etdtype = etd.getBaseType();
      if (dataType != etdtype)
        log.error("Variable.setDataType: enum basetype mismatch: {} != {}", etdtype, dataType);

      /* DataType basetype = null;
      if (dataType == DataType.ENUM1) basetype = DataType.BYTE;
      else if (dataType == DataType.ENUM2) basetype = DataType.SHORT;
      else if (dataType == DataType.ENUM4) basetype = DataType.INT;
      else basetype = etdtype;

      if (etdtype != null && dataType != etdtype)
      else
        etd.setBaseType(basetype);
    }  */
  }

Set the data type

@param dataType set to this value


public void setDimensions(List<Dimension> dims) {
    if (immutable) throw new IllegalStateException("Cant modify");
    this.dimensions = (dims == null) ? new ArrayList<>() : new ArrayList<>(dims);
    resetShape();
  }

public
void
setDimensions
(
List
<
Dimension
>
dims
)
{
if
(
immutable
)
throw
new
IllegalStateException
(
"Cant modify"
)
;
this
.
dimensions
=
(
dims
==
)
new
ArrayList
<>
(
)
:
new
ArrayList
<>
(
dims
)
;
resetShape
(
)
;
}

Set the shape with a list of Dimensions. The Dimensions may be shared or not.
Dimensions are in order, slowest varying first. Send a null for a scalar.
Technically you can use Dimensions from any group; pragmatically you should only use
Dimensions contained in the Variable's parent groups.

@param dims list of type ucar.nc2.Dimension

Set the shape with a list of Dimensions . The Dimensions may be shared or not . Dimensions are in order slowest varying first . Send a null for a scalar . Technically you can use Dimensions from any group ; pragmatically you should only use Dimensions contained in the Variable s parent groups .


public void resetShape() {
    // if (immutable) throw new IllegalStateException("Cant modify");  LOOK allow this for unlimited dimension updating
    this.shape = new int[dimensions.size()];
    for (int i = 0; i < dimensions.size(); i++) {
      Dimension dim = dimensions.get(i);
      shape[i] = dim.getLength();
      //shape[i] = Math.max(dim.getLength(), 0); // LOOK
      // if (dim.isUnlimited() && (i != 0)) // LOOK only true for Netcdf-3
      //   throw new IllegalArgumentException("Unlimited dimension must be outermost");
      if (dim.isVariableLength()) {
        //if (dimensions.size() != 1)
        //  throw new IllegalArgumentException("Unknown dimension can only be used in 1 dim array");
        //else
        isVariableLength = true;
      }
    }
    this.shapeAsSection = null; // recalc next time its asked for
  }

Use when dimensions have changed, to recalculate the shape.

Use when dimensions have changed to recalculate the shape .


public void setDimensions(String dimString) {
    if (immutable) throw new IllegalStateException("Cant modify");
    try {
      setDimensions(Dimension.makeDimensionsList(getParentGroup(), dimString));
      //this.dimensions = Dimension.makeDimensionsList(getParentGroup(), dimString);
      resetShape();
    } catch (IllegalStateException e) {
      throw new IllegalArgumentException("Variable " + getFullName() + " setDimensions = '" + dimString +
              "' FAILED: " + e.getMessage() + " file = " + getDatasetLocation());
    }
  }

Set the dimensions using the dimensions names. The dimension is searched for recursively in the parent groups.

@param dimString : whitespace separated list of dimension names, or '*' for Dimension.UNKNOWN, or number for anon dimension. null or empty String is a scalar.

Set the dimensions using the dimensions names . The dimension is searched for recursively in the parent groups .


public void resetDimensions() {
    if (immutable) throw new IllegalStateException("Cant modify");
    ArrayList<Dimension> newDimensions = new ArrayList<>();

    for (Dimension dim : dimensions) {
      if (dim.isShared()) {
        Dimension newD = getParentGroup().findDimension(dim.getShortName());
        if (newD == null)
          throw new IllegalArgumentException("Variable " + getFullName() + " resetDimensions  FAILED, dim doesnt exist in parent group=" + dim);
        newDimensions.add(newD);
      } else {
        newDimensions.add(dim);
      }
    }
    this.dimensions = newDimensions;
    resetShape();
  }

Reset the dimension array. Anonymous dimensions are left alone.
Shared dimensions are searched for recursively in the parent groups.

Reset the dimension array . Anonymous dimensions are left alone . Shared dimensions are searched for recursively in the parent groups .


public void setDimension(int idx, Dimension dim) {
    if (immutable) throw new IllegalStateException("Cant modify");
    dimensions.set(idx, dim);
    resetShape();
  }

public
void
setDimension
(
int
idx
,
Dimension
dim
)
{
if
(
immutable
)
throw
new
IllegalStateException
(
"Cant modify"
)
;
dimensions
.
set
(
idx
,
dim
)
;
resetShape
(
)
;
}

Replace a dimension with an equivalent one.

@param idx index into dimension array
@param dim to set

Replace a dimension with an equivalent one .


public void setCachedData(Array cacheData, boolean isMetadata) {
    if ((cacheData != null) && (cacheData.getElementType() != getDataType().getPrimitiveClassType()))
      throw new IllegalArgumentException("setCachedData type=" + cacheData.getElementType() + " incompatible with variable type=" + getDataType());

    this.cache.data = cacheData;
    this.isMetadata = isMetadata;
    this.cache.cachingSet = true;
    this.cache.isCaching = true;
  }

public
void
setCachedData
(
Array
cacheData
,
boolean
isMetadata
)
{
if
(
(
cacheData
!=
)
&&
(
cacheData
.
getElementType
(
)
!=
getDataType
(
)
.
getPrimitiveClassType
(
)
)
)
throw
new
IllegalArgumentException
(
"setCachedData type="
+
cacheData
.
getElementType
(
)
+
" incompatible with variable type="
+
getDataType
(
)
)
;
this
.
cache
.
data
=
cacheData
;
this
.
isMetadata
=
isMetadata
;
this
.
cache
.
cachingSet
=
true
;
this
.
cache
.
isCaching
=
true
;
}

Set the data cache

@param cacheData  cache this Array
@param isMetadata : synthesized data, set true if must be saved in NcML output (ie data not actually in the file).


public List<Dimension> getDimensionsAll() {
    List<Dimension> dimsAll = new ArrayList<>();
    addDimensionsAll(dimsAll, this);
    return dimsAll;
  }

public List < Dimension > getDimensionsAll ( ) { List < Dimension > dimsAll = new ArrayList <> ( ) ; addDimensionsAll ( dimsAll , this ) ; return dimsAll ; }

Get list of Dimensions, including parents if any.

@return array of Dimension, rank of v plus all parents.

Get list of Dimensions including parents if any .


protected void setBoundingBox() {
    LatLonRect largestBB = null;
    // look through all the coord systems
    for (Object o : csHash.values()) {
      RadialCoordSys sys = (RadialCoordSys) o;
      sys.setOrigin(origin);
      LatLonRect bb = sys.getBoundingBox();
      if (largestBB == null)
        largestBB = bb;
      else if (bb != null)
        largestBB.extend(bb);
    }
    boundingBox = largestBB;
  }

protected
void
setBoundingBox
(
)
{
LatLonRect
largestBB
=
;
// look through all the coord systems
for
(
Object
o
:
csHash
.
values
(
)
)
{
RadialCoordSys
sys
=
(
RadialCoordSys
)
o
;
sys
.
setOrigin
(
origin
)
;
LatLonRect
bb
=
sys
.
getBoundingBox
(
)
;
if
(
largestBB
==
)
largestBB
=
bb
;
else
if
(
bb
!=
)
largestBB
.
extend
(
bb
)
;
}
boundingBox
=
largestBB
;
}

you must set EarthLocation before you call this.

you must set EarthLocation before you call this .


void finish() {
    gridList = new ArrayList<>(uvHash.values());
    Collections.sort(gridList);

    // find the common coordinates
    for (GridVariable grid : gridList) {
      grid.finish();
    }

    // assign sequence number for time
    int seqno = 0;
    for (TimeCoord tc : timeCoords)
      tc.setId(seqno++);

    // assign sequence number for vertical coords with same name
    HashMap<String, List<VertCoord>> map = new HashMap<>();
    for (VertCoord vc : vertCoords) {
      List<VertCoord> list = map.get(vc.getName());
      if (list == null) {
        list = new ArrayList<>();
        map.put(vc.getName(), list);
      }
      list.add(vc);
    }
    for (List<VertCoord> list : map.values()) {
      if (list.size() > 0) {
        int count = 0;
        for (VertCoord vc : list) {
          if (count > 0) vc.setName(vc.getName()+count);
          count++;
        }
      }
    }

  }


public Iterable<Dataset> getAllDatasets() {
    List<Dataset> all = new ArrayList<>();
    addAll(this, all);
    return all;
  }

public Iterable < Dataset > getAllDatasets ( ) { List < Dataset > all = new ArrayList <> ( ) ; addAll ( this , all ) ; return all ; }

get all datasets contained directly in this catalog


public boolean dspMatch(String path, DapContext context)
    {
        for(String ext : SYNEXTENSIONS) {
            if(path.endsWith(ext))
                return true;
        }
        return false;
    }

public boolean dspMatch ( String path , DapContext context ) { for ( String ext : SYNEXTENSIONS ) { if ( path . endsWith ( ext ) ) return true ; } return false ; }

A path is a Synthetic path if it ends in .dmr or .syn

@param path
@param context Any parameters that may help to decide.
@return true if this path appears to be processible by this DSP

A path is a Synthetic path if it ends in . dmr or . syn


public CDMDSP open(NetcdfDataset ncd)
            throws DapException
    {
        assert this.context != null;
        this.dmrfactory = new DMRFactory();
        this.ncdfile = ncd;
        setLocation(this.ncdfile.getLocation());
        buildDMR();
        return this;
    }

public CDMDSP open ( NetcdfDataset ncd ) throws DapException { assert this . context != null ; this . dmrfactory = new DMRFactory ( ) ; this . ncdfile = ncd ; setLocation ( this . ncdfile . getLocation ( ) ) ; buildDMR ( ) ; return this ; }

Provide an extra API for use in testing

@param ncd
@return
@throws DapException


public void
    buildDMR()
            throws DapException
    {
        if (getDMR() != null)
            return;
        try {
            if (DUMPCDL) {
                System.out.println("writecdl:");
                this.ncdfile.writeCDL(System.out, false);
                System.out.flush();
            }
            // Use the file path to define the dataset name
            String name = this.ncdfile.getLocation();
            // Normalize the name
            name = DapUtil.canonicalpath(name);
            // Remove any path prefix
            int index = name.lastIndexOf('/');
            if (index >= 0)
                name = name.substring(index + 1, name.length());
            // Initialize the root dataset node
            setDMR((DapDataset) dmrfactory.newDataset(name).annotate(NetcdfDataset.class, this.ncdfile));
            // Map the CDM root group to this group
            recordNode(this.ncdfile.getRootGroup(), getDMR());
            getDMR().setBase(DapUtil.canonicalpath(this.ncdfile.getLocation()));

            // Now recursively build the tree. Start by
            // Filling the dataset with the contents of the ncfile
            // root group.
            fillgroup(getDMR(), this.ncdfile.getRootGroup());

            // Add an order index to the tree
            getDMR().sort();

            // Now locate the coordinate variables for maps

            /* Walk looking for VariableDS instances */
            processmappedvariables(this.ncdfile.getRootGroup());

            // Now set the view
            getDMR().finish();

        } catch (DapException e) {
            setDMR(null);
            throw new DapException(e);
        }
    }

Extract the metadata from the NetcdfDataset
and build the DMR.

Extract the metadata from the NetcdfDataset and build the DMR .


protected void
    buildseqtypes(Variable cdmvar)
            throws DapException
    {
        if (CDMUtil.hasVLEN(cdmvar)) {
            buildseqtype(cdmvar);
        }
        if (cdmvar.getDataType() == DataType.STRUCTURE
                || cdmvar.getDataType() == DataType.SEQUENCE) {
            Structure struct = (Structure) cdmvar;
            List<Variable> fields = struct.getVariables();
            for (int i = 0; i < fields.size(); i++) {
                Variable field = fields.get(i);
                buildseqtypes(field); // recurse for inner vlen dims
            }
        }
    }

protected
void
buildseqtypes
(
Variable
cdmvar
)
throws
DapException
{
if
(
CDMUtil
.
hasVLEN
(
cdmvar
)
)
{
buildseqtype
(
cdmvar
)
;
}
if
(
cdmvar
.
getDataType
(
)
==
DataType
.
STRUCTURE
||
cdmvar
.
getDataType
(
)
==
DataType
.
SEQUENCE
)
{
Structure
struct
=
(
Structure
)
cdmvar
;
List
<
Variable
>
fields
=
struct
.
getVariables
(
)
;
for
(
int
i
=
0
;
i
<
fields
.
size
(
)
;
i
++
)
{
Variable
field
=
fields
.
get
(
i
)
;
buildseqtypes
(
field
)
;
// recurse for inner vlen dims
}
}
}

Walk this variable, including fields, to construct sequence types
for any contained vlen dimensions

@param cdmvar variable to walk

Walk this variable including fields to construct sequence types for any contained vlen dimensions