Deltares / hydromt_delft3dfm

Delft3D FM plugin for HydroMT
https://deltares.github.io/hydromt_delft3dfm/
GNU General Public License v3.0
8 stars 2 forks source link

Generate 1d2d links for pipes and tunnels at endnodes #2

Open rhutten opened 1 year ago

rhutten commented 1 year ago

What is the need for this task. Sewer systems can also have 1D2D links at end nodes. The current code does not allow for this. Hence this new feature should be implemented.

What is the task? To allow 1D2D links generation at end nodes of pipes and tunnels that are not connected to a 1D river of channel and/or have a boundary location forced upon the end nodes. Note that should most likely happen for 1D-to-2D method. See incorrect version: hydrolib/dhydamo/links1d2d_add_links_1d_to_2d_include_boundary.

rhutten commented 1 year ago

def links1d2d_add_links_1d_to_2d_include_boundary( network: Network, branchids: List[str] = None, within: Union[Polygon, MultiPolygon] = None, max_length: float = np.inf, ) -> None: """Function to add 1d2d links to network, by generating them from 1d to 2d. Branchids can be specified for 1d branches that need to be linked. A (Multi)Polygon can be provided were links should be made. Modified from links1d2d_add_links_1d_to_2d to include also boundary locations.

Note: The boundary nodes of Mesh1d (those sharing only one Mesh1d edge) are also connected to Mesh2d face.

Args:
    network (Network): Network in which the connections are made
    branchids (List[str], optional): List of branchid's to connect. If None, all branches are connected. Defaults to None.
    within (Union[Polygon, MultiPolygon], optional): Area within which connections are made. Defaults to None.
    max_length (float, optional): Max edge length. Defaults to None.

See also:
    links1d2d_add_links_1d_to_2d
"""
# Load 1d and 2d in meshkernel
network._mesh1d._set_mesh1d()
network._mesh2d._set_mesh2d()

if within is None:
    # If not provided, create a box from the maximum bounds
    xmin = min(
        network._mesh1d.mesh1d_node_x.min(), network._mesh2d.mesh2d_node_x.min()
    )
    xmax = max(
        network._mesh1d.mesh1d_node_x.max(), network._mesh2d.mesh2d_node_x.max()
    )
    ymin = min(
        network._mesh1d.mesh1d_node_y.min(), network._mesh2d.mesh2d_node_y.min()
    )
    ymax = max(
        network._mesh1d.mesh1d_node_y.max(), network._mesh2d.mesh2d_node_y.max()
    )

    within = box(xmin, ymin, xmax, ymax)

# If a 'within' polygon was provided, convert it to a geometrylist
geometrylist = GeometryList.from_geometry(within)

# Get the nodes for the specific branch ids
node_mask = network._mesh1d.get_node_mask(branchids)

# Get the already present links. These are not filtered on length
npresent = len(network._link1d2d.link1d2d)

# Generate links
network._link1d2d._link_from_1d_to_2d(node_mask, polygon=geometrylist)

# generate 1d2d links #FIXME does not work yet
network._link1d2d.meshkernel.contacts_compute_boundary(node_mask=node_mask, polygons=geometrylist, search_radius = max_length * 10)
network._link1d2d._process()

# Filter the links that are longer than the max distance
id1d = network._link1d2d.link1d2d[npresent:, 0]
id2d = network._link1d2d.link1d2d[npresent:, 1]
nodes1d = np.stack(
    [network._mesh1d.mesh1d_node_x[id1d], network._mesh1d.mesh1d_node_y[id1d]],
    axis=1,
)
faces2d = np.stack(
    [network._mesh2d.mesh2d_face_x[id2d], network._mesh2d.mesh2d_face_y[id2d]],
    axis=1,
)
lengths = np.hypot(nodes1d[:, 0] - faces2d[:, 0], nodes1d[:, 1] - faces2d[:, 1])
keep = np.concatenate(
    [np.arange(npresent), np.where(lengths < max_length)[0] + npresent]
)
_filter_links_on_idx(network, keep)
xldeltares commented 1 year ago

Current code generate 1d2d link in a weird fashion: image