<h1>tl;dr</h1>

<p>I would suggest considering the borehole measurements as a vertical profile. In terms of the CF Convention it would be a <code>featureType</code> <a href="http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#profile-data" rel="nofollow noreferrer"><code>profile</code></a>, which is described in the <a href="http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#discrete-sampling-geometries" rel="nofollow noreferrer">discrete sampling geometries section</a>.</p>

<p>I didn't include all reference to the relevant sections in the CF Conventions below. Just comment if import things are missing.</p>

<h1>Example netCDF</h1>

<pre><code>netcdf borehole_01 {
dimensions:
      z = 8 ;
      profile = 1 ;
      nv = 2 ;

variables:
    int profile(profile) ;
          profile:cf_role = "profile_id";
    double time(profile);
        time:standard_name = "time";
        time:long_name = "time" ;
        time:units = "days since 1970-01-01 00:00:00" ;
    float lon(profile);
        lon:standard_name = "longitude";
        lon:long_name = "longitude" ;
        lon:units = "degrees_east" ;
    float lat(profile);
        lat:standard_name = "latitude";
        lat:long_name = "latitude" ;
        lat:units = "degrees_north" ;
    float z(z) ;
        z:standard_name = "depth";
        z:long_name = "depth below ..." ;
        z:units = "m" ;
        z:positive = "down" ;
        z:axis = "Z" ;
        z:bounds = "z_bnds" ;
    float z_bnds(z, nv) ;
    float temp(profile, z) ;
        temp:standard_name = "soil_temperature" ;
        temp:long_name = "soil_temperature" ;
        temp:units = "K" ;
        temp:coordinates = "time lon lat z" ;
        temp:cell_methods = "z: mean" ;

// global attributes:
        :featureType = "profile";

data:

 z = 5, 15, 25, 45, 55, 70, 90, 150 ;

 z_bnds = 
  0, 10,
  10, 20,
  20, 30,
  40, 50,
  50, 60, 
  60, 80,
  80, 100,
  100, 200 ;

 temp = 279.4, 278.8, 278.3, 277.0, 277.1, 276.9, 277.0, 279.2 ;
}
</code></pre>

<h1>Explanation</h1>

<p>The variable <code>temp</code> is an example for a data variable in the file.</p>

<h2>Basic depth information</h2>

<p><em>Please see CF Conventions section <a href="http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#cell-boundaries" rel="nofollow noreferrer">7.1 Cell Boundaries</a> for details</em>.</p>

<p><code>z_bnds</code> provides the boundaries of intervals over which the temperature is averaged. The attribute <code>bounds</code> of variable <code>z</code> points to these boundary data. In this example, I wrote the average depth of each interval into the <code>z</code> variable. However, this is no requirement (as far as I know). It might be also the upper or lower depth of each interval or another depth in between. <code>z_bnds</code> automatically inherits all relevant attributs from <code>z</code>. Therefore, it has no own <code>units</code> and <code>standard_name</code> attributes. </p>

<p>As you can see in the data for <code>z_bnds</code> (or in the table below), it is possible to skip depth ranges (between depth invertal 3 and 4) and to have differently spaced intervals (e.g. interval 6 compared to previous intervals).</p>

<pre><code>| **depth interval** | **minimum** | **maximum** |
|--------------------|-------------|-------------|
| 1                  | 0           | 10          |
| 2                  | 10          | 20          |
| 3                  | 20          | *30*        |
| 4                  | *40*        | 50          |
| 5                  | 50          | 60          |
| 6                  | *60*        | *80*        |
| 7                  | 80          | 100         |
| 8                  | 100         | 200         |
</code></pre>

<h2>Connecting data variables proberly to the vertical coordinate</h2>

<p><em>Please see CF Conventions section <a href="http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#cell-methods" rel="nofollow noreferrer">7.3 Cell Methods</a> for details on the first paragraph and section <a href="http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#_two_dimensional_latitude_longitude_coordinate_variables" rel="nofollow noreferrer">5.2 Two-Dimensional Latitude, Longitude, Coordinate Variables</a> for details on the second paragraph.</em></p>

<p>The value <code>z: mean</code> of the attribute <code>cell_methods</code> of variable <code>temp</code> tells us that the temperature is an average value in z-direction over the interval provided in <code>z_bnds</code>. The latter (<em>over the interval provided in <code>z_bnds</code></em>) is implicitely assumed.</p>

<p>The value <code>time lon lat z</code> of the <code>coordinates</code> attribute of variable <code>temp</code> indicates that the variables <code>time</code>, <code>lon</code>, <code>lat</code> and <code>z</code> provided temporal and spatial dimensions to each value of <code>temp</code>. Really proper software should be able to map each value of <code>temp</code> a the correspondinc <code>time</code>, <code>lat</code> and <code>lon</code> values via the dimension <code>profile</code>. However, implementing this properly is hard work. Therefore, most software package won't recognize it or might even have issues with it. I your software package throws errors, one first step should be to remove the attribute <code>coordinates</code>.</p>

<h2>Setting global attributes</h2>

<p><em>Please see CF Conventions section <a href="http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#_features_and_feature_types" rel="nofollow noreferrer">Features and feature types</a> for details</em></p>

<p>The global attribute <code>featureType</code> is mandatory when we have a discret sampling geometry.</p>

<h2>Several boreholes with different depth intervals</h2>

<p><em>For details on <code>coordinate variables</code> and <code>auxiliary coordinate variables</code> please have a look into sections <a href="http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#terminology" rel="nofollow noreferrer">1.2 Terminology</a> and <a href="http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#coordinate-system" rel="nofollow noreferrer">5 Coordinate System</a></em></p>

<p>Via the dimension <code>profile</code> we could save several boreholes in one file. In the current situation, the samplings depths of each borehole would be the same. One could make the variable <code>z</code> and <code>z_bnds</code> dependent on <code>profile</code> to provide depth intervals for each borehole. However, then we needed to rename the variables <code>z</code> and <code>z_bnds</code> because a variable might only have the same name of a dimension, if the variable is onedimensional and only depends on this dimension (a <code>coordiante variable</code>). When a variable like the depth depends on two dimensions, it becomes and auxiliary coordinate variable and has to have a different names. Thus, we would have <code>double depth(profile, z)</code> instead of <code>z(z)</code> and <code>double depth_bnds(profile, z, nv)</code> instead of <code>z_bnds(z, nv)</code>. The <code>temp:coordiantes</code> would have a value of <code>time lat lon depth</code> (because <code>depth</code> is the vertical coordinates) but <code>temp:cell_methods</code> would remain <code>z: mean</code> (because we calculate average in z-direction).</p>

CC BY-SA 4.0
2020-03-27T19:13:20.317Z
Great answer. I wonder if there is a way to take advantage of the standard_name:  `thickness_of_soil_layer` to make it more interoperable by using the conventions. The one example I was able to find (also in a soils context) did this: http://www2.nrel.colostate.edu/projects/irc/public/Documents/Software/Century5/Reference/html/Century/SoilsNetCDFFile.htm. However, I like that the bounds are explicitly stated the way you have it so they don't need to be recomputed.
alex_danielssen
CC BY-SA 4.0
2020-03-28T19:52:26.960Z
@alex_danielssen Thanks for the feedback. `thickness_of_soil_layer` doesn't seem to be in the official [standard name list](http://cfconventions.org/Data/cf-standard-names/72/build/cf-standard-name-table.html) but was used as `standard_name` in some data sets like [this one](http://www2.nrel.colostate.edu/projects/irc/public/Documents/Software/Century5/Reference/html/Century/SoilsNetCDFFile.htm). To be CF-compliant only standard names of the official standard name list are allowed to be used. One can use the `long_name` attribute to set a name, that might be a standard name but isn't.
daniel.heydebreck
CC BY-SA 4.0
2020-03-28T19:53:28.150Z
New standard names can be proposed at the [CF Conventions discussion GitHub repository](https://github.com/cf-convention/discuss).
daniel.heydebreck
CC BY-SA 4.0
2020-03-28T19:59:50.237Z
Based on my personal feeling and on [this dataset](http://www2.nrel.colostate.edu/projects/irc/public/Documents/Software/Century5/Reference/html/Century/SoilsNetCDFFile.htm) I think that `thickness_of_soil_layer` means something else than the thickness of several vertical layers in the ground. `soil_layer` means the layer where plants can grow -- where we actually have *soil* as described in its [Wikipedia article](https://en.wikipedia.org/wiki/Soil). `thickness_of_soil_layer` is the thinkness of the layer in which plants etc. can grow/live. This variable should have no vertical dimension.
daniel.heydebreck
CC BY-SA 4.0
2020-08-11T21:04:44.727Z
You are correct about `thickness_of_soil_layer` not being in the CF standard names, but I disagree about the usage of `soil_layer` in CF.  Consider that the standard name `frozen_water_content_of_soil_layer` defines "Layer" as `any layer with upper and lower boundaries that have constant values in some vertical coordinate`. Also that `Quantities defined for a soil layer must have a vertical coordinate variable`. My interpretation of that dataset is that the layer dimension refers to the vertical index of vertically-stacked soil layers.
alex_danielssen
CC BY-SA 4.0
2020-09-01T07:59:17.193Z
@alex_danielssen I agree with you after reading the definition of `frozen_water_content_of_soil_layer`. Sould the CDL example be updated somehow?
daniel.heydebreck
CC BY-SA 4.0
2020-03-27T18:39:44.197Z
2020-03-27T18:39:44.197Z
daniel.heydebreck
<p>I have a number of datasets that describe geological properties as intervals down a borehole (e.g. unit codes, sample results)</p>

<p>In a database, or a flat ASCII file, I would describe these with a <code>from</code> and a <code>to</code> column, and then have a column for each observation type.</p>

<p>What (if any) is the guidance for storing this kind of data that represents an <em>interval</em> within a netCDF. I've checked the <a href="http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#_description_of_the_data" rel="nofollow noreferrer">CF Conventions</a>, notably the section on discrete sampling geometries but haven't been able to find anything. </p>

<p>The more I think about it, intuitively, it seems like the wrong file format but maybe I'm wrong.</p>

CC BY-SA 4.0
2020-03-26T08:15:52.507Z
For clarification: I mean variable `XY` has a value of `5.2` from `0m` to `10m`, a value of `4.9` from `10m` to `20m`, a value of ... from `20m` to `30m` and so on? Is it one borehole per file or several borehols per file? Do you need different time steps?
daniel.heydebreck
CC BY-SA 4.0
2020-03-26T14:15:49.110Z
Your clarification is correct. With the added complication that there may be some intervals with no sampling information (although this could just have a nodata value). I would be open to one or multiple boreholes per file, but am primarily looking for existing best practices, so in a way, it would depend on that. Time steps are not essential but may come in handy.
alex_danielssen
CC BY-SA 4.0
2020-03-26T19:10:49.343Z
The `featureType` [profile](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#profile-data) seems to be reasonable for your case. To indicate the boundaries, you insert a variable `z_bnds` that contains the boundaries of the cells. I will post an answer later on or tomorrow.
daniel.heydebreck
<geology><geography><data-formats><netcdf>
Storing borehole interval data (logs) in netcdf
alex_danielssen
# Storing borehole interval data (logs) in netcdf

(Asked by: username_0 on 2020-03-25)

I have a number of datasets that describe geological properties as intervals down a borehole (e.g. unit codes, sample results)

In a database, or a flat ASCII file, I would describe these with a `from` and a `to` column, and then have a column for each observation type.

What (if any) is the guidance for storing this kind of data that represents an *interval* within a netCDF. I've checked the [CF Conventions](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#_description_of_the_data), notably the section on discrete sampling geometries but haven't been able to find anything.

The more I think about it, intuitively, it seems like the wrong file format but maybe I'm wrong.

**Tags:** geology, geography, data-formats, netcdf

> **Comments:**
> **username_1**: For clarification: I mean variable `XY` has a value of `5.2` from `0m` to `10m`, a value of `4.9` from `10m` to `20m`, a value of ... from `20m` to `30m` and so on? Is it one borehole per file or several borehols per file? Do you need different time steps?  
> **username_0**: Your clarification is correct. With the added complication that there may be some intervals with no sampling information (although this could just have a nodata value). I would be open to one or multiple boreholes per file, but am primarily looking for existing best practices, so in a way, it would depend on that. Time steps are not essential but may come in handy.  
> **username_1**: The `featureType` [profile](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#profile-data) seems to be reasonable for your case. To indicate the boundaries, you insert a variable `z_bnds` that contains the boundaries of the cells. I will post an answer later on or tomorrow.  

---

## 1 answers

### Answer by username_1 on 2020-03-27. Score: 2 | Accepted answer

tl;dr
I would suggest considering the borehole measurements as a vertical profile. In terms of the CF Convention it would be a featureType profile, which is described in the discrete sampling geometries section.
I didn't include all reference to the relevant sections in the CF Conventions below. Just comment if import things are missing.
Example netCDF
netcdf borehole_01 {
dimensions:
      z = 8 ;
      profile = 1 ;
      nv = 2 ;

variables:
    int profile(profile) ;
          profile:cf_role = "profile_id";
    double time(profile);
        time:standard_name = "time";
        time:long_name = "time" ;
        time:units = "days since 1970-01-01 00:00:00" ;
    float lon(profile);
        lon:standard_name = "longitude";
        lon:long_name = "longitude" ;
        lon:units = "degrees_east" ;
    float lat(profile);
        lat:standard_name = "latitude";
        lat:long_name = "latitude" ;
        lat:units = "degrees_north" ;
    float z(z) ;
        z:standard_name = "depth";
        z:long_name = "depth below ..." ;
        z:units = "m" ;
        z:positive = "down" ;
        z:axis = "Z" ;
        z:bounds = "z_bnds" ;
    float z_bnds(z, nv) ;
    float temp(profile, z) ;
        temp:standard_name = "soil_temperature" ;
        temp:long_name = "soil_temperature" ;
        temp:units = "K" ;
        temp:coordinates = "time lon lat z" ;
        temp:cell_methods = "z: mean" ;

// global attributes:
        :featureType = "profile";

data:

 z = 5, 15, 25, 45, 55, 70, 90, 150 ;

 z_bnds = 
  0, 10,
  10, 20,
  20, 30,
  40, 50,
  50, 60, 
  60, 80,
  80, 100,
  100, 200 ;

 temp = 279.4, 278.8, 278.3, 277.0, 277.1, 276.9, 277.0, 279.2 ;
}

Explanation
The variable temp is an example for a data variable in the file.
Basic depth information
Please see CF Conventions section 7.1 Cell Boundaries for details.
z_bnds provides the boundaries of intervals over which the temperature is averaged. The attribute bounds of variable z points to these boundary data. In this example, I wrote the average depth of each interval into the z variable. However, this is no requirement (as far as I know). It might be also the upper or lower depth of each interval or another depth in between. z_bnds automatically inherits all relevant attributs from z. Therefore, it has no own units and standard_name attributes. 
As you can see in the data for z_bnds (or in the table below), it is possible to skip depth ranges (between depth invertal 3 and 4) and to have differently spaced intervals (e.g. interval 6 compared to previous intervals).
| **depth interval** | **minimum** | **maximum** |
|--------------------|-------------|-------------|
| 1                  | 0           | 10          |
| 2                  | 10          | 20          |
| 3                  | 20          | *30*        |
| 4                  | *40*        | 50          |
| 5                  | 50          | 60          |
| 6                  | *60*        | *80*        |
| 7                  | 80          | 100         |
| 8                  | 100         | 200         |

Connecting data variables proberly to the vertical coordinate
Please see CF Conventions section 7.3 Cell Methods for details on the first paragraph and section 5.2 Two-Dimensional Latitude, Longitude, Coordinate Variables for details on the second paragraph.
The value z: mean of the attribute cell_methods of variable temp tells us that the temperature is an average value in z-direction over the interval provided in z_bnds. The latter (over the interval provided in z_bnds) is implicitely assumed.
The value time lon lat z of the coordinates attribute of variable temp indicates that the variables time, lon, lat and z provided temporal and spatial dimensions to each value of temp. Really proper software should be able to map each value of temp a the correspondinc time, lat and lon values via the dimension profile. However, implementing this properly is hard work. Therefore, most software package won't recognize it or might even have issues with it. I your software package throws errors, one first step should be to remove the attribute coordinates.
Setting global attributes
Please see CF Conventions section Features and feature types for details
The global attribute featureType is mandatory when we have a discret sampling geometry.
Several boreholes with different depth intervals
For details on coordinate variables and auxiliary coordinate variables please have a look into sections 1.2 Terminology and 5 Coordinate System
Via the dimension profile we could save several boreholes in one file. In the current situation, the samplings depths of each borehole would be the same. One could make the variable z and z_bnds dependent on profile to provide depth intervals for each borehole. However, then we needed to rename the variables z and z_bnds because a variable might only have the same name of a dimension, if the variable is onedimensional and only depends on this dimension (a coordiante variable). When a variable like the depth depends on two dimensions, it becomes and auxiliary coordinate variable and has to have a different names. Thus, we would have double depth(profile, z) instead of z(z) and double depth_bnds(profile, z, nv) instead of z_bnds(z, nv). The temp:coordiantes would have a value of time lat lon depth (because depth is the vertical coordinates) but temp:cell_methods would remain z: mean (because we calculate average in z-direction).

> **Comments:**
> **username_0**: Great answer. I wonder if there is a way to take advantage of the standard_name:  `thickness_of_soil_layer` to make it more interoperable by using the conventions. The one example I was able to find (also in a soils context) did this: http://www2.nrel.colostate.edu/projects/irc/public/Documents/Software/Century5/Reference/html/Century/SoilsNetCDFFile.htm. However, I like that the bounds are explicitly stated the way you have it so they don't need to be recomputed.  
> **username_1**: @username_0 Thanks for the feedback. `thickness_of_soil_layer` doesn't seem to be in the official [standard name list](http://cfconventions.org/Data/cf-standard-names/72/build/cf-standard-name-table.html) but was used as `standard_name` in some data sets like [this one](http://www2.nrel.colostate.edu/projects/irc/public/Documents/Software/Century5/Reference/html/Century/SoilsNetCDFFile.htm). To be CF-compliant only standard names of the official standard name list are allowed to be used. One can use the `long_name` attribute to set a name, that might be a standard name but isn't.  
> **username_1**: New standard names can be proposed at the [CF Conventions discussion GitHub repository](https://github.com/cf-convention/discuss).  
> **username_1**: Based on my personal feeling and on [this dataset](http://www2.nrel.colostate.edu/projects/irc/public/Documents/Software/Century5/Reference/html/Century/SoilsNetCDFFile.htm) I think that `thickness_of_soil_layer` means something else than the thickness of several vertical layers in the ground. `soil_layer` means the layer where plants can grow -- where we actually have *soil* as described in its [Wikipedia article](https://en.wikipedia.org/wiki/Soil). `thickness_of_soil_layer` is the thinkness of the layer in which plants etc. can grow/live. This variable should have no vertical dimension.  
> **username_0**: You are correct about `thickness_of_soil_layer` not being in the CF standard names, but I disagree about the usage of `soil_layer` in CF.  Consider that the standard name `frozen_water_content_of_soil_layer` defines "Layer" as `any layer with upper and lower boundaries that have constant values in some vertical coordinate`. Also that `Quantities defined for a soil layer must have a vertical coordinate variable`. My interpretation of that dataset is that the layer dimension refers to the vertical index of vertically-stacked soil layers.  
> **username_1**: @username_0 I agree with you after reading the definition of `frozen_water_content_of_soil_layer`. Sould the CDL example be updated somehow?  

---

