Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inflow schema 300 #366

Merged
merged 14 commits into from
Aug 1, 2024
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, windows-2019, macos-11]
os: [ubuntu-20.04, windows-2019, macos-12]

steps:
- name: Checkout source
Expand Down
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Changelog of threedigrid-builder
1.15.1 (unreleased)
-------------------

- Adapt grid-builder to work with schema upgrades for inflow (0.223)
- Create quarter administration.
- Add support for NumPy 2.

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def get_version():

install_requires = [
"numpy>=1.15,<3.0",
"threedi-schema==0.222.*",
"threedi-schema==0.223.*",
"shapely>=2",
"pyproj>=3",
"condenser[geo]>=0.1.1",
Expand Down
6 changes: 1 addition & 5 deletions threedigrid_builder/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from threedigrid_builder.constants import InflowType
from threedigrid_builder.exceptions import SchematisationError
from threedigrid_builder.grid import Grid, QuadTree
from threedigrid_builder.grid.zero_d import ImperviousSurfaces
from threedigrid_builder.interface import (
DictOut,
GDALInterface,
Expand Down Expand Up @@ -210,10 +209,7 @@ def _make_gridadmin(
# process zero-d information, either using the 'v2_surfaces'
# or 'v2_impervious_surfaces' table.
progress_callback(0.95, "Processing 0D domain...")
if grid_settings.use_0d_inflow == InflowType.SURFACE.value:
surfaces: Surfaces = db.get_surfaces()
else:
surfaces: ImperviousSurfaces = db.get_impervious_surfaces()
surfaces: Surfaces = db.get_surfaces()
grid.add_0d(surfaces)

grid.finalize()
Expand Down
6 changes: 3 additions & 3 deletions threedigrid_builder/grid/grid.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dataclasses import dataclass, fields
from typing import Optional, Tuple, Union
from typing import Optional, Tuple

import numpy as np
import shapely
Expand Down Expand Up @@ -769,9 +769,9 @@ def set_breach_ids(self, breach_points: PotentialBreachPoints):
breach_points.assign_to_connection_nodes(self.nodes, self.lines)
breach_points.match_breach_ids_with_calculation_types(self.nodes)

def add_0d(self, surfaces: Union[zero_d.Surfaces, zero_d.ImperviousSurfaces]):
def add_0d(self, surfaces: zero_d.Surfaces):
"""
Zero dimension admin derived from 'v2_surfaces' and 'v2_impervious_surfaces'.
Zero dimension admin derived from 'surfaces'.
"""
self.surfaces = surfaces.as_grid_surfaces()
self.surface_maps = surfaces.as_surface_maps(self.nodes, self.nodes_embedded)
Expand Down
55 changes: 6 additions & 49 deletions threedigrid_builder/grid/zero_d.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

from threedigrid_builder.base import Array, surfaces
from threedigrid_builder.base.nodes import Nodes
from threedigrid_builder.constants import ContentType, SurfaceClass
from threedigrid_builder.constants import ContentType

__all__ = ["Surfaces", "ImperviousSurfaces"]
__all__ = ["Surfaces"]


SURFACE_TYPE_PROPERTIES = {
Expand Down Expand Up @@ -207,10 +207,8 @@ class BaseSurface:
surface_id: int
code: str
display_name: str
nr_of_inhabitants: float
area: float
dry_weather_flow: float
the_geom: shapely.Geometry
geom: shapely.Geometry

connection_node_id: int
connection_node_the_geom: shapely.Geometry
Expand All @@ -219,31 +217,19 @@ class BaseSurface:

class Surface(BaseSurface):
"""
Datamodel based on "v2_surface" table
Datamodel based on "surface" table
"""

id: int
function: str
outflow_delay: float
surface_layer_thickness: float
infiltration: float
infiltration: bool
max_infiltration_capacity: float
min_infiltration_capacity: float
infiltration_decay_constant: float
infiltration_recovery_constant: float


class ImperviousSurface(BaseSurface):
"""
Datamodel based on "v2_impervious_surface" table
"""

id: int
surface_inclination: str
surface_class: SurfaceClass
surface_sub_class: str


def fill_missing_centroids(
centroids: np.ndarray, surface_ids: np.ndarray, connection_node_the_geom: np.ndarray
):
Expand Down Expand Up @@ -281,7 +267,7 @@ def as_grid_surfaces(
if extra_fields is None:
extra_fields = {}

centroids = shapely.centroid(self.the_geom)
centroids = shapely.centroid(self.geom)
no_centroid_mask = shapely.is_missing(centroids)

if np.any(no_centroid_mask):
Expand All @@ -298,8 +284,6 @@ def as_grid_surfaces(
area=self.area[self.unique_surfaces_mask],
centroid_x=centroid_coords[:, 0][self.unique_surfaces_mask],
centroid_y=centroid_coords[:, 1][self.unique_surfaces_mask],
dry_weather_flow=self.dry_weather_flow[self.unique_surfaces_mask],
nr_of_inhabitants=self.nr_of_inhabitants[self.unique_surfaces_mask],
**extra_fields
)

Expand Down Expand Up @@ -372,37 +356,10 @@ def as_grid_surfaces(self) -> surfaces.Surfaces:
outflow_delay=self.outflow_delay[unique_surfaces_mask] / 60.0,
storage_limit=self.surface_layer_thickness[unique_surfaces_mask] / 1000.0,
infiltration_flag=self.infiltration[unique_surfaces_mask].astype("bool"),
function=self.function[unique_surfaces_mask],
fb=fb,
fe=fe,
ka=ka,
kh=kh,
)

return super().as_grid_surfaces(extra_fields)


class ImperviousSurfaces(Array[ImperviousSurface], BaseSurfaces):
def as_grid_surfaces(self) -> surfaces.Surfaces:
params = SurfaceParams.from_surface_class_and_inclination(
self.surface_class[self.unique_surfaces_mask],
self.surface_inclination[self.unique_surfaces_mask],
)
surface_sub_class = self.surface_sub_class[self.unique_surfaces_mask]
surface_sub_class[shapely.is_missing(surface_sub_class)] = b""

extra_fields = dict(
surface_inclination=self.surface_inclination[self.unique_surfaces_mask],
surface_class=self.surface_class[self.unique_surfaces_mask],
surface_sub_class=surface_sub_class,
function=np.full(len(self.unique_surfaces_mask), b""),
outflow_delay=params.outflow_delay,
storage_limit=params.surface_storage,
infiltration_flag=params.infiltration,
fb=params.fb,
fe=params.fe,
ka=params.ka,
kh=params.kh,
)

return super().as_grid_surfaces(extra_fields)
54 changes: 3 additions & 51 deletions threedigrid_builder/interface/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
DemAverageAreas,
ExchangeLines,
GridRefinements,
ImperviousSurfaces,
Obstacles,
Orifices,
Pipes,
Expand All @@ -44,7 +43,7 @@
# hardcoded source projection
SOURCE_EPSG = 4326

MIN_SQLITE_VERSION = 222
MIN_SQLITE_VERSION = 223

DAY_IN_SECONDS = 24.0 * 3600.0

Expand Down Expand Up @@ -299,13 +298,10 @@ def get_surfaces(self) -> Surfaces:
arr = (
session.query(
models.Surface.id.label("surface_id"),
models.Surface.function,
models.Surface.code,
models.Surface.display_name,
models.Surface.nr_of_inhabitants,
models.Surface.area,
models.Surface.dry_weather_flow,
models.Surface.the_geom,
models.Surface.geom,
models.SurfaceParameter.outflow_delay,
models.SurfaceParameter.surface_layer_thickness,
models.SurfaceParameter.infiltration,
Expand All @@ -331,7 +327,7 @@ def get_surfaces(self) -> Surfaces:
)

# reproject
arr["the_geom"] = self.reproject(arr["the_geom"])
arr["geom"] = self.reproject(arr["geom"])
arr["connection_node_the_geom"] = self.reproject(
arr["connection_node_the_geom"]
)
Expand All @@ -341,50 +337,6 @@ def get_surfaces(self) -> Surfaces:
**{name: arr[name] for name in arr.dtype.names},
)

def get_impervious_surfaces(self) -> ImperviousSurfaces:
with self.get_session() as session:
arr = (
session.query(
models.ImperviousSurface.id.label("surface_id"),
models.ImperviousSurface.code,
models.ImperviousSurface.display_name,
models.ImperviousSurface.surface_inclination,
models.ImperviousSurface.surface_class,
models.ImperviousSurface.surface_sub_class,
models.ImperviousSurface.nr_of_inhabitants,
models.ImperviousSurface.area,
models.ImperviousSurface.dry_weather_flow,
models.ImperviousSurface.the_geom,
models.ConnectionNode.id.label("connection_node_id"),
models.ConnectionNode.the_geom.label("connection_node_the_geom"),
models.ImperviousSurfaceMap.percentage,
)
.select_from(models.ImperviousSurface)
.join(models.ImperviousSurfaceMap)
.join(
models.ConnectionNode,
models.ImperviousSurfaceMap.connection_node_id
== models.ConnectionNode.id,
)
.order_by(models.ImperviousSurface.id)
.as_structarray()
)

# convert enums to values
arr["surface_class"] = [x.value for x in arr["surface_class"]]
arr["surface_inclination"] = [x.value for x in arr["surface_inclination"]]

# reproject
arr["the_geom"] = self.reproject(arr["the_geom"])
arr["connection_node_the_geom"] = self.reproject(
arr["connection_node_the_geom"]
)

return ImperviousSurfaces(
id=np.arange(0, len(arr["surface_id"] + 1), dtype=int),
**{name: arr[name] for name in arr.dtype.names},
)

def get_boundary_conditions_1d(self) -> BoundaryConditions1D:
"""Return BoundaryConditions1D"""
with self.get_session() as session:
Expand Down
2 changes: 1 addition & 1 deletion threedigrid_builder/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
@pytest.fixture(scope="session")
def db(tmp_path_factory):
"""Yields a threedigrid_builder.interface.db.SQLite object with access
to the test v2_bergermeer.sqlite."""
to the test v2_bergermeer.gpkg."""
fn = tmp_path_factory.mktemp("data") / "v2_bergermeer.gpkg"
sqlite_path = data_path / "v2_bergermeer.gpkg"
shutil.copyfile(sqlite_path, fn)
Expand Down
Binary file modified threedigrid_builder/tests/data/v2_bergermeer.gpkg
Binary file not shown.
11 changes: 3 additions & 8 deletions threedigrid_builder/tests/test_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_init(tmp_path):
with mock.patch(
"threedigrid_builder.interface.db.ThreediDatabase"
) as db, mock.patch.object(SQLite, "get_version") as get_version:
get_version.return_value = 222
get_version.return_value = 223
sqlite = SQLite(path)

db.assert_called_with(path)
Expand Down Expand Up @@ -65,7 +65,7 @@ def test_init_bad_version(tmp_path):


def test_get_version(db):
assert db.get_version() == 222
assert db.get_version() == 223


def test_get_boundary_conditions_1d(db):
Expand All @@ -86,6 +86,7 @@ def test_get_boundary_conditions_2d(db):
assert len(boundary_conditions_2d) == 0


# TODO: fix this, no clue why this fails
def test_get_channels(db):
channels = db.get_channels()
assert isinstance(channels, Channels)
Expand Down Expand Up @@ -391,12 +392,6 @@ def test_get_surfaces(db):
assert len(surfaces) == 0


def test_get_impervious_surfaces(db):
impervious_surfaces = db.get_impervious_surfaces()
# No impervious_surfaces in test dataset
assert len(impervious_surfaces) == 0


def test_get_windshieldings(db):
windshieldings = db.get_windshieldings()
# No windshielding in test dataset
Expand Down
Loading
Loading