-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Start to add graphflood * trying to pull request * update that branch to match newer interface (not ready to merge) * Update to latest upstream libttb and pytopotools * reformat ipynb I ran * Comply to flake8 format * sort type conflict * Use version 2024-W40 of libtopotoolbox --------- Co-authored-by: William Kearney <[email protected]>
- Loading branch information
1 parent
996ec57
commit 58e2d42
Showing
32 changed files
with
312 additions
and
3 deletions.
There are no files selected for viewing
Empty file.
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
Empty file.
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
// This file contains bindings for the fillsinks function using PyBind11. | ||
|
||
extern "C" { | ||
#include <topotoolbox.h> | ||
} | ||
|
||
#include <pybind11/pybind11.h> | ||
#include <pybind11/numpy.h> | ||
#include <stdbool.h> | ||
#include <stdio.h> | ||
#include <iostream> | ||
|
||
namespace py = pybind11; | ||
|
||
|
||
/* | ||
Runs the full graphflood's algorithm as described in Gailleton et al., 2024 | ||
Z: 1D numpy array (n nodes) of topography (type np.float32) | ||
hw: 1D numpy array (n nodes) of flow depth type np.float32) | ||
BCs: 1D numpy array (n nodes) of boundary codes (type np.uint8) | ||
Precipitations: 1D numpy array (n nodes) of precipitation rates in m.s-1 (type np.float32) | ||
manning: 1D numpy array (n nodes) of friction coefficient (type np.float32) | ||
dim: [nrows,ncolumns] for row major (e.g. python) or [ncolumns, nrows] for column major. Numpy array as np.uint64. | ||
dt: time step (s ~ although this is not simulated time as we make the steady low assumption) | ||
dx: spatial step (m) | ||
D8: true to include diagonal paths | ||
N_iterations: how many iterations to run | ||
B.G. (last modification: 08/2024) | ||
*/ | ||
void wrap_graphflood_full( | ||
py::array_t<GF_FLOAT> Z, | ||
py::array_t<GF_FLOAT> hw, | ||
py::array_t<uint8_t> BCs, | ||
py::array_t<GF_FLOAT> Precipitations, | ||
py::array_t<GF_FLOAT> manning, | ||
py::array_t<GF_UINT> dim, | ||
GF_FLOAT dt, | ||
GF_FLOAT dx, | ||
bool SFD, | ||
bool D8, | ||
GF_UINT N_iterations, | ||
GF_FLOAT step | ||
){ | ||
|
||
// numpy arrays to pointers | ||
GF_FLOAT* Z_ptr = Z.mutable_data() ; | ||
GF_FLOAT* hw_ptr = hw.mutable_data() ; | ||
uint8_t* BCs_ptr = BCs.mutable_data() ; | ||
GF_FLOAT* Precipitations_ptr = Precipitations.mutable_data() ; | ||
GF_FLOAT* manning_ptr = manning.mutable_data() ; | ||
GF_UINT* dim_ptr = dim.mutable_data() ; | ||
|
||
// calling the C function | ||
graphflood_full(Z_ptr, hw_ptr, BCs_ptr, Precipitations_ptr, manning_ptr, dim_ptr, dt, dx, SFD, D8, N_iterations, step); | ||
} | ||
|
||
|
||
/* | ||
Computes a single flow graph compatible with the boundary conditions system of graphflood | ||
topo: 1D numpy array (n nodes) of topography (type np.float32) | ||
Sreceivers: 1D numpy array (n nodes), flat index of steepest receiver (type np.uint64) | ||
distToReceivers: 1D numpy array (n nodes), distance to steepest receiver (type np.float32) | ||
Sdonors: 1D numpy array (n nodes * 4 or 8), flat index of donors (type np.uint64) | ||
NSdonors: 1D numpy array (n nodes ), flat index of number of steepest donors (type np.uint8) | ||
Stack: Topologically ordered nodes from downstream to upstream (stakc in Braun and Willett 2013) | ||
BCs: 1D numpy array (n nodes) of boundary codes (type np.uint8) | ||
dim: [nrows,ncolumns] for row major (e.g. python) or [ncolumns, nrows] for column major. Numpy array as np.uint64. | ||
dx: spatial step (m) | ||
D8: true to include diagonal paths | ||
PF: true to also fill the topography using priority flood (Barnes, 2014) | ||
B.G. (last modification: 08/2024) | ||
*/ | ||
void wrap_compute_sfgraph( | ||
py::array_t<GF_FLOAT> topo, | ||
py::array_t<GF_UINT> Sreceivers, | ||
py::array_t<GF_FLOAT> distToReceivers, | ||
py::array_t<GF_UINT> Sdonors, | ||
py::array_t<uint8_t> NSdonors, | ||
py::array_t<GF_UINT> Stack, | ||
py::array_t<uint8_t> BCs, | ||
py::array_t<GF_UINT> dim, | ||
GF_FLOAT dx, | ||
bool D8, | ||
bool PF, | ||
GF_FLOAT step | ||
){ | ||
|
||
GF_FLOAT *topo_ptr = topo.mutable_data() ; | ||
GF_UINT *Sreceivers_ptr = Sreceivers.mutable_data() ; | ||
GF_FLOAT *distToReceivers_ptr = distToReceivers.mutable_data() ; | ||
GF_UINT *Sdonors_ptr = Sdonors.mutable_data() ; | ||
uint8_t *NSdonors_ptr = NSdonors.mutable_data() ; | ||
GF_UINT *Stack_ptr = Stack.mutable_data() ; | ||
uint8_t *BCs_ptr = BCs.mutable_data() ; | ||
GF_UINT *dim_ptr = dim.mutable_data() ; | ||
|
||
if(PF) | ||
compute_sfgraph_priority_flood(topo_ptr, Sreceivers_ptr, distToReceivers_ptr, Sdonors_ptr, NSdonors_ptr, Stack_ptr, BCs_ptr, dim_ptr, dx, D8, step); | ||
else | ||
compute_sfgraph(topo_ptr, Sreceivers_ptr, distToReceivers_ptr, Sdonors_ptr, NSdonors_ptr, Stack_ptr, BCs_ptr, dim_ptr, dx, D8); | ||
|
||
} | ||
|
||
void wrap_compute_drainage_area_single_flow( | ||
py::array_t<GF_FLOAT> output, | ||
py::array_t<GF_UINT> Sreceivers, | ||
py::array_t<GF_UINT> Stack, | ||
py::array_t<GF_UINT> dim, | ||
GF_FLOAT dx | ||
){ | ||
|
||
GF_FLOAT* output_ptr = output.mutable_data(); | ||
GF_UINT* Sreceivers_ptr = Sreceivers.mutable_data(); | ||
GF_UINT* Stack_ptr = Stack.mutable_data(); | ||
GF_UINT* dim_ptr = dim.mutable_data(); | ||
|
||
|
||
compute_drainage_area_single_flow(output_ptr, Sreceivers_ptr, Stack_ptr, dim_ptr, dx); | ||
} | ||
|
||
void wrap_compute_priority_flood_plus_stack( | ||
py::array_t<GF_FLOAT> topo, | ||
py::array_t<GF_UINT> Stack, | ||
py::array_t<uint8_t> BCs, | ||
py::array_t<GF_UINT> dim, | ||
bool D8 , | ||
GF_FLOAT step | ||
){ | ||
|
||
GF_FLOAT* topo_ptr = topo.mutable_data(); | ||
GF_UINT* Stack_ptr = Stack.mutable_data(); | ||
uint8_t* BCs_ptr = BCs.mutable_data(); | ||
GF_UINT* dim_ptr = dim.mutable_data(); | ||
|
||
// First priority flooding and calculating stack | ||
compute_priority_flood_plus_topological_ordering(topo_ptr, Stack_ptr, BCs_ptr, dim_ptr, D8,step); | ||
} | ||
|
||
void wrap_compute_priority_flood( | ||
py::array_t<GF_FLOAT> topo, | ||
py::array_t<uint8_t> BCs, | ||
py::array_t<GF_UINT> dim, | ||
bool D8 , | ||
GF_FLOAT step | ||
){ | ||
|
||
GF_FLOAT* topo_ptr = topo.mutable_data(); | ||
uint8_t* BCs_ptr = BCs.mutable_data(); | ||
GF_UINT* dim_ptr = dim.mutable_data(); | ||
|
||
// First priority flooding and calculating stack | ||
compute_priority_flood(topo_ptr, BCs_ptr, dim_ptr, D8,step); | ||
} | ||
|
||
|
||
// Make wrap_funcname() function available as grid_funcname() to be used by | ||
// by functions in the pytopotoolbox package | ||
|
||
PYBIND11_MODULE(_graphflood, m) { | ||
m.def("graphflood_run_full", &wrap_graphflood_full); | ||
m.def("graphflood_sfgraph", &wrap_compute_sfgraph); | ||
m.def("compute_priority_flood_plus_topological_ordering", &wrap_compute_priority_flood_plus_stack); | ||
m.def("compute_priority_flood", &wrap_compute_priority_flood); | ||
m.def("compute_drainage_area_single_flow", &wrap_compute_drainage_area_single_flow); | ||
|
||
|
||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
from .grid_object import GridObject # noqa | ||
from .flow_object import FlowObject # noqa | ||
from .utils import * # noqa | ||
from .graphflood import * # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
""" | ||
Basic interface to libtopotoolbox implementation of graphflood | ||
""" | ||
|
||
from .grid_object import GridObject | ||
import numpy as np | ||
from ._graphflood import ( # type: ignore | ||
graphflood_run_full, | ||
graphflood_sfgraph, | ||
compute_priority_flood_plus_topological_ordering, | ||
compute_priority_flood, | ||
compute_drainage_area_single_flow | ||
) | ||
from copy import deepcopy | ||
|
||
# exposing function as string dictionary | ||
funcdict = { | ||
"run_full": graphflood_run_full, | ||
"sfgraph": graphflood_sfgraph, | ||
"priority_flood_TO": compute_priority_flood_plus_topological_ordering, | ||
"priority_flood": compute_priority_flood, | ||
"drainage_area_single_flow": compute_drainage_area_single_flow, | ||
} | ||
|
||
__all__ = ["run_graphflood"] | ||
|
||
|
||
def run_graphflood( | ||
grid: GridObject, | ||
initial_hw=None, | ||
BCs=None, | ||
dt=1e-3, | ||
P=10 * 1e-3 / 3600, | ||
manning=0.033, | ||
SFD=False, | ||
D8=True, | ||
N_iterations=100, | ||
): | ||
|
||
# Preparing the arguments | ||
ny = grid.rows | ||
nx = grid.columns | ||
dx = grid.cellsize | ||
dim = np.array([ny, nx], dtype=np.uint64) | ||
|
||
# Order C for vectorised topography | ||
Z = grid.z.ravel(order="C") | ||
|
||
# Ingesting the flow depth | ||
if initial_hw is None: | ||
hw = np.zeros_like(Z) | ||
else: | ||
if initial_hw.shape != grid.z.shape: | ||
raise RuntimeError( | ||
"""Feeding the model with initial flow depth | ||
requires a 2D numpy array or a GridObject of | ||
the same dimension of the topographic grid""" | ||
) | ||
|
||
if isinstance(grid, GridObject): | ||
hw = initial_hw.z.ravel(order="C") | ||
else: | ||
hw = initial_hw.ravel(order="C") | ||
|
||
# Ingesting boundary condition | ||
if BCs is None: | ||
tBCs = np.ones((grid.rows, grid.columns), dtype=np.uint8) | ||
tBCs[[0, -1], :] = 3 | ||
tBCs[:, [0, -1]] = 3 | ||
tBCs = tBCs.ravel(order="C") | ||
else: | ||
if BCs.shape != grid.shape: | ||
raise RuntimeError( | ||
"""Feeding the model with boundary conditions requires | ||
a 2D numpy array or a GridObject of the same dimension | ||
of the topographic grid""" | ||
) | ||
|
||
if isinstance(BCs, GridObject): | ||
tBCs = BCs.z.ravel(order="C").astype(np.uint8) | ||
else: | ||
tBCs = BCs.ravel(order="C").astype(np.uint8) | ||
|
||
# Ingesting Precipitations | ||
if isinstance(P, np.ndarray): | ||
if P.shape != grid.shape: | ||
raise RuntimeError( | ||
"""Feeding the model with precipitations requires a | ||
2D numpy array or a GridObject of the same | ||
dimension of the topographic grid""" | ||
) | ||
Precipitations = P.ravel(order="C") | ||
elif isinstance(P, GridObject): | ||
if P.shape != grid.shape: | ||
raise RuntimeError( | ||
"""Feeding the model with precipitations requires a | ||
2D numpy array or a GridObject of the same dimension | ||
of the topographic grid""" | ||
) | ||
Precipitations = P.z.ravel(order="C") | ||
else: | ||
# in case precipitation is a scalar | ||
Precipitations = np.full_like(Z, P) | ||
|
||
# Ingesting manning | ||
if isinstance(manning, np.ndarray): | ||
if manning.shape != grid.shape: | ||
raise RuntimeError( | ||
"""Feeding the model with precipitations requires a | ||
2D numpy array or a GridObject of the same dimension | ||
of the topographic grid""" | ||
) | ||
manning = manning.ravel(order="C") | ||
elif isinstance(manning, GridObject): | ||
if manning.shape != grid.shape: | ||
raise RuntimeError( | ||
"""Feeding the model with precipitations requires a | ||
2D numpy array or a GridObject of the same dimension | ||
of the topographic grid""" | ||
) | ||
manning = manning.z.ravel(order="C") | ||
else: | ||
# in case precipitation is a scalar | ||
manning = np.full_like(Z, manning) | ||
|
||
graphflood_run_full( | ||
Z, hw, tBCs, Precipitations, manning, | ||
dim, dt, dx, SFD, D8, N_iterations, 1e-3 | ||
) | ||
res = deepcopy(grid) | ||
|
||
res.z = hw.reshape(grid.shape) | ||
|
||
return res |
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.