<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`](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#profile-data), which is described in the [discrete sampling geometries section](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#discrete-sampling-geometries).

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](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#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](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#cell-methods) for details on the first paragraph and section [5.2 Two-Dimensional Latitude, Longitude, Coordinate Variables](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#_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](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#_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](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#terminology) and [5 Coordinate System](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#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?  

---

