Skip to main content

Optimal Channel Networks (OCN) in Python with a C core

Project description

PyOCN

This is a package to generate optimal channel networks (OCNs), based on the algorithm described in Carraro et al. (2020). Generation and application of river network analogues for use in ecology and evolution. Ecology and Evolution. doi:10.1002/ece3.6479 and mirrors some of the functionality of the OCNet R package (https://lucarraro.github.io/OCNet/).

This is a work in progress. I plan to release this as a package on PyPI in the near future. For now, you can clone the repository and build the package from source.

To compile libocn with gcc on MacOS or Linux, move the root directory into your project's working directory andrun the following commands from the root directory:

cd PyOCN/c_src
bash build.sh

or alternatively:

cd PyOCN/c_src
gcc -fPIC -O3 -flto -c ocn.c flowgrid.c status.c rng.c
gcc -shared -O3 -flto -o libocn.so ocn.o flowgrid.o status.o rng.o
mv libocn.so ../libocn.so
rm -f ocn.o flowgrid.o status.o rng.o

If you have any questions or comments, please open an issue or contact me directly at https://www.afox.land

OCN Algorithm

An initial stream network is generated as a directed acyclic graph (DAG) that is a spanning tree over a 2d grid of cells. Each cell in the grid (except the root) has a single outgoing edge that connects to one of its 8 neighboring cells. The OCN algorithm then iteratively modifies the DAG by randomly selecting a cell and changing its outflow to point to a different neighbor, ensuring that the spanning tree structure is maintained (i.e. no cycles are introduced and each cell has a single outflow, except for the root cell). The total energy at cell $k$ after iteration $n$ is given by:

$$ E_k[n] = \sum_{i} A_i^\gamma[n] $$

Where $A_i$ is the cumulative drained area at cell $i$, and $i\in\mathrm{drained}(k)$ is a cell drained by $k$, including itself, and $\gamma$ controls how the energy scales with area. This change is accepted or rejected based on an annealing method, which is related to the Metropolis-Hastings algorithm. The probability of accepting a proposed change to the network is given by:

$$ P(\mathrm{accept}) = \min\left(1, \exp\left(-\frac{E_\mathrm{root}[n] - E_\mathrm{root}[n-1]}{T[n]}\right)\right) $$

Where $T[n]$ is the "temperature" of the network at iteration $n$. Initially, the temperature is set to a high value ($\sim E[0]$) to encourage exploration of the solution space. The temperature is then set to exponentially decay over time, "annealing" the network as it settles into a low-energy configuration. Note that a proposed change is always accepted if it results in a lower energy state ($E[n] < E[n-1]$).

Lower values of gamma allow very dendritic networks with lots fo branching. The following animation shows the process of optimizing an OCN with $\gamma=0.7$ on a 256x256 grid for 4M iterations, which took about 2 minutes to run on a Macbook pro.

Optimizing an OCN

libocn

The backend of PyOCN is the libocn C library. libocn implements the core algorithms for generating and manipulating OCNs. Unlike the OCNet R package which uses an adjacency matrix implementation representation of the flow grid (based on the SPArse Matrix library), the libocn C library directly represents the network as a DAG. Each grid cell in the network has an associated outflow direction (given as an integer, 0-7, representing the 8 possible directions to neighboring cells) and a list of the directions of its neighbors (given as an 8-bit integer, where each bit indicates whether there is an edge connecting the cell to one of its 8 neighbors). libocn also implements functions to traverse and manipulate the network structure according to the simulated annealing algorithm described in the orginal paper.

PyOCN

The PyOCN frontend is a Python package that provides a high-level interface to the libocn C library. PyOCN uses the NetworkX library to expose the network graph and provides additional functions to manipulate and analyze the graph, as well as export the graph to various formats, including GeoTIFF. The main class in PyOCN is the OCN class, which includes methods for constructing an initial configuration and running the optimization algorithm.

Citing PyOCN

If you use PyOCN in your research, please cite this package and the original paper by Carraro et al.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyocn-1.0.20251001.tar.gz (45.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyocn-1.0.20251001-cp311-cp311-macosx_11_0_arm64.whl (54.7 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

File details

Details for the file pyocn-1.0.20251001.tar.gz.

File metadata

  • Download URL: pyocn-1.0.20251001.tar.gz
  • Upload date:
  • Size: 45.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for pyocn-1.0.20251001.tar.gz
Algorithm Hash digest
SHA256 520f8d865209cd9288ce4316378faeb8d2ab6997b76599da6bb9c85d23d5bb7c
MD5 e52cec4c3df6867dbb752c22c6920a1b
BLAKE2b-256 2fe7b1452cbd9c4f4ea49d46880f08ba408fc5095742dc7d588f070793321347

See more details on using hashes here.

File details

Details for the file pyocn-1.0.20251001-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyocn-1.0.20251001-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4aeb857d5fcb1a5e45c3ca70fe29e9a90578e2e1886bf4b4e97930f3eaab263e
MD5 d90538b071736cf650f363cbd8e98f22
BLAKE2b-256 34988cb007353b8ccda2b58088598d7b1a60dfdd0c84ba57f31e2c0c137b1453

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page