Grid Metadata Tutorial

From OPeNDAP Documentation
⧼opendap2-jumptonavigation⧽

An Example of Adding Metadata to a Grid

Category:NCML

We will go through a basic example of adding metadata to all the possible scopes in a Grid variable:

  • The top-level Grid Structure itself
  • The data Array in the Grid
  • Each Map vector in the Grid

We will also modify the global dataset attribute container to elucidate the difference between an attribute Structure and a variable Structure.

Let's start with a "pass-through" NcML file which wraps a Netcdf dataset that Hyrax represents as a Grid. This will let us see the exact structure of the data we will want to modify (which may be slightly different than the wrapped dataset due to legacy issues with how shared dimensions are represented, etc):

<?xml version="1.0" encoding="UTF-8"?>
<netcdf location="data/ncml/agg/grids/f97182070958.hdf" title="This file results in a Grid">
<!-- This space intentionally left blank! -->
</netcdf>

This gives the DDS:

Dataset {
    Grid {
      Array:
        UInt32 dsp_band_1[lat = 1024][lon = 1024];
      Maps:
        Float64 lat[1024];
        Float64 lon[1024];
    } dsp_band_1;
} grid_attributes_2.ncml;

and the (extensive) DAS:

Attributes {
    HDF_GLOBAL {
        UInt16 dsp_SubImageId 0;
        String dsp_SubImageName "N/A";
        Int32 dsp_ModificationDate 20040416;
        Int32 dsp_ModificationTime 160521;
        Int32 dsp_SubImageFlag 64;
        String dsp_SubImageTitle "Ingested by SCRIPP";
        Int32 dsp_StartDate 19970701;
        Float32 dsp_StartTime 70958.5;
        Int32 dsp_SizeX 1024;
        Int32 dsp_SizeY 1024;
        Int32 dsp_OffsetX 0;
        Int32 dsp_RecordLength 2048;
        Byte dsp_DataOrganization 64;
        Byte dsp_NumberOfBands 1;
        String dsp_ing_tiros_ourid "NO14****C\\217\\345P?\\253\\205\\037";
        UInt16 dsp_ing_tiros_numscn 44305;
        UInt16 dsp_ing_tiros_idsat 2560;
        UInt16 dsp_ing_tiros_iddata 768;
        UInt16 dsp_ing_tiros_year 24832;
        UInt16 dsp_ing_tiros_daysmp 46592;
        Int32 dsp_ing_tiros_milsec 1235716353;
        Int32 dsp_ing_tiros_slope 1075636998, 551287046, -426777345, -1339034123, 5871604;
        Int32 dsp_ing_tiros_intcpt 514263295, 1892553983, -371365632, 9497638, -2140793044;
        UInt16 dsp_ing_tiros_tabadr 256, 512, 768;
        UInt16 dsp_ing_tiros_cnlins 256;
        UInt16 dsp_ing_tiros_cncols 256;
        UInt16 dsp_ing_tiros_czncs 8;
        UInt16 dsp_ing_tiros_line 256;
        UInt16 dsp_ing_tiros_icol 0;
        String dsp_ing_tiros_date0 "23-MAY-10 13:54:29\\030";
        String dsp_ing_tiros_time0 "13:54:29\\030";
        UInt16 dsp_ing_tiros_label 14112, 12576, 14137;
        UInt16 dsp_ing_tiros_nxtblk 1280;
        UInt16 dsp_ing_tiros_datblk 1280;
        UInt16 dsp_ing_tiros_itape 256;
        UInt16 dsp_ing_tiros_cbias 0;
        UInt16 dsp_ing_tiros_ccoeff 0;
        Int32 dsp_ing_tiros_pastim 1235716353;
        UInt16 dsp_ing_tiros_passcn 3840;
        UInt16 dsp_ing_tiros_lostct 0;
        UInt16 dsp_ing_tiros_lost 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
        UInt16 dsp_ing_tiros_ndrll 1280;
        UInt16 dsp_ing_tiros_ndrrec 3840, 5376, 6912, 8448, 9984, 0, 0, 0, 0, 0;
        UInt16 dsp_ing_tiros_ndrlat 46110, 44318, 42526, 40478, 38686, 0, 0, 0, 0, 0;
        UInt16 dsp_ing_tiros_ndrlon 49891, 48611, 47075, 45539, 44259, 0, 0, 0, 0, 0;
        UInt16 dsp_ing_tiros_chncnt 1280;
        UInt16 dsp_ing_tiros_chndsq 8, 8, 8, 8, 8;
        UInt16 dsp_ing_tiros_czncs2 4;
        UInt16 dsp_ing_tiros_wrdsiz 512;
        UInt16 dsp_ing_tiros_nchbas 256;
        UInt16 dsp_ing_tiros_nchlst 1280;
        Float32 dsp_ing_tiros_rpmclc 0;
        UInt16 dsp_ing_tiros_numpix 8;
        UInt16 dsp_ing_tiros_scnden 256;
        UInt16 dsp_ing_tiros_eltden 256;
        UInt16 dsp_ing_tiros_orbtno 23858;
        Int32 dsp_ing_tiros_slope2 1075636998, 551287046, -426777345, -1339034123, 5871604;
        Int32 dsp_ing_tiros_intcp2 514263295, 1892553983, -371365632, 9497638, -2140793044;
        Float32 dsp_ing_tiros_prtemp 3.0811e+10;
        Float32 dsp_ing_tiros_timerr 5.6611e-20;
        UInt16 dsp_ing_tiros_timstn 8279;
        String dsp_nav_xsatid "NO14\\005\\002";
        Byte dsp_nav_xsatty 5;
        Byte dsp_nav_xproty 2;
        Byte dsp_nav_xmapsl 0;
        Byte dsp_nav_xtmpch 4;
        Float32 dsp_nav_ximgdy 97182;
        Float32 dsp_nav_ximgtm 70954.4;
        Float32 dsp_nav_xorbit 12893;
        Float32 dsp_nav_ximgcv 71.1722, 0, 4.88181, 0, -112.11, 0, -27.9583, 0;
        Float32 dsp_nav_earth_linoff 0;
        Float32 dsp_nav_earth_pixoff 0;
        Float32 dsp_nav_earth_scnstr 1;
        Float32 dsp_nav_earth_scnstp 1024;
        Float32 dsp_nav_earth_pixstr 1;
        Float32 dsp_nav_earth_pixstp 1024;
        Float32 dsp_nav_earth_latorg 0;
        Float32 dsp_nav_earth_lonorg 0;
        Float32 dsp_nav_earth_orgrot 0;
        Float32 dsp_nav_earth_lattop 0;
        Float32 dsp_nav_earth_latbot 0;
        Float32 dsp_nav_earth_latcen 38;
        Float32 dsp_nav_earth_loncen -70;
        Float32 dsp_nav_earth_height 66.3444;
        Float32 dsp_nav_earth_width 84.2205;
        Float32 dsp_nav_earth_level 1;
        Float32 dsp_nav_earth_xspace 5.99902;
        Float32 dsp_nav_earth_yspace 5.99902;
        String dsp_nav_earth_rev " 0.1";
        Float32 dsp_nav_earth_dflag 0;
        Float32 dsp_nav_earth_toplat 71.1722;
        Float32 dsp_nav_earth_botlat 4.88181;
        Float32 dsp_nav_earth_leflon -112.11;
        Float32 dsp_nav_earth_ritlon -27.9583;
        Float32 dsp_nav_earth_numpix 1024;
        Float32 dsp_nav_earth_numras 1024;
        Float32 dsp_nav_earth_magxx 6;
        Float32 dsp_nav_earth_magyy 6;
        Int32 dsp_hgt_llnval 18;
        Int32 dsp_hgt_lltime 25744350;
        Float32 dsp_hgt_llvect 869.428, 1.14767, 868.659, 1.09635, 867.84, 1.04502, 866.979, 0.9937, 866.084, 0.942374, 865.165, 0.891045, 864.231, 0.839715, 863.292, 0.788383, 862.356, 0.737049, 861.434, 0.685714, 860.536, 0.634378, 859.67, 0.58304, 858.847, 0.531702, 858.075, 0.480362, 857.363, 0.429022, 856.718, 0.377682, 856.148, 0.326341, 855.66, 0.275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
        String history "\\001PATHNLC May 23 22:40:54 2000 PATHNLC t,3,269.16,0.125,0.,0.01,271.16,308.16,,,,1,,,2,,,3,,,,,,4,,,,,,,2.,,35.,0.1,5,,,,,,,2.,,35.,0.15,55.,80.,0.005,20,,,-2,6.,t,,,,,,,,,,16,,3.5 allb=0 nlsst=1 in=/pathfdr5//97182070958.N14@INGEST@ in1=/pathfdr10/mask/oi.9727.mean out=/pathfdr4/nlc/f97182070958.FMG@0\\012\\004PATHNLC  NLSST Temp calculation date: April 10, 1996\\012\\001OISST Jan 12 17:53:43 1998 OISST  /usr3/gacsst/maketc/oi/dinp/oi.comp.bias.1997,/usr3/gacsst/maketc/oi/dout/oi.97,-3.,0.15,oi.dates.97,0\\012\\004OISST 26 97 06 22 97 06 28  7        472\\012\\001STATS Jan 12 18:27:34 1998 STATS minpix=1 maxpix=255 in=/usr3/gacsst/maketc/oi/dout//oi.9726 \\011  audit=t, callim=f, cal=f, cloud=f \\011  outm=/usr3/gacsst/etc/oi/oi.9727.mean\\012\\001OISST Jan 12 17:53:43 1998 OISST  /usr3/gacsst/maketc/oi/dinp/oi.comp.bias.1997,/usr3/gacsst/maketc/oi/dout/oi.97,-3.,0.15,oi.dates.97,0\\012\\004OISST 27 97 06 29 97 07 05  7        472\\012\\002STATS /usr3/gacsst/maketc/oi/dout//oi.9727\\012\\001OISST Jan 12 17:53:43 1998 OISST  /usr3/gacsst/maketc/oi/dinp/oi.comp.bias.1997,/usr3/gacsst/maketc/oi/dout/oi.97,-3.,0.15,oi.dates.97,0\\012\\004OISST 27 97 06 29 97 07 05  7        472\\012\\002STATS /usr3/gacsst/maketc/oi/dout//oi.9727\\012\\001OISST Jan 12 17:53:43 1998 OISST  /usr3/gacsst/maketc/oi/dinp/oi.comp.bias.1997,/usr3/gacsst/maketc/oi/dout/oi.97,-3.,0.15,oi.dates.97,0\\012\\004OISST 28 97 07 06 97 07 12  7        472\\012\\002STATS /usr3/gacsst/maketc/oi/dout//oi.9728\\012\\002PATHNLC /pathfdr10/mask/oi.9727.mean\\012\\004PATHNLC  45d coeffs used (1) =    0.759   0.947   0.110   1.460   0.000\\012\\004PATHNLC  45d coeffs used (2) =    1.320   0.952   0.071   0.882   0.000\\012\\004PATHNLC  45d coeffs used (3) =    0.000   0.000   0.000   0.000   0.000\\012\\004PATHNLC  GETOZONE I     0.0900    0.0000\\012\\001REMAP Jun  4 07:59:42 2000 REMAP in=/coral/miami/remaps/sst_8r/file_uZ.FMG out=/coral/miami/remaps/sst_8r/f97182070958.nwa16\\012\\004REMAP Output image pixel, line size =    6144,    6144\\012\\004REMAP Grid spacing (X,Y) = (        6.00,        6.00), Projection Code=     1\\012\\004REMAP center lon,lat,dlon,dlat =       -70.00       38.00        0.01        0.01\\012\\001merge_sb Apr 16 16:05:09 2004 merge_sb in=(file=/NOPP/carlw/atlantic/remaps/nwa16/f97182070958.nwa16, filecheck=/RAID2/sbaker/atlantic/bslines97/f97182070958.nwa16) val=0 valcheck=0 tag=0 out=(file1=/RAID2/sbaker/nwa1024d/NDC/dsp_data/f97182070958.tmp_m2)\\012\\001merge_sb Apr 16 16:05:18 2004 merge_sb in=(file=/RAID2/sbaker/nwa1024d/NDC/dsp_data/f97182070958.tmp_m2, filecheck=/RAID/sbaker/DECLOUD/landmask16.img) val=1 valcheck=2 tag=0 out=(file1=/RAID2/sbaker/nwa6144d/NDC/dsp_data/f97182070958.nwa16)\\012\\001CONVRT Apr 16 16:05:21 2004 CONVRT 1024,1024,0,0,6,6,0,0,f,f,t,16,,SUB,1 in=/RAID2/sbaker/nwa6144d/NDC/dsp_data/f97182070958.nwa16   out=/RAID2/sbaker/nwa1024d/NDC/dsp_data/f97182070958.nwa16\\012\\012@\\000\\000\\000";
    }
    dsp_band_1 {
        Byte dsp_PixelType 1;
        Byte dsp_PixelSize 2;
        UInt16 dsp_Flag 0;
        UInt16 dsp_nBits 16;
        Int32 dsp_LineSize 0;
        String dsp_cal_name "Temperature";
        String units "Temp";
        UInt16 dsp_cal_eqnNumber 2;
        UInt16 dsp_cal_CoeffsLength 8;
        Float32 dsp_cal_coeffs 0.125, -4;
        Float32 scale_factor 0.125;
        Float32 add_off -4;
        dsp_band_1 {
        }
        lat {
            String name "lat";
            String long_name "latitude";
        }
        lon {
            String name "lon";
            String long_name "longitude";
        }
    }
}

Let's say we want to add the following attributes:

  1. Add an attribute to the HDF_GLOBAL attribute container called "ncml_location" since the file is wrapped by our NcML and the original location being wrapped might not be obvious.
  2. Add the same attribute to the dsp_band_1 Grid itself so it's easier to see and in case of projections
  3. Add "units" to the Array member variable dsp_band_1 of the Grid that matches the containing Grid's "units" attribute with value "Temp"
  4. Add "units" to the lat map vector as a String with value "degrees_north"
  5. Add "units" to the lon map vector as a String with value "degrees_east"

First, let's add the "ncml_location" into the HDF_GLOBAL attribute container. To do this, we need to specify the "scope" of the HDF_GLOBAL attribute container (called a Structure in NcML):

<?xml version="1.0" encoding="UTF-8"?>
<netcdf location="data/ncml/agg/grids/f97182070958.hdf" title="This file results in a Grid">

  <!-- Traverse into the HDF_GLOBAL attribute Structure (container) -->
  <attribute name="HDF_GLOBAL" type="Structure">
    <!-- Specify the new attribute in that scope -->
1)  <attribute name="ncml_location" type="String" value="data/ncml/agg/grids/f97182070958.hdf"/>
  </attribute>
  
</netcdf>

This results in the following (clipped for clarity) DAS:

Attributes {
    HDF_GLOBAL {
        UInt16 dsp_SubImageId 0;
        ... *** CLIPPED FOR CLARITY ***  ...
1)    String ncml_location "data/ncml/agg/grids/f97182070958.hdf";
    }
    dsp_band_1 {
        Byte dsp_PixelType 1;
        Byte dsp_PixelSize 2;
        UInt16 dsp_Flag 0;
        UInt16 dsp_nBits 16;
        Int32 dsp_LineSize 0;
        String dsp_cal_name "Temperature";
        String units "Temp";
        UInt16 dsp_cal_eqnNumber 2;
        UInt16 dsp_cal_CoeffsLength 8;
        Float32 dsp_cal_coeffs 0.125, -4;
        Float32 scale_factor 0.125;
        Float32 add_off -4;
        dsp_band_1 {
        }
        lat {
            String name "lat";
            String long_name "latitude";
        }
        lon {
            String name "lon";
            String long_name "longitude";
        }
    }
}

We can see at the 1) where the new attribute has been added to HDF_GLOBAL as desired.

Next, we want to add the same attribute to the top-level dsp_band_1 Grid variable. Here's the NcML:

<?xml version="1.0" encoding="UTF-8"?>
<netcdf location="data/ncml/agg/grids/f97182070958.hdf" title="This file results in a Grid">

  <!-- Traverse into the HDF_GLOBAL attribute Structure (container) -->
 <attribute name="HDF_GLOBAL" type="Structure">
   <!-- Specify the new attribute in that scope -->
   <attribute name="ncml_location" type="String" value="data/ncml/agg/grids/f97182070958.hdf"/>
 </attribute>

 <!-- Traverse into the dsp_band_1 variable Structure (actually a Grid) -->
 <variable name="dsp_band_1" type="Structure">
   <!-- Specify the new attribute in that scope -->
2) <attribute name="ncml_location" type="String" value="data/ncml/agg/grids/f97182070958.hdf"/>
 </variable>
  
</netcdf>

which gives the (clipped again) DAS:

Attributes {
    HDF_GLOBAL {
       ... *** CLIPPED FOR CLARITY *** ...
        String ncml_location "data/ncml/agg/grids/f97182070958.hdf";
    }
    dsp_band_1 {
        Byte dsp_PixelType 1;
        Byte dsp_PixelSize 2;
        UInt16 dsp_Flag 0;
        UInt16 dsp_nBits 16;
        Int32 dsp_LineSize 0;
        String dsp_cal_name "Temperature";
        String units "Temp";
        UInt16 dsp_cal_eqnNumber 2;
        UInt16 dsp_cal_CoeffsLength 8;
        Float32 dsp_cal_coeffs 0.125, -4;
        Float32 scale_factor 0.125;
        Float32 add_off -4;
2)    String ncml_location "data/ncml/agg/grids/f97182070958.hdf";
        dsp_band_1 {
        }
        lat {
            String name "lat";
            String long_name "latitude";
        }
        lon {
            String name "lon";
            String long_name "longitude";
        }
    }
}

We have denoted the injected metadata with a 2).

As a learning exercise, let's say we made a mistake and tried to use <attribute> to specify the dsp_band_1 attribute table:

<?xml version="1.0" encoding="UTF-8"?>
<netcdf location="data/ncml/agg/grids/f97182070958.hdf" title="This file results in a Grid">

  <!-- Traverse into the HDF_GLOBAL attribute Structure (container) -->
 <attribute name="HDF_GLOBAL" type="Structure">
   <!-- Specify the new attribute in that scope -->
   <attribute name="ncml_location" type="String" value="data/ncml/agg/grids/f97182070958.hdf"/>
 </attribute>

 <!-- THIS IS AN ERROR! -->
 <attribute name="dsp_band_1" type="Structure">
   <!-- Specify the new attribute in that scope -->
   <attribute name="ncml_location" type="String" value="data/ncml/agg/grids/f97182070958.hdf"/>
 </attribute>
  
</netcdf>

Then we get a Parse Error:

<?xml version="1.0" encoding="ISO-8859-1"?>
<response xmlns="http://xml.opendap.org/ns/bes/1.0#" reqID="some_unique_value">
  <getDAS>
      <BESError><Type>3</Type>
           <Message>NCMLModule ParseError: at line 11: Cannot create a new attribute container with name=dsp_band_1 at current scope since a variable with that name already exists.  Scope=</Message>
           <Administrator>admin.email.address@your.domain.name</Administrator><Location><File>AttributeElement.cc</File><Line>277</Line></Location>
      </BESError>
   </getDAS>
</response>

which basically tells us the problem: we tried to specify an attribute with the same name as the Grid, but dsp_band_1 is a variable already with that name. It is illegal for an attribute and variable at the same scope to have the same name.

Next, we want to add the "units" attribute that is on the Grid itself to the actual data Array inside the Grid (say we know we will be projecting it out with a constraint and don't want to lose this metadata). The NcML now becomes:

<?xml version="1.0" encoding="UTF-8"?>
<netcdf location="data/ncml/agg/grids/f97182070958.hdf" title="This file results in a Grid">

  <!-- Traverse into the HDF_GLOBAL attribute Structure (container) -->
 <attribute name="HDF_GLOBAL" type="Structure">
   <!-- Specify the new attribute in that scope -->
   <attribute name="ncml_location" type="String" value="data/ncml/agg/grids/f97182070958.hdf"/>
 </attribute>

 <!-- Traverse into the dsp_band_1 variable Structure (actually a Grid) -->
 <variable name="dsp_band_1" type="Structure">

   <!-- Specify the new attribute in the Grid's attribute table -->
   <attribute name="ncml_location" type="String" value="data/ncml/agg/grids/f97182070958.hdf"/>

   <!-- While remaining in the Grid, traverse into the Array dsp_band_1: -->
   <variable name="dsp_band_1">
     <!-- And add the attribute there.  Fully qualified name of this scope is "dsp_band_1.dsp_band_1" -->
3)   <attribute name="units" type="String" value="Temp"/>
   </variable> <!-- Exit the Array variable scope, back to the Grid level -->

 </variable>
  
</netcdf>

Our modified DAS is now:

Attributes {
    HDF_GLOBAL {
       ... *** CLIPPED FOR CLARITY *** ...
        String ncml_location "data/ncml/agg/grids/f97182070958.hdf";
    }
    dsp_band_1 {
        Byte dsp_PixelType 1;
        Byte dsp_PixelSize 2;
        UInt16 dsp_Flag 0;
        UInt16 dsp_nBits 16;
        Int32 dsp_LineSize 0;
        String dsp_cal_name "Temperature";
        String units "Temp";
        UInt16 dsp_cal_eqnNumber 2;
        UInt16 dsp_cal_CoeffsLength 8;
        Float32 dsp_cal_coeffs 0.125, -4;
        Float32 scale_factor 0.125;
        Float32 add_off -4;
        String ncml_location "data/ncml/agg/grids/f97182070958.hdf";
        dsp_band_1 {
3)        String units "Temp";
        }
        lat {
            String name "lat";
            String long_name "latitude";
        }
        lon {
            String name "lon";
            String long_name "longitude";
        }
    }
}

where the 3) denotes the newly injected metadata on dsp_band_1.dsp_band_1.

Next, we will add the units to both of the map vectors in the next version of our NcML:

<?xml version="1.0" encoding="UTF-8"?>
<netcdf location="data/ncml/agg/grids/f97182070958.hdf" title="This file results in a Grid">

  <!-- Traverse into the HDF_GLOBAL attribute Structure (container) -->
 <attribute name="HDF_GLOBAL" type="Structure">
   <!-- Specify the new attribute in that scope -->
   <attribute name="ncml_location" type="String" value="data/ncml/agg/grids/f97182070958.hdf"/>
 </attribute>

 <!-- Traverse into the dsp_band_1 variable Structure (actually a Grid) -->
 <variable name="dsp_band_1" type="Structure">

   <!-- Specify the new attribute in the Grid's attribute table -->
   <attribute name="ncml_location" type="String" value="data/ncml/agg/grids/f97182070958.hdf"/>

   <!-- While remaining in the Grid, traverse into the Array dsp_band_1: -->
   <variable name="dsp_band_1">
     <!-- And add the attribute there.  Fully qualified name of this scope is "dsp_band_1.dsp_band_1" -->
     <attribute name="units" type="String" value="Temp"/>
   </variable> <!-- Exit the Array variable scope, back to the Grid level -->

   <!-- Traverse into the lat map vector variable -->
   <variable name="lat">
     <!-- Add the units -->
4)   <attribute name="units" type="String" value="degrees_north"/>
   </variable>
   
   <!-- Traverse into the lon map vector variable -->
   <variable name="lon">
     <!-- Add the units -->
5)   <attribute name="units" type="String" value="degrees_east"/>
   </variable>

 </variable>
  
</netcdf>

where we denote the changed with 4) and 5). Here's the resulting DAS:

Attributes {
    HDF_GLOBAL {
        ... *** CLIPPED FOR CLARITY *** ...
1)      String ncml_location "data/ncml/agg/grids/f97182070958.hdf";
    }
    dsp_band_1 {
        Byte dsp_PixelType 1;
        Byte dsp_PixelSize 2;
        UInt16 dsp_Flag 0;
        UInt16 dsp_nBits 16;
        Int32 dsp_LineSize 0;
        String dsp_cal_name "Temperature";
        String units "Temp";
        UInt16 dsp_cal_eqnNumber 2;
        UInt16 dsp_cal_CoeffsLength 8;
        Float32 dsp_cal_coeffs 0.125, -4;
        Float32 scale_factor 0.125;
        Float32 add_off -4;
2)       String ncml_location "data/ncml/agg/grids/f97182070958.hdf";
        dsp_band_1 {
3)          String units "Temp";
        }
        lat {
            String name "lat";
            String long_name "latitude";
4)          String units "degrees_north";
        }
        lon {
            String name "lon";
            String long_name "longitude";
5)          String units "degrees_east";
        }
    }
}

where we have marked all the new metadata we have injected, including the new attributes on the map vectors.

Although we added metadata to the Grid, it is possible to also use the other forms of <attribute> in order to modify existing attributes or remove unwanted or incorrect attributes.

The only place where this syntax varies slightly is in adding metadata to an aggregated Grid. Please see the tutorial section on aggregating grids for more information.