Example of DOV search methods for groundwater permits (grondwatervergunningen)

Binder

Mind that the data source of groundwater permits is just a WFS. It can be accessed with simple WFS calls from OWSLib. It is included in the pydov API for ease of access for less experienced users. And to provide a general interface with unit testing to all considered objects.

Use cases explained below

  • Get permits in a bounding box

  • Get permits in a bounding box based on specific properties

  • Select permits in a municipality and return depth

  • Get permits, returning fields not available in the standard output dataframe

  • Get for a certain permit the measured water quality parameters if available

[36]:
%matplotlib inline
import inspect, sys
import warnings; warnings.simplefilter('ignore')
[37]:
# check pydov path
import pydov

Get information about the datatype ‘GrondwaterVergunning’

[38]:
from pydov.search.grondwatervergunning import GrondwaterVergunningSearch
gwv = GrondwaterVergunningSearch()

A description is provided for the ‘Gwvergunningen’ datatype (in Dutch):

[39]:
gwv.get_description()
[39]:
'Vergunningen verleend voor het winnen van grondwater kunnen gevisualiseerd en bevraagd worden in de Databank Ondergrond Vlaanderen. \r\nSinds 1999 zijn vergunningen verleend volgens de VLAREM-wetgeving. Ze zijn ingedeeld in klasse 1, 2 of 3, waarbij er voor klasse 1 en 2 een vergunningsplicht geldt en voor klasse 3 een meldingsplicht. De indelingslijst is terug te vinden in VLAREM I (het winnen van grondwater is opgenomen onder rubriek 53). Oudere aanvragen zijn verleend volgens het Grondwaterdecreet. Deze zijn ingedeeld in categorie A, B en C.'

The different fields that are available for objects of the ‘Gwvergunningen’ datatype can be requested with the get_fields() method:

[40]:
fields = gwv.get_fields()

# print available fields
for f in fields.values():
    print(f['name'])
id_vergunning
pkey_installatie
exploitant_naam
inrichtingsnummer
watnr
vergunning
vlaremrubriek
vergund_jaardebiet
vergund_dagdebiet
van_datum_termijn
tot_datum_termijn
aquifer_vergunning
diepte
vergund_aantal_putten
inrichtingsklasse
vergunningverlenende_overheid_VVO
referentie_VVO
nacebelcode
IIOA_CBBnr
IIOA_adres
grondwaterlichaam
actie_waakgebied
x
y
exploitant_adres
cbbnr
kbonr
heffingsnummer
exploitant_namen
eerste_invoer
geom

You can get more information of a field by requesting it from the fields dictionary: * name: name of the field * definition: definition of this field * cost: currently this is either 1 or 10, depending on the datasource of the field. It is an indication of the expected time it will take to retrieve this field in the output dataframe. However, since the data source is currently a WFS, the cost of each field is 1 * notnull: whether the field is mandatory or not * type: datatype of the values of this field

[41]:
fields['actie_waakgebied']
[41]:
{'name': 'actie_waakgebied',
 'definition': 'de actie- en waakgebieden afgebakend i.k.v. het gebiedspecifieke beleid zoals vastgesteld in de herstelprogrammas voor grondwaterlichamen in ontoereikende kwantitatieve toestand binnen het Centraal Vlaams Systeem, het Brulandkrijtsysteem en het Sokkelsysteem (2016-2021)',
 'type': 'string',
 'notnull': False,
 'query': True,
 'cost': 1}

Example use cases

Get permits in a bounding box

Get data for all the permits that are geographically located within the bounds of the specified box.

The coordinates are in the Belgian Lambert72 (EPSG:31370) coordinate system and are given in the order of lower left x, lower left y, upper right x, upper right y.

[42]:
from pydov.util.location import Within, Box

df = gwv.search(location=Within(Box(153145, 206930, 163150, 216935)))
df.head()
[000/001] .
[42]:
id_vergunning pkey_installatie x y diepte exploitant_naam watnr vlaremrubriek vergund_jaardebiet vergund_dagdebiet van_datum_termijn tot_datum_termijn aquifer_vergunning inrichtingsklasse nacebelcode actie_waakgebied cbbnr kbonr
0 66167 https://www.dov.vlaanderen.be/data/installatie... 153698.11 213812.68 10.0 HOOYBERGHS ANT-00586-A 53.2.2.b)2. 50000.0 NaN 2019-06-07 2020-02-07 0250: Mioceen Aquifersysteem Klasse 2 41201: Algemene bouw van residentiële gebouwen... geen actie/waakgebieden NaN 0424877618
1 67692 https://www.dov.vlaanderen.be/data/installatie... 154171.79 214241.69 NaN AQUAFIN ANT-01287-A 53.2.2.b)2. 200000.0 NaN 2021-03-08 2023-09-08 0100: Quartaire aquifersystemen Klasse 2 37: Afvalwaterafvoer geen actie/waakgebieden 00418870000022 0440691388
2 68060 https://www.dov.vlaanderen.be/data/installatie... 157404.31 212039.04 10.0 Strabag Belgium ANT-01711-A 53.2.1.b 1300.0 NaN 2020-08-21 NaN 0250: Mioceen Aquifersysteem Klasse 2 41203: Algemene bouw van andere niet-residenti... NaN NaN 0472028526
3 68899 https://www.dov.vlaanderen.be/data/installatie... 161741.40 216702.31 7.0 Beyers Nancy ANT-02159-A 53.2.2.a) 17640.0 360.0 2020-12-17 NaN 0100: Quartaire aquifersystemen Klasse 3 0000: onbekend geen actie/waakgebieden NaN NaN
4 68967 https://www.dov.vlaanderen.be/data/installatie... 159355.06 215945.52 7.0 KRUISPAD ANT-02204-A 53.2.2.a) 16757.0 140.0 2020-12-30 NaN 0230: Pleistoceen en Plioceen aquifer Klasse 3 0000: onbekend NaN NaN 0712688197
[43]:
len(df)
[43]:
471

471 permits were obtained in this bbox. However, not all permits are stil active, indicated by tot_datum_termijn. For more information about the extracted volumes, referenced by vlaremrubriek, see Vlarem II. See this link for more information about the potential definitions.

[44]:
fields['vlaremrubriek']
[44]:
{'name': 'vlaremrubriek',
 'definition': 'Code die gebruikt wordt in VLAREM (bijlage 1 VLAREM II) om een rubriek aan te duiden',
 'type': 'string',
 'notnull': False,
 'query': True,
 'cost': 1}

Get permits in a bounding box with specific properties

Next to querying permits based on their geographic location within a bounding box, we can also search for permits matching a specific set of properties. For this we can build a query using a combination of the ‘Gwvergunningen’ fields and operators provided by the WFS protocol.

A list of possible operators can be found below:

[45]:
[i for i,j in inspect.getmembers(sys.modules['owslib.fes2'], inspect.isclass) if 'Property' in i]
[45]:
['PropertyIsBetween',
 'PropertyIsEqualTo',
 'PropertyIsGreaterThan',
 'PropertyIsGreaterThanOrEqualTo',
 'PropertyIsLessThan',
 'PropertyIsLessThanOrEqualTo',
 'PropertyIsLike',
 'PropertyIsNotEqualTo',
 'PropertyIsNull',
 'SortProperty']

In this example we build a query using the PropertyIsGreaterThan operator in addition to the earlier bbox, to restrict the query to active permits:

[46]:
from owslib.fes2 import PropertyIsGreaterThan

query = PropertyIsGreaterThan(propertyname='tot_datum_termijn',
                          literal='2020-09-01')
df = gwv.search(query=query,
                location=Within(Box(153145, 206930, 163150, 216935)))

df.head()
[000/001] .
[46]:
id_vergunning pkey_installatie x y diepte exploitant_naam watnr vlaremrubriek vergund_jaardebiet vergund_dagdebiet van_datum_termijn tot_datum_termijn aquifer_vergunning inrichtingsklasse nacebelcode actie_waakgebied cbbnr kbonr
0 67692 https://www.dov.vlaanderen.be/data/installatie... 154171.79 214241.69 NaN AQUAFIN ANT-01287-A 53.2.2.b)2. 200000.0 NaN 2021-03-08 2023-09-08 0100: Quartaire aquifersystemen Klasse 2 37: Afvalwaterafvoer geen actie/waakgebieden 00418870000022 0440691388
1 75181 https://www.dov.vlaanderen.be/data/installatie... 159353.39 215831.45 8.0 UP CONSTRUCT ANT-02817-A 53.2.2.b)2. 115000.0 NaN 2022-07-06 2023-03-21 0100: Quartaire aquifersystemen Klasse 2 43390: Overige werkzaamheden in verband met de... geen actie/waakgebieden NaN 0435155559
2 80487 https://www.dov.vlaanderen.be/data/installatie... 155163.90 213762.33 NaN Beheersmaatschappij Antwerpen Mobiel en Tijdel... VLA-00642-A 53.2.2.b)2. 1075058.0 6506.0 2023-02-23 2024-06-30 0250: Mioceen Aquifersysteem Klasse 1 - Vlaams project 0000: onbekend geen actie/waakgebieden NaN NaN
3 80490 https://www.dov.vlaanderen.be/data/installatie... 155163.90 213762.33 2.5 Beheersmaatschappij Antwerpen Mobiel en Tijdel... VLA-00642-A 53.11.1 1075058.0 6506.0 2023-02-23 2024-06-30 0250: Mioceen Aquifersysteem Klasse 1 - Vlaams project 0000: onbekend geen actie/waakgebieden NaN NaN
4 81179 https://www.dov.vlaanderen.be/data/installatie... 158820.75 215899.98 7.3 Algemene Ondernemingen August Van Cauter 2023069188-A 53.2.2.a) 15000.0 500.0 2023-07-03 2023-08-02 0100: Quartaire aquifersystemen Klasse 3 41101: Ontwikkeling van residentiële bouwproje... geen actie/waakgebieden NaN 0412137756
[47]:
len(df)
[47]:
84

Contrary to the earlier query, this result contains considerably less active permits in the considered bbox.

Mind that among these permits, there could also be permits for dewatering works, or ATES systems. Both of these are mostly not important in the development of a hydrogeological model. For dewatering works, it is currently not possible to see the operational status. These works could have well been finished some time ago, or not. See this link for more information about vlaremrubriek codes.

Select permits in a municipality and return depth

We can limit the columns in the output dataframe by specifying the return_fields parameter in our search.

In this example we query all the permits in the city of Ghent and return their depth. For this a remote WFS GML query is used as described in this notebook:

[48]:
from owslib.etree import etree
from owslib.wfs import WebFeatureService
from owslib.fes import PropertyIsEqualTo

from pydov.util.location import GmlFilter

gemeentegrenzen = WebFeatureService(
    'https://geo.api.vlaanderen.be/VRBG/wfs',
    version='1.1.0')
naam_filter = PropertyIsEqualTo(propertyname='NAAM', literal='Gent')
gemeente_poly = gemeentegrenzen.getfeature(
    typename='VRBG:Refgem',
    filter=etree.tostring(naam_filter.toXML()).decode("utf8"),
    outputFormat='text/xml; subtype=gml/3.2').read()

df = gwv.search(
    location=GmlFilter(gemeente_poly, Within),
    return_fields=('id_vergunning', 'diepte'))
df.hist(column='diepte')
[000/001] .
[48]:
array([[<Axes: title={'center': 'diepte'}>]], dtype=object)
../_images/notebooks_search_grondwatervergunningen_31_2.png
[49]:
df.describe()
[49]:
diepte
count 1461.000000
mean 19.852656
std 31.676266
min -1.000000
25% 5.000000
50% 7.500000
75% 21.000000
max 385.000000

Get permit data, returning fields not available in the standard output dataframe

Not all fields are available in the default output frame. However, you can examine the available fields with the get_fields() method and pass the desired field name to the return_fields parameter.

[50]:
from owslib.fes2 import PropertyIsGreaterThanOrEqualTo

query = PropertyIsGreaterThanOrEqualTo(
            propertyname='diepte',
            literal='200')

df = gwv.search(
    location=GmlFilter(gemeente_poly, Within),
    return_fields=('id_vergunning', 'diepte', 'vergunningverlenende_overheid_VVO'))

df.head()
[000/001] .
[50]:
id_vergunning diepte vergunningverlenende_overheid_VVO
0 60451 60.0 Provinciebestuur OOST-VLAANDEREN
1 66888 5.0 Gemeentebestuur GENT
2 66889 5.0 Gemeentebestuur GENT
3 66992 4.0 Gemeentebestuur GENT
4 67238 3.0 Gemeentebestuur GENT

Estimate groundwater quality data for a certain permit

Given groundwater scarcity in Belgium, the reuse of dewatering drainage is increasingly being considerd. In some cases, this water contains a high iron load which is not desirable for a lot of applications.
Determine the groundwater quality for a certain permit, e.g. for the permit at Diestsestraat 209 3000 Leuven.
[51]:
from pydov.util.location import Within, Box
from owslib.fes2 import PropertyIsEqualTo
import pandas as pd

query = PropertyIsEqualTo(propertyname='inrichtingsnummer',
                          literal='20181004-0018')
df_permit = gwv.search(query=query)
df_permit.head()
[000/001] .
[51]:
id_vergunning pkey_installatie x y diepte exploitant_naam watnr vlaremrubriek vergund_jaardebiet vergund_dagdebiet van_datum_termijn tot_datum_termijn aquifer_vergunning inrichtingsklasse nacebelcode actie_waakgebied cbbnr kbonr
0 64279 https://www.dov.vlaanderen.be/data/installatie... 174097.89 174672.54 11.0 Rialto Holding VLB-00133-A 53.2.2.a) 22450.0 445.0 2019-05-29 2023-03-16 0620: Zand van Brussel Klasse 3 64200: Holdings NaN NaN 0675544028
The water is extracted from the hydrogeological layer ‘Zand van Brussel’ which is designated with the according HCOV code ‘0620’. We can now look in the data from the groundwater quality monitoring wells which wells are situated nearby for that specific hydrogeological layer. For this, we first have to look at the dataset comprising the head measurements, that also contains the HCOV code of the aquifer. Subsequently, we can fetch the water quality monitoring data of the selected well screens.
More information on the HCOV code can be found through this link.
[52]:
from pydov.search.grondwaterfilter import GrondwaterFilterSearch
from pydov.search.grondwatermonster import GrondwaterMonsterSearch
from pydov.util.query import Join

gfs = GrondwaterFilterSearch()
fields = gfs.get_fields()

# print available fields
for f in fields.values():
    print(f['name'])

gw_id
pkey_grondwaterlocatie
filternummer
pkey_filter
namen
filtergrafiek
putgrafiek
aquifer
diepte_onderkant_filter
lengte_filter
putsoort
filtertype
meetnet
x
y
start_grondwaterlocatie_mtaw
gemeente
grondwaterlichaam
afgesloten_volgens_gwdecreet
datum_in_filter
datum_uit_filter
stijghoogterapport
analyserapport
boornummer
boringfiche
peilmetingen_van
peilmetingen_tot
kwaliteitsmetingen_van
kwaliteitsmetingen_tot
recentste_exploitant
beheerder
eerste_invoer
recentste_installatie
geom
meetnet_code
aquifer_code
grondwaterlichaam_code
regime
datum
tijdstip
peil_mtaw
betrouwbaarheid
methode
filterstatus
filtertoestand
mv_mtaw
[53]:
from pydov.search.grondwaterfilter import GrondwaterFilterSearch
from pydov.search.grondwatermonster import GrondwaterMonsterSearch
from pydov.util.query import Join

gfs = GrondwaterFilterSearch()
gwmonster = GrondwaterMonsterSearch()

df_gfs = gfs.search(location=Within(Box(170000, 174000, 190000, 180000)),
                   return_fields=['pkey_filter', 'x', 'y', 'aquifer', 'diepte_onderkant_filter'])

filters = df_gfs[(df_gfs['aquifer'].str.contains('0620')) ]
filters.head()
[000/001] .
[53]:
pkey_filter x y aquifer diepte_onderkant_filter
26 https://www.dov.vlaanderen.be/data/filter/2021... 173724.0 175112.0 0620 - Zand van Brussel 19.0
27 https://www.dov.vlaanderen.be/data/filter/2021... 173727.0 175127.0 0620 - Zand van Brussel 19.0
28 https://www.dov.vlaanderen.be/data/filter/2021... 173755.0 175104.0 0620 - Zand van Brussel 19.0
29 https://www.dov.vlaanderen.be/data/filter/2021... 173769.0 175122.0 0620 - Zand van Brussel 19.0
30 https://www.dov.vlaanderen.be/data/filter/2021... 173798.0 175119.0 0620 - Zand van Brussel 19.0

Now select the according water quality data

[54]:
df_gwq = gwmonster.search(query=Join(filters, 'pkey_filter'),
                         )
df_gwq['parameter'] = df_gwq['parameter'].str.encode('utf-8')
df_gwq['parameter'].unique()
[000/001] .
[000/210] cccccccccccccccccccccccccccccccccccccccccccccccccc
[050/210] cccccccccccccccccccccccccccccccccccccccccccccccccc
[100/210] cccccccccccccccccccccccccccccccccccccccccccccccccc
[150/210] cccccccccccccccccccccccccccccccccccccccccccccccccc
[200/210] cccccccccc
[54]:
array([b'Na', b'EC', b'Mg', b'Cd', b'Ca', b'NO2', b'Zn', b'Al', b'CN',
       b'Cr', b'K', b'HCO3', b'F', b'Cl', b'As', b'Cu', b'T', b'Ni',
       b'Pb', b'NH4', b'TOC', b'Mn', b'NO3', b'CO3', b'Fe', b'O2',
       b'Eh\xc2\xb0', b'PO4', b'Fe2+', b'SO4', b'Hg', b'pH', b'EC(Lab.)',
       b'Co', b'pH(Lab.)', b'Isoprot', b'chazr', b'Bentaz', b'metola-S',
       b'atr_des', b'Terbu', b'Diur', b'Simaz', b'VIS', b'DMS',
       b'Chlortol', b'BAM', b'Atraz', b'AMPA', b'Chloridaz', b'Glyfos',
       b'Linur', b'SomAN', b'SomKAT', b'B', b'%AfwijkBalans',
       b'trichlorpyr', b'Mesotri', b'fluopicolide', b'meta9', b'Dchdzn',
       b'meta4', b'meta11', b'Imida', b'Triflox', b'Metola-S-ESA',
       b'flufe', b'meta8', b'Br', b'TDS', b'Temp.', b'PropaCl', b'24d',
       b'Linur_mono', b'Propan', b'Terbu_des', b'Carben',
       b'Atr_desisoprop', b'Propaz', b'brom', b'Ethofum', b'mcpa',
       b'Carbet', b'Cyana', b'Metaza', b'Prometr', b'Clproph',
       b'5ClFenol', b'Metox', b'Ala', b'Metobro', b'Metami', b'245t',
       b'24db', b'Fenoprop', b'Mecopr', b'Fluroxypyr', b'Terbutryn',
       b'mcpb', b'Methabenz', b'Dichlorpr', b'Sebu', b'Hexaz', b'Dicam',
       b'Per', b'Tri'], dtype=object)
[55]:
pars_select = [b'Fe', b'Fe2+', b'Fe(Tot.)', b'Fe3+']
df_selected = df_gwq.loc[df_gwq.parameter.isin(pars_select), :]
df_stat = df_selected.loc[:, ['parameter', 'waarde']].groupby('parameter').describe().unstack(1)
df_stat
[55]:
               parameter
waarde  count  b'Fe'        200.000000
               b'Fe2+'       75.000000
        mean   b'Fe'          1.480600
               b'Fe2+'        0.701600
        std    b'Fe'          1.955772
               b'Fe2+'        1.268584
        min    b'Fe'          0.000000
               b'Fe2+'        0.000000
        25%    b'Fe'          0.020000
               b'Fe2+'        0.020000
        50%    b'Fe'          0.300000
               b'Fe2+'        0.070000
        75%    b'Fe'          3.355000
               b'Fe2+'        0.650000
        max    b'Fe'         12.300000
               b'Fe2+'        4.400000
dtype: float64

Mind the units of the values.

[56]:
df_selected.eenheid.unique()
[56]:
array(['mg/l'], dtype=object)

As such, the iron content of the considered hydrogeological layer is on average 1.5 mg/L with a stdev of 1.97 mg/L. This is most likely above the standars for use as irrigation water (see this link). Mind that further processing with a limited selection of the two nearest monitoring screens is possible. And even further, an indication of the nearest OVAM sites can be obtaind from the WFS with (in Dutch) ‘Dossierinfo’ as available from this link.