This page documents the vertical coordinate transforms that are standard in CDM. These follow the CF-1.0 Convention, where they are called Dimensionless Vertical Coordinates. The purpose of a vertical transform is to define a function to calculate the pressure or height coordinate of each grid point in a data variable. This typically creates a 3D vertical coordinate, one which varies at each grid point. The dimensionless vertical coordinate in contrast, is 1 dimensional, and thus easier to work with and smaller to store in the file.

To follow CF, typically one adds transform information to the vertical coordinate, for example:

``````double s_rho(s_rho=20);
:long_name = "S-coordinate at RHO-points";
:valid_min = -1.0; // double
:valid_max = 0.0; // double

:standard_name = "ocean_s_coordinate";
:positive = "up";
:formula_terms = "s: s_rho eta: zeta depth: h a: theta_s b: theta_b depth_c: hc";
``````

This example is a CF `ocean_s_coordinate` vertical coordinate. The formula terms, explained in the CF doc, point to variables in the same file, which the calculation needs:

``````Definition:
z(n,k,j,i) = eta(n,j,i)*(1+s(k)) + depth_c*s(k) +  (depth(j,i)-depth_c)*C(k)
``````

So in this example, anywhere you see `s(k)` in the definition, one uses the variable `s_rho` in the calculation. Similarly for the rest:

``````Definition term    actual variable name
---------------    -------------------
s           s_rho
eta           zeta
depth         h
a           theta_s
b           theta_b
depth_c         hc
``````

All of these variables must exist in your file, and be the proper dimension etc, as spelled out in the CF doc. Note that the file writer must construct the `formula_terms` attribute with the correct variable names. The CDM, as well as other software that implements this part of the CF spec, will use the above information to calculate the 3D vertical coordinate.

This 3D vertical coordinate can be obtained in the CDM library by opening the file as a `NetcdfDataset`, and examining the `CoordinateSystem` attached to each `VariableDS`. Use `GridCoordinateSystem.getVerticalTransform()` to find a vertical transform (class `ucar.nc2.geoloc.vertical.VerticalTransform`). For performance, the actual work is done by `VerticalTransform.getCoordinateArray3D()` to get the 3D coordinate array.

To summarize, in order for CF Vertical transforms to work in the CDM, you must:

• Add the `standard_name`, `positive`, and `formula_terms` attributes to the vertical ccoordinate.
• Add to your file all the variables required by the transform definition.
• If you are writing your own software that needs the 3D pressure/height values, follow the above steps to retrieve the 3D vertical coordinate.

## Standard Vertical Transforms

Attribute names follow the CF Conventions Appendix D (Vertical Transforms)) and Appendix F (Grid Mappings). See that document for details on the meanings of the formula terms.

These are examples of placing the Coordinate Transform parameters on the corresponding vertical coordinate (required by CF). If you are using CF Conventions, you do not have to add the _Coordinate attributes, as they will be added automatically in the CoordSysBuilder.

### atmosphere_ln_pressure_coordinate

``````double levCoord(levCoord=26);
:long_name = "log pressure levels";
:units = "";
:positive = "down";
:standard_name = "atmosphere_ln_pressure_coordinate";
:formula_terms = "p0: P0 lev: levCoord";
``````

atmosphere_ln_pressure_coordinate transform only works in CF Conventions. Required attributes: `standard_name`, `formula_terms`

### atmosphere_hybrid_height_coordinate

``````double lev(lev=26);
:long_name = "hybrid hybrid height coordinate";
:units = "m";
:positive = "up";
:standard_name = "atmosphere_hybrid_height_coordinate";
:formula_terms = "a: varA b: varB orog: orography";
:_CoordinateAxisType = "GeoZ";
:_CoordinateZisPositive = "up;
:_CoordinateTransformType = "Vertical";
:_CoordinateAxes = "lev";
``````

Required attributes: `standard_name`, `formula_terms`, `_CoordinateTransformType`, `_CoordinateAxes`

### atmosphere_hybrid_sigma_pressure_coordinate

``````double lev(lev=26);
:long_name = "hybrid level at midpoints (1000*(A+B))";
:units = "";
:positive = "down";
:standard_name = "atmosphere_hybrid_sigma_pressure_coordinate";
:formula_terms = "a: hyam b: hybm p0: P0 ps: PS";
:_CoordinateAxisType = "GeoZ";
:_CoordinateZisPositive = "down;
:_CoordinateTransformType = "Vertical";
:_CoordinateAxes = "lev";
``````

Required attributes: `standard_name`, `formula_terms`, `_CoordinateTransformType`, `_CoordinateAxes`

or

``````double lev(lev=26);
:long_name = "hybrid level at midpoints (1000*(A+B))";
:units = "";
:positive = "down";
:standard_name = "atmosphere_hybrid_sigma_pressure_coordinate";
:formula_terms = "ap: hyam b: hybm p0: P0";
:_CoordinateAxisType = "GeoZ";
:_CoordinateZisPositive = "down;
:_CoordinateTransformType = "Vertical";
:_CoordinateAxes = "lev";
``````

Required attributes: `standard_name`, `formula_terms`, `_CoordinateTransformType`, `_CoordinateAxes`

### atmosphere_sigma_coordinate

``````float level(level=2);
:units = "";
:long_name = "sigma at layer midpoints";
:positive = "down";
:standard_name = "atmosphere_sigma_coordinate";
:formula_terms = "sigma: level ps: PS ptop: PTOP";
:_CoordinateAxisType = "GeoZ";
:_CoordinateZisPositive = "down";
:_CoordinateTransformType = "Vertical";
:_CoordinateAxes = "level";
``````

Required attributes: `standard_name`, `formula_terms`, `_CoordinateTransformType`, `_CoordinateAxes`

### ocean_s_coordinate

``````double s_rho(s_rho=20);
:long_name = "S-coordinate at RHO-points";
:units = "";
:positive = "up";
:standard_name = "ocean_s_coordinate";
:formula_terms = "s: s_rho eta: zeta depth: h a: theta_s b: theta_b depth_c: hc";
:_CoordinateAxisType = "GeoZ";
:_CoordinateZisPositive = "up";
:_CoordinateTransformType = "Vertical";
:_CoordinateAxes = "s_rho";
``````

Required attributes: `standard_name`, `formula_terms`, `_CoordinateTransformType`, `_CoordinateAxes`

### ocean_s_coordinate_g1

``````char OceanSG1_Transform_s_rho;
:standard_name = "ocean_s_coordinate_g1";
:formula_terms = "s: s_rho C: Cs_r eta: zeta depth: h depth_c: hc";
:height_formula = "height(x,y,z) =  depth_c*s(z) + (depth([n],x,y)-depth_c)*C(z) + eta(x,y)*(1+(depth_c*s(z) + (depth([n],x,y)-depth_c)*C(z))/depth([n],x,y))";
:Eta_variableName = "zeta";
:S_variableName = "s_rho";
:Depth_variableName = "h";
:Depth_c_variableName = "hc";
:c_variableName = "Cs_r";
``````

Required attributes: `standard_name`, `formula_terms` The other are added for extra readability.

### ocean_s_coordinate_g2

``````char OceanSG2_Transform_s_rho;
:standard_name = "ocean_s_coordinate_g2";
:formula_terms = "s: s_rho C: Cs_r eta: zeta depth: h depth_c: hc";
:height_formula = "height(x,y,z) = eta(x,y) + (eta(x,y) + depth([n],x,y)) * ((depth_c*s(z) + depth([n],x,y)*C(z))/(depth_c+depth([n],x,y)))";
:Eta_variableName = "zeta";
:S_variableName = "s_rho";
:Depth_variableName = "h";
:Depth_c_variableName = "hc";
:c_variableName = "Cs_r";
``````

Required attributes: `standard_name`, `formula_terms`. The other are added for extra readability.

### ocean_sigma_coordinate

``````float zpos(zpos=22);
:long_name = "Sigma Layer";
:units = "";
:positive = "up";
:standard_name = "ocean_sigma_coordinate";
:formula_terms = "sigma: zpos eta: elev depth: depth";
:_CoordinateAxisType = "GeoZ";
:_CoordinateZisPositive = "up";
:_CoordinateTransformType = "Vertical";
:_CoordinateAxes = "zpos";
``````

Required attributes: `standard_name`, `formula_terms`, `_CoordinateTransformType`, `_CoordinateAxes`

### explicit_field

``````char ExplicitField;
:standard_name = "explicit_field";  // canonical transform name
:existingDataField = "ght_hybr";  // must be a 3 or 4D pressure / height / geopotential height field
:_CoordinateTransformType = "vertical"; // unambiguouly identifies it as vertical transform
:_CoordinateAxes = "hybr"; // attach transform to any coord sys with the "hbyr" axis.
``````

Required attributes: `standard_name`, `existingDataField`, `_CoordinateTransformType`, `_CoordinateAxes` This is not part of CF, but a way to mark an existing 3D (4D if time dependent) field as the vertical coordinate.

## Using Vertical Transforms

``````public void testAtmHybrid() throws java.io.IOException, InvalidRangeException {
try (NetcdfDataset gds = NetcdfDatasets.openDataset(TestDir.cdmUnitTestDir + "conventions/cf/ccsm2.nc")) {
System.out.printf("openDataset %s%n", gds.getLocation());

VariableDS vds = (VariableDS) gds.findVariable("T");
assertThat(vds).isNotNull();
assertThat(vds.getShape()).isEqualTo(new int[] {1, 26, 64, 128});

CoordinateSystem cs = vds.getCoordinateSystems().get(0);
assertThat(cs).isNotNull();

VerticalCT vct = cs.getVerticalCT();
assertThat(vct).isNotNull();
assertThat(vct.getVerticalTransformType()).isEqualTo(VerticalCT.Type.HybridSigmaPressure);

VerticalTransform vt = vct.makeVerticalTransform(gds, null);
assertThat(vt).isNotNull();

ArrayDouble.D3 ca = vt.getCoordinateArray(0);
assertThat(ca).isNotNull();
assertThat(ca.getShape()).isEqualTo(new int[] {26, 64, 128});
}
}
``````