BRO GeoTop#
GeoST provides support to work with models that are provided by the BRO such as GeoTOP. This section will explain the usage of GeoTop
, how to make easy selections and combinations with for example borehole data contained in a BoreholeCollection
.
Reading GeoTop#
GeoTOP data can be read from a local NetCDF file of downloaded data from the BRO or directly accessed from the OPeNDAP-server of TNO Geological survey. See GeoTop.from_netcdf
and GeoTop.from_opendap
in the API reference.
Working with GeoTop#
Let’s load some example GeoTOP data for the Utrecht Science park:
import geost
geotop = geost.data.geotop_usp()
print(geotop)
Downloading file 'geotop_usp.nc' from 'https://github.com/Deltares-research/geost/raw/main/data/geotop_usp.nc' to '/home/runner/.cache/geost'.
GeoTop
Data variables:
strat (y, x, z) float32 357kB ...
lithok (y, x, z) float32 357kB ...
kans_1 (y, x, z) float32 357kB ...
kans_2 (y, x, z) float32 357kB ...
kans_3 (y, x, z) float32 357kB ...
kans_4 (y, x, z) float32 357kB ...
kans_5 (y, x, z) float32 357kB ...
kans_6 (y, x, z) float32 357kB ...
kans_7 (y, x, z) float32 357kB ...
kans_8 (y, x, z) float32 357kB ...
kans_9 (y, x, z) float32 357kB ...
onz_lk (y, x, z) float32 357kB ...
onz_ls (y, x, z) float32 357kB ...
Dimensions: {'x': 19, 'y': 15, 'z': 313}
Resolution (y, x, z): (100.0, 100.0, 0.5)
As you can see this prints information on the type of class (i.e. GeoTop
), the available data variables, xyz-dimensions and resolution. The GeoTop
class inherits from GeoST VoxelModel
and as such, inherits all the attributes and associated selection methods. For example, we can check the horizontal and vertical bounds:
print(geotop.horizontal_bounds)
print(geotop.vertical_bounds)
(139500.0, 454700.0, 141400.0, 456200.0)
(-50.0, 106.5)
This prints the “xmin, ymin, xmax, ymax” bounding box and the “zmin, zmax” of the data. GeoTop
depends strongly on xarray.Dataset and therefore provides familiar selection methods .sel
and .isel
to select specific coordinates or indices, or slices of coordinates or indices:
sel = geotop.sel(x=[139_650, 139_750]) # Select specific x-coordinates
sel = geotop.isel(x=[2, 5]) # Select specific x-indices
sel = geotop.sel(x=slice(140_000, 140_500)) # Select a slice of x-coordinates
sel = geotop.isel(x=slice(2, 5)) # Select a slice of x-indices
sel = geotop.sel(x=[140_013.23, 140_333.14], method='nearest') # Select the nearest x-coordinates
print(sel)
GeoTop
Data variables:
strat (y, x, z) float32 38kB ...
lithok (y, x, z) float32 38kB ...
kans_1 (y, x, z) float32 38kB ...
kans_2 (y, x, z) float32 38kB ...
kans_3 (y, x, z) float32 38kB ...
kans_4 (y, x, z) float32 38kB ...
kans_5 (y, x, z) float32 38kB ...
kans_6 (y, x, z) float32 38kB ...
kans_7 (y, x, z) float32 38kB ...
kans_8 (y, x, z) float32 38kB ...
kans_9 (y, x, z) float32 38kB ...
onz_lk (y, x, z) float32 38kB ...
onz_ls (y, x, z) float32 38kB ...
Dimensions: {'x': 2, 'y': 15, 'z': 313}
Resolution (y, x, z): (100.0, 300.0, 0.5)
As you can see, a selection returns a new GeoTop
instance for the desired coordinates. Note that the x-resolution has also been changed because the coordinates in the last selection are approximately 300 meters apart.
Selections#
Often it can be necessary to select GeoTop at specific locations, such as borehole locations, to compare the borehole data with GeoTop. We can easily select GeoTop at the locations of boreholes using the GeoTop.select_with_points
method. Let’s load a BoreholeCollection
with borehole data for the Utrecht Science Park to see what happens:
boreholes = geost.data.boreholes_usp() # BoreholeCollection
geotop_at_locations = geotop.select_with_points(boreholes.header.gdf)
print(geotop_at_locations)
<xarray.Dataset> Size: 1MB
Dimensions: (idx: 67, z: 313)
Coordinates:
x (idx) float64 536B 1.396e+05 1.396e+05 ... 1.41e+05 1.412e+05
y (idx) float64 536B 4.56e+05 4.55e+05 ... 4.56e+05 4.56e+05
* z (z) float32 1kB -49.75 -49.25 -48.75 ... 105.2 105.8 106.2
spatial_ref int64 8B 0
* idx (idx) int64 536B 0 1 2 3 4 5 6 7 8 ... 59 60 61 62 63 64 65 66
Data variables: (12/13)
strat (idx, z) float32 84kB ...
lithok (idx, z) float32 84kB ...
kans_1 (idx, z) float32 84kB ...
kans_2 (idx, z) float32 84kB ...
kans_3 (idx, z) float32 84kB ...
kans_4 (idx, z) float32 84kB ...
... ...
kans_6 (idx, z) float32 84kB ...
kans_7 (idx, z) float32 84kB ...
kans_8 (idx, z) float32 84kB ...
kans_9 (idx, z) float32 84kB ...
onz_lk (idx, z) float32 84kB ...
onz_ls (idx, z) float32 84kB ...
Attributes:
title: geotop v01r6 (100.0m * 100.0m * 0.5m
references: http://www.dinoloket.nl/detaillering-van-de-bovenste-lagen...
comment: GeoTOP 1.6 (lithoklasse)
disclaimer: http://www.dinoloket.nl
terms_of_use: http://www.dinoloket.nl
institution: TNO / Geologische Dienst Nederland
Conventions: CF-1.4
source: Generated by nl.tno.dino.geo3dmodel.generator.GeoTOPVoxelM...
history: Generated on Thu Oct 05 17:01:25 CEST 2023
The result is an xarray.Dataset
with a new “idx” dimension and note that variables like “strat” now have “(idx, z)” dimensions. The .select_with_points
method selects the voxel columns each borehole is in, in the index order of the boreholes in the BoreholeCollection
. It does not return a VoxelModel
instance because a VoxelModel
is only valid if it contains “x”, “y” and “z” dimensions.
With the selection result, it is possible to compare a borehole with a specific voxel column. Let’s for example compare the first borehole in the collection with the voxel column. First, let’s print the “header” attribute of the borehole collection to find the “nr” of the first borehole:
print(boreholes.header)
PointHeader instance containing 67 objects
nr x y surface end geometry
0 B31H0541 139585 456000 1.200 -9.900 POINT (139585 456000)
1 B31H0611 139600 455060 1.200 -23.000 POINT (139600 455060)
2 B31H0718 139950 455200 1.300 -271.200 POINT (139950 455200)
3 B31H0803 139675 455087 2.160 -4.840 POINT (139675 455087)
4 B31H0806 139684 455384 1.000 -49.500 POINT (139684 455384)
.. ... ... ... ... ... ...
62 B32C1889 140919 456000 1.728 -2.772 POINT (140919 456000)
63 B32C1890 140938 455878 3.948 0.248 POINT (140938 455878)
64 B32C1891 141025 455998 2.112 -1.888 POINT (141025 455998)
65 B32C1892 141091 455966 1.769 -2.731 POINT (141091 455966)
66 B32C1893 141266 455989 2.328 -2.172 POINT (141266 455989)
[67 rows x 6 columns]
We can see that the first number (at index 0) is “B31H0541”. Notice in the “surface” and “end” columns that the borehole is between +1.2 m NAP and -9.9 m NAP. We can select the first index from geotop_at_locations
, select the depths between 1.2 and -9.9 m NAP and create a DataFrame to compare the data. In similar way, selection method for other use cases are available when working with GeoTop
. See the API reference for available methods.
# Increase zmin and zmax by a little to make sure the complete depth of the borehole is covered
voxel_column = geotop_at_locations.sel(idx=0, z=slice(-10.5, 1.5))
voxel_column = voxel_column.to_dataframe().sort_index(ascending=False) # Make depth increase from top to bottom
voxel_column # Check out the result
x | y | strat | lithok | kans_1 | kans_2 | kans_3 | kans_4 | kans_5 | kans_6 | kans_7 | kans_8 | kans_9 | onz_lk | onz_ls | spatial_ref | idx | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
z | |||||||||||||||||
1.25 | 139550.0 | 456050.0 | 2010.0 | 2.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
0.75 | 139550.0 | 456050.0 | 2010.0 | 1.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
0.25 | 139550.0 | 456050.0 | 2010.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 2.0 | 0 | 0 |
-0.25 | 139550.0 | 456050.0 | 2010.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 11.0 | 0 | 0 |
-0.75 | 139550.0 | 456050.0 | 3030.0 | 5.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 17.0 | 0 | 0 |
-1.25 | 139550.0 | 456050.0 | 3030.0 | 5.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 7.0 | 0 | 0 |
-1.75 | 139550.0 | 456050.0 | 3030.0 | 5.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-2.25 | 139550.0 | 456050.0 | 3030.0 | 5.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 4.0 | 0 | 0 |
-2.75 | 139550.0 | 456050.0 | 3030.0 | 5.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 13.0 | 0 | 0 |
-3.25 | 139550.0 | 456050.0 | 3100.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 17.0 | 0 | 0 |
-3.75 | 139550.0 | 456050.0 | 3100.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 13.0 | 0 | 0 |
-4.25 | 139550.0 | 456050.0 | 3100.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 3.0 | 0 | 0 |
-4.75 | 139550.0 | 456050.0 | 3100.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-5.25 | 139550.0 | 456050.0 | 3100.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-5.75 | 139550.0 | 456050.0 | 3100.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 3.0 | 0 | 0 |
-6.25 | 139550.0 | 456050.0 | 3100.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 16.0 | 0 | 0 |
-6.75 | 139550.0 | 456050.0 | 4010.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 12.0 | 0 | 0 |
-7.25 | 139550.0 | 456050.0 | 4010.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-7.75 | 139550.0 | 456050.0 | 4010.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-8.25 | 139550.0 | 456050.0 | 4010.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-8.75 | 139550.0 | 456050.0 | 4010.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-9.25 | 139550.0 | 456050.0 | 4010.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-9.75 | 139550.0 | 456050.0 | 4010.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 14.0 | 77.0 | 9.0 | 0.0 | 0.0 | 36.0 | 0.0 | 0 | 0 |
-10.25 | 139550.0 | 456050.0 | 4010.0 | 6.0 | 0.0 | 0.0 | 0.0 | 0.0 | 27.0 | 68.0 | 5.0 | 0.0 | 0.0 | 39.0 | 0.0 | 0 | 0 |
Relabelling GeoTOP information#
Notice that in the voxel_column
result, the columns “strat” (i.e. stratigraphy) and “lithok” (i.e. lithology) contain numbers, instead of names which makes it difficult to understand what the unit and lithology at specific depths are. This makes a comparison with the borehole data difficult.
GeoST provides the StratGeotop
class and Lithology
class which make it easy to translate these numbers into more meaningful names. Let’s import them and check which stratigraphic unit belongs to the number 2010 in the “strat” column and what the number 6 in the “lithok” means:
from geost.bro import Lithology, StratGeotop
unit = StratGeotop.select_values(2010)
print(unit)
lith = Lithology.select_values(6)
print(lith)
[<HoloceneUnits.EC: 2010>]
[<Lithology.medium_sand: 6>]
As you can see, the printed result says 2010 in the “strat” column belongs to “HoloceneUnits.EC”. The first part relates to the main group the unit belongs to. StratGeotop
contains four main groups of stratigraphic units as class attributes: “holocene”, “channel”, “older” and “antropogenic”. The second part is the abbreviated name of the unit which can be found in the stratigraphic nomenclature. Most units belong to the “Boven-Noordzee Groep” (prefix “NU”). For example, the unit “EC” from the selection result corresponds to the “Echteld formation” and can be found here.
The printed result of lith
says 6 in the “lithok” column refers to “Lithology.medium_sand” which is medium coarse sand.
StratGeotop
and Lithology
can also easily be transformed into a dictionary so each value in the “strat” and “lithok” columns can be transformed into meaningful labels:
strat_dict = StratGeotop.to_dict(key="value")
lith_dict = Lithology.to_dict(key="value")
voxel_column["strat"] = voxel_column["strat"].replace(strat_dict)
voxel_column["lithok"] = voxel_column["lithok"].replace(lith_dict)
voxel_column # See the result
x | y | strat | lithok | kans_1 | kans_2 | kans_3 | kans_4 | kans_5 | kans_6 | kans_7 | kans_8 | kans_9 | onz_lk | onz_ls | spatial_ref | idx | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
z | |||||||||||||||||
1.25 | 139550.0 | 456050.0 | EC | clay | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
0.75 | 139550.0 | 456050.0 | EC | organic | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
0.25 | 139550.0 | 456050.0 | EC | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 2.0 | 0 | 0 |
-0.25 | 139550.0 | 456050.0 | EC | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 11.0 | 0 | 0 |
-0.75 | 139550.0 | 456050.0 | BXWISIKO | fine_sand | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 17.0 | 0 | 0 |
-1.25 | 139550.0 | 456050.0 | BXWISIKO | fine_sand | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 7.0 | 0 | 0 |
-1.75 | 139550.0 | 456050.0 | BXWISIKO | fine_sand | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-2.25 | 139550.0 | 456050.0 | BXWISIKO | fine_sand | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 4.0 | 0 | 0 |
-2.75 | 139550.0 | 456050.0 | BXWISIKO | fine_sand | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 13.0 | 0 | 0 |
-3.25 | 139550.0 | 456050.0 | BX | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 17.0 | 0 | 0 |
-3.75 | 139550.0 | 456050.0 | BX | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 13.0 | 0 | 0 |
-4.25 | 139550.0 | 456050.0 | BX | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 3.0 | 0 | 0 |
-4.75 | 139550.0 | 456050.0 | BX | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-5.25 | 139550.0 | 456050.0 | BX | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-5.75 | 139550.0 | 456050.0 | BX | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 3.0 | 0 | 0 |
-6.25 | 139550.0 | 456050.0 | BX | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 16.0 | 0 | 0 |
-6.75 | 139550.0 | 456050.0 | KRBXDE | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 12.0 | 0 | 0 |
-7.25 | 139550.0 | 456050.0 | KRBXDE | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-7.75 | 139550.0 | 456050.0 | KRBXDE | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-8.25 | 139550.0 | 456050.0 | KRBXDE | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-8.75 | 139550.0 | 456050.0 | KRBXDE | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-9.25 | 139550.0 | 456050.0 | KRBXDE | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0 | 0 |
-9.75 | 139550.0 | 456050.0 | KRBXDE | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 14.0 | 77.0 | 9.0 | 0.0 | 0.0 | 36.0 | 0.0 | 0 | 0 |
-10.25 | 139550.0 | 456050.0 | KRBXDE | medium_sand | 0.0 | 0.0 | 0.0 | 0.0 | 27.0 | 68.0 | 5.0 | 0.0 | 0.0 | 39.0 | 0.0 | 0 | 0 |
Now, let’s select borehole “B31H0541” from the BoreholeCollection
(this was the borehole at the first index in geotop_at_locations
) and then compare lithology and stratigraphy information in the borehole data with the voxel column.
borehole = boreholes.get("B31H0541")
# Check out relevant information in the borehole data
borehole.data[['nr', 'surface', 'end', 'top', 'bottom', 'lith', 'strat_2003']]
nr | surface | end | top | bottom | lith | strat_2003 | |
---|---|---|---|---|---|---|---|
0 | B31H0541 | 1.2 | -9.9 | 0.00 | 0.20 | K | EC |
1 | B31H0541 | 1.2 | -9.9 | 0.20 | 0.60 | K | EC |
2 | B31H0541 | 1.2 | -9.9 | 0.60 | 0.95 | V | NI |
3 | B31H0541 | 1.2 | -9.9 | 0.95 | 2.80 | Z | EC |
4 | B31H0541 | 1.2 | -9.9 | 2.80 | 4.20 | Z | BXWI |
5 | B31H0541 | 1.2 | -9.9 | 4.20 | 8.40 | Z | BX |
6 | B31H0541 | 1.2 | -9.9 | 8.40 | 9.60 | Z | KR |
7 | B31H0541 | 1.2 | -9.9 | 9.60 | 11.10 | Z | KR |
Combining with Collections#
GeoST also makes it possible to add information from GeoTop directly to borehole data in a BoreholeCollection
or CPT data in a CptCollection
. This is shown in the examples section.