Functionalities

Accessing 3Di model components

threedigrid uses a limited number of main classes to access 3Di model components:

The Lines and Nodes classes have several child classes (e.g. Manholes or Weirs) that allow access to attributes specific to those 3Di model components.

Breaches, Nodes, Lines, and Pumps have time series connected to them through the GridH5ResultAdmin, GridH5AggregateResultAdmin, or GridH5WaterQualityResultAdmin.

Filters and subsets

To make selections of data, you can use Spatial filters, Non-spatial filters, Subsets, and Selecting attributes using only. You can chain these in any way you like. The example below returns all 1D nodes with a storage area >= 1.0 within a specific area.

ga.nodes.subset("1D_ALL").filter(storage_area__gte=1.0).filter(coordinates__intersects_geometry=my_polygon)

The filters and subsets are ‘lazy’, i.e. they are not executed until data is retrieved. To retrieve data you have to call data or timeseries() explicitly:

ga.nodes.filter(node_type__eq=5)  # will not return all data
ga.nodes.filter(node_type__eq=5).data  # returns all data as an OrderedDict
gr.nodes.timeseries(0, 3600).s1 # time series of the water levels of the first hour of the simulation

Spatial filters

The following filters are available for making spatial selections:

The spatial filters can be used on GeomArrayField subclasses:

  • Breaches: coordinates or line_geometries

  • Cells: cell_coords

  • Levees: coords

  • Lines: line_coords or line_geometries

  • Nodes: coordinates

Warning

Spatial filters only work on data in projected coordinate reference systems.

contains_point

The contains_point filter can be used to, e.g., identify a grid cell in which a given point falls:

ga.cells.filter(cell_coords__contains_point=xy).id


from shapely.geometry import Polygon
polygon = Polygon([
    [109300.0, 518201.2], [108926.5, 518201.2], [108935.6, 517871.7], [109300.0, 518201.2]
])
ga.nodes.filter(coordinates__intersects_geometry=polygon)

in_bbox

Returns the features that are within a bounding box.

Example:

from shapely.geometry import Polygon
polygon = Polygon([
    [109300.0, 518201.2], [108926.5, 518201.2], [108935.6, 517871.7], [109300.0, 518201.2]
])
gr.lines.filter(
    line_coords__in_bbox=polygon.bounds
)

in_tile

Example:

ga.nodes.filter(coordinates__in_tile=[0, 0, 0])

intersects_bbox

Returns the features that intersect a bounding box.

Example:

from shapely.geometry import Polygon
polygon = Polygon([
    [109300.0, 518201.2], [108926.5, 518201.2], [108935.6, 517871.7], [109300.0, 518201.2]
])
gr.lines.filter(
    line_coords__intersects_bbox=polygon.bounds
)

intersects_geometry

Returns the features that intersect the input geometry. It expects a shapely geometry:

from shapely.geometry import Polygon
polygon = Polygon([
    [109300.0, 518201.2], [108926.5, 518201.2], [108935.6, 517871.7], [109300.0, 518201.2]
])
ga.cells.filter(cell_coords__intersects_geometry=polygon)

To improve performance, it is recommended to always combine intersects_geometry with intersects_bbox, like this:

gr.lines.filter(
    line_coords__intersects_bbox=polygon.bounds
).filter(
    line_coords__intersects_geometry=polygon
)

intersects_tile

Example:

ga.nodes.filter(coordinates__intersects_tile=[0, 0, 0])

Non-spatial filters

Non-geometry fields can also be filtered on. For example, to select the nodes with type “2D Boundary” (i.e. node_type = 5), you can use this filter:

ga.nodes.filter(node_type__eq=5)

or both “2D Boundary” and “2D Open water” nodes:

ga.nodes.filter(node_type__in=[5, 6])

The following non-spatial filters are available:

  • eq: Equals

  • ne: Not equals

  • gt: Greater than

  • gte: Greater than equals

  • lt: Less than

  • lte: Less than equals

  • in: In collection

You combine them with the field name by adding a double underscore __ in between, e.g. crest_level must be greater than 4.33: crest_level__gt=4.33.

Subsets

Subsets are an easy way to retrieve categorized sub parts of the data.

Nodes and Lines have predefined subsets. To those, can call the known_subset property:

ga.lines.known_subset

>>> [u'ACTIVE_BREACH',
>>>  u'2D_OPEN_WATER',
>>>  u'1D',
>>>  u'SHORT_CRESTED_STRUCTURES',
>>>  u'2D_GROUNDWATER',
>>>  u'LONG_CRESTED_STRUCTURES',
>>>  u'1D2D',
>>>  u'2D_VERTICAL_INFILTRATION',
>>>  u'1D_ALL',
>>>  u'2D_ALL',
>>>  u'2D_OPEN_WATER_OBSTACLES',
>>>  u'GROUNDWATER_ALL']

To retrieve data of a subset use the subset() method like this:

ga.lines.subset('1D_ALL').data  # remember, all filtering is lazy

The definitions of the known subsets can be found here:

  • Nodes: threedigrid/admin/nodes/subsets.py

  • Lines: threedigrid/admin/lines/subsets.py

You can also define your own subsets.

Selecting attributes using only

If you only need a few attributes, you can use only().

Example:

ga.nodes.only('id', 'coordinates').data

Exporters

Exporters allow you to export model data to files. For example exporting all 2D open water lines to a Shapefile with EPSG code 4326 (WGS84):

from threedigrid.admin.lines.exporters import LinesOgrExporter

line_2d_open_water_wgs84 = ga.lines.subset('2D_OPEN_WATER').reproject_to('4326')

exporter = LinesOgrExporter(line_2d_open_water_wgs84)
exporter.save('/tmp/line.shp', line_2d_open_water_wgs84.data, '4326')

Supported extenstions are:

  • .shp (Shapefile)

  • .gpkg (GeoPackage)

  • .json (GeoJSON)

  • .geojson (GeoJSON)

Most models have shortcut methods for exporting their data for shapefiles and geopackages, like:

# Shapefile
ga.lines.subset('2D_OPEN_WATER').reproject_to('4326').to_shape('/tmp/line.shp')

# Geopackage
ga.lines.subset('2D_OPEN_WATER').reproject_to('4326').to_gpkg('/tmp/line.gpkg')

Command line interfaces

3digrid_explore

Using the 3digrid_explore shortcut, simply run:

$ 3digrid_explore --grid-file=<path to grid file> --ipy

This will invoke an ipython session with a GridH5Admin instance already loaded.

To get a quick overview of the threedimodels meta data omit the --ipy option or explicitly run:

$ 3digrid_explore --grid-file=<the to grid file> --no-ipy

This will give you output like this:

Overview of model specifics:

model slug:              v2_bergermeer-v2_bergermeer_bres_maalstop-58-b1f8179f1f3c2333adb08c9e6933fa7b9a8cd163
threedicore version:     0-20180315-3578e9b-1
threedi version:         1.63.dev0
has 1d:                  True
has 2d:                  True
has groundwater:         True
has levees:              True
has breaches:            True
has pumpstations:        True

3digrid_export

To quickly export data of a model (or a models subset) you can use the 3digrid_export shortcut. To get an overview of the options run:

$ 3digrid_export --help

Usage: 3digrid_export [OPTIONS]

Options:
  --grid-file PATH                Path to the admin file
  --file-type [shape|gpkg]
  --output-file PATH              Path to the output file
  --model [nodes|lines|breaches|levees]
  --subset TEXT                   Filter by a subset like 1D_all (applies only
                                  for models nodes and lines
  --help                          Show this message and exit.

So to export the all 1D nodes:

$ 3digrid_export --grid-file=<path to grid file> --file-type=shape --output-file=<name>.shp --model=nodes --subset=1d_all

Remote procedure calls

Note

This is an advanced feature used inside the 3Di stack, probably you do not need this.

Currently only the client-side is included. The server-side might be added in a later stage.

Installation:

$ pip install threedigrid[rpc]

Basic usage:

ga = GridH5ResultAdmin('rpc://REDIS_HOST/SIMULATION_ID', 'rpc://REDIS_HOST/SIMULATION_ID')
# Replace REDIS_HOST and SIMULATION_ID with actual values.
future_result = ga.nodes.filter(lik__eq=4).data
data = await future_result.resolve()

Subscription usage:

subscription = await future_result.subscribe()

async for item in subscription.enumerate():
    # do something with item