diff --git a/.github/workflows/bundle-release.yml b/.github/workflows/bundle-release.yml index 1c981372..78fdcc98 100644 --- a/.github/workflows/bundle-release.yml +++ b/.github/workflows/bundle-release.yml @@ -54,10 +54,10 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Copy existing PDFs from docs/end-user-docs + - name: Copy existing PDFs from docs/end_user_docs run: | - echo "Copying existing PDFs from docs/end-user-docs/source..." - cp docs/end-user-docs/*.pdf bundle/docs/ 2>/dev/null || echo "No PDFs found in source directory" + echo "Copying existing PDFs from docs/end_user_docs/source..." + cp docs/end_user_docs/*.pdf bundle/docs/ 2>/dev/null || echo "No PDFs found in source directory" echo "PDFs copied to bundle/docs:" ls -lh bundle/docs/ diff --git a/.github/workflows/generate-latex.yml b/.github/workflows/generate-latex.yml index 1301e6d6..278f438c 100644 --- a/.github/workflows/generate-latex.yml +++ b/.github/workflows/generate-latex.yml @@ -2,39 +2,27 @@ name: Generate LaTeX Documentation on: workflow_dispatch: # Manual trigger - workflow_run: # Auto-trigger when release.yml completes - workflows: ["Automated release workflow"] - types: - - completed release: # Trigger on manual release creation types: [created, published] -permissions: - contents: write - -env: - SVN_USERNAME: ${{ secrets.SVN_USERNAME }} - SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} - SVN_REPO_URL: ${{ secrets.SVN_REPO_URL }} - jobs: - generate-latex: + build-pdf: runs-on: ubuntu-latest + permissions: + contents: read # ← unprivileged - only read access needed for build # Only run if triggered by workflow_dispatch, release, pull_request, or if workflow_run completed successfully if: | github.event_name == 'workflow_dispatch' || - github.event_name == 'release' || - github.event_name == 'pull_request' || - (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') + github.event_name == 'release' steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: - ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.ref }} + ref: ${{ github.event_name == 'workflow_run' && github.event.repository.default_branch || github.ref }} - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version: '3.11' @@ -45,7 +33,7 @@ jobs: pandoc --version - name: Install uv - uses: astral-sh/setup-uv@v4 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 #v7 with: enable-cache: true cache-dependency-glob: uv.lock @@ -55,51 +43,59 @@ jobs: uv lock --check || uv lock - name: Install Dependencies - run: uv sync --group dev --group docs + run: uv sync --group dev --group docs # NOSONAR - name: list env contents run: | uv pip list - - name: Install Subversion - run: | - sudo apt-get update - sudo apt-get install -y subversion + - name: Checkout Deltares LaTeX styles from internal GitHub repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + repository: Deltares/LatexInstallation + token: ${{ secrets.LATEX_REP_TOKEN }} + path: temp_latex + ref: main - - name: Checkout Deltares LaTeX styles from SVN + - name: Copy Deltares LaTeX styles to source directory run: | - cd docs/end-user-docs - - # Checkout SVN repository with error handling - if ! svn checkout --username "${{ secrets.SVN_USERNAME }}" --password "${{ secrets.SVN_PASSWORD }}" --non-interactive --trust-server-cert "${{ secrets.SVN_REPO_URL }}" temp_svn; then - echo "::error::Failed to checkout SVN repository" - exit 1 - fi + cd docs/end_user_docs # List available directories for debugging - echo "Available LaTeX directories in SVN:" - ls -la temp_svn/templates/latex/tex/latex/ || echo "Directory structure different than expected" + echo "Available LaTeX directories in GitHub repo:" + ls -la ../../temp_latex/MiKTeX/tex/latex/ || echo "Directory structure different than expected" # Copy Deltares styles with error handling - if [ -d "temp_svn/templates/latex/tex/latex/deltares" ]; then - cp -r temp_svn/templates/latex/tex/latex/deltares/* source/ || echo "::warning::Failed to copy deltares styles" + if [ -d "../../temp_latex/MiKTeX/tex/latex/deltares" ]; then + cp -r ../../temp_latex/MiKTeX/tex/latex/deltares/* source/ + echo "✓ Copied deltares styles" + else + echo "::warning::deltares styles directory not found" fi - if [ -d "temp_svn/templates/latex/tex/latex/nomentbl/deltares" ]; then - cp -r temp_svn/templates/latex/tex/latex/nomentbl/deltares/* source/ || echo "::warning::Failed to copy nomentbl styles" + if [ -d "../../temp_latex/MiKTeX/tex/latex/nomentbl/deltares" ]; then + cp -r ../../temp_latex/MiKTeX/tex/latex/nomentbl/deltares/* source/ + echo "✓ Copied nomentbl styles" + else + echo "::warning::nomentbl styles directory not found" fi - if [ -d "temp_svn/templates/latex/bibtex/bst/deltares" ]; then - cp -r temp_svn/templates/latex/bibtex/bst/deltares/* source/ || echo "::warning::Failed to copy bibtex styles" + if [ -d "../../temp_latex/MiKTeX/bibtex/bst/deltares/" ]; then + cp -r ../../temp_latex/MiKTeX/bibtex/bst/deltares/* source/ + echo "✓ Copied bibtex styles" + else + echo "::warning::bibtex styles directory not found" fi - rm -rf temp_svn - - name: Generate LaTeX from Markdown (user_docs) run: | - uv run ddocs markdown-to-latex \ - --input docs/mkdocs/user_docs \ - --output docs/end-user-docs/source + .venv/bin/ddocs markdown-to-latex \ + --input docs/user_docs \ + --output docs/end_user_docs/source + + - name: Generate LaTeX from Markdown (changelog) + run: | + .venv/bin/pandoc -o docs/end_user_docs/source/changelog.tex docs/CHANGELOG.md - name: Install LaTeX run: | @@ -114,37 +110,40 @@ jobs: pdflatex --version - - name: Compile PDF with pdflatex and bibtex + - name: Make build script executable + run: chmod +x docs/end_user_docs/build_pdf.sh + + - name: Build PDF documentation with version run: | - cd docs/end-user-docs/source - pdflatex fm2prof_user_manual.tex - pdflatex fm2prof-release-notes.tex - # Run bibtex if citations exist, otherwise skip - if grep -q '\\citation' fm2prof_user_manual.aux 2>/dev/null; then - bibtex fm2prof_user_manual - bibtex fm2prof-release-notes - else - echo "No citations found, skipping bibtex" - fi - pdflatex fm2prof_user_manual.tex - pdflatex fm2prof-release-notes.tex - pdflatex fm2prof_user_manual.tex - pdflatex fm2prof-release-notes.tex + cd docs/end_user_docs + ./build_pdf.sh - name: List generated files run: | echo "Generated LaTeX files:" - find docs/end-user-docs/source -name "*.tex" -type f + find docs/end_user_docs/source -name "*.tex" -type f + echo "" echo "Generated PDF files:" - find docs/end-user-docs/source -name "*.pdf" -type f + find docs/end_user_docs/source -name "*.pdf" -type f - name: Upload PDF artifact uses: actions/upload-artifact@v4 with: name: Documentations - path: docs/end-user-docs/source/*.pdf + path: docs/end_user_docs/source/*.pdf retention-days: 3 + upload_to_release: + runs-on: ubuntu-latest + needs: build-pdf + permissions: + contents: write # priviliged, has write access. + steps: + - name: Download PDF artifact + uses: actions/download-artifact@v4 + with: + name: Documentations + path: pdfs/ - name: Get release tag id: get_tag if: github.event_name == 'release' || github.event_name == 'workflow_run' @@ -165,6 +164,6 @@ jobs: with: tag_name: ${{ steps.get_tag.outputs.tag }} files: | - docs/end-user-docs/source/*.pdf + docs/end_user_docs/source/*.pdf env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 53087270..ccb8d4a6 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,8 @@ /tests/test_data/compare1d2d/rijn-j22_6-v1a2/output/** testIni.ini *_cache.json +# notebooks +**.ipynb_checkpoints** # pixi environments .pixi/* !.pixi/config.toml diff --git a/docs/guides/release.md b/docs/dev_docs/commitizen_release.md similarity index 100% rename from docs/guides/release.md rename to docs/dev_docs/commitizen_release.md diff --git a/docs/markdown/contributing.md b/docs/dev_docs/contributing.md similarity index 96% rename from docs/markdown/contributing.md rename to docs/dev_docs/contributing.md index c4c352fd..f6d70e1e 100644 --- a/docs/markdown/contributing.md +++ b/docs/dev_docs/contributing.md @@ -1,120 +1,120 @@ -# Contributing - -This is brief guide on how to contribute to the code. This guide is -written for Deltares developers. At the moment, we are not accepting -external pull requests. - -## Set up development environment - -### Dependency management -Dependencies are managed through the standard [pyproject.toml](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/) -configuration file. - -Lock files are maintained for the [uv](https://docs.astral.sh/uv/) and [pixi](https://pixi.sh/latest/python/tutorial/) -environment managers, but note that our CI system uses `uv`. We therefore recommend using the [uv](https://docs.astral.sh/uv/). - -With a supported environment manager installed, set up your development environment using the `lock` command. This will create a virtual environment. - -=== "uv" - - ``` bash - git clone https://github.com/Deltares/Fm2Prof.git - cd Fm2Prof - uv lock - ``` - -=== "pixi" - - ``` bash - git clone https://github.com/Deltares/Fm2Prof.git - cd Fm2Prof - pixi lock - ``` - - - -## Style & documentation conventions - -We use [ruff](https://github.com/astral-sh/ruff) for linting and code formatting. -Documentation is based on [mkdocs](https://www.mkdocs.org/) and [mkdocstringds](https://mkdocstrings.github.io/#:~:text=mkdocstrings.%20Automatic%20documentation%20from%20sources,%20for). Numpy, sphinx and google-style -docstrings are supported, but when writing new code please use [Google-style docstring syntax](https://mkdocstrings.github.io/griffe/docstrings/#google-style) - -To support documentation for multiple versions, we use the [mike](https://github.com/jimporter/mike) preprocessor. -See "How to make a new release" below on how to use mike. - -## Testing - -Automatic tests are run on each pull request and push. A PR cannot be merged -unless all tests are passing. To run tests locally, use `pytest`: - -=== "uv" - - ``` bash - uv run pytest --cov=fm2prof - ``` - -=== "pixi" - - ``` bash - pixi run -e dev pytest --cov=fm2prof - ``` - - -## Deploying - -### Locally build executable (optional) - -To build a local version of an FM2PROF executable, run: - -`uv run pyinstaller FM2PROF_WINDOWS.spec` - -!!! note - - Executables are no longer automatically made since fm2prof was published on pypi - - -### How to make a new release - -Publishing a new release takes some steps. - -#### Tag your version -After merging a PR to `master`, first make a new tag. Using version `v2.3.0` as an example, -a tag can be made via the terminal: - -``` bash -git tag v2.3.0 -``` -#### Make a new release - -Use Github interface to draft a new release using the appropriate. Document all changes since the previous version. -If possible, refer to Github Issues. - -#### Update the documentation -We use [mike](https://github.com/jimporter/mike) as a pre-processor for `mkdocs`. To update the documentation -for a new release, use the following line in a terminal: - -``` bash -uv run mike deploy 2.3.0 latest -u -``` - -This will build the documentation for a specific version (e.g. `2.3.0` for version v2.3.0). The keyword -`latest` will set this to be the default version. The flag `-u` will overwrite any -existing documentation for this versino. - -Finally, you need to push the documentation to github. First, checkout the documentation branch - -``` bash -git checkout gh-pages -``` - -and then push changes to github - -``` bash -git push -``` - -The documentation is hosted on github pages, no other steps are necessary. - - - - +# Contributing + +This is brief guide on how to contribute to the code. This guide is +written for Deltares developers. At the moment, we are not accepting +external pull requests. + +## Set up development environment + +### Dependency management +Dependencies are managed through the standard [pyproject.toml](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/) +configuration file. + +Lock files are maintained for the [uv](https://docs.astral.sh/uv/) and [pixi](https://pixi.sh/latest/python/tutorial/) +environment managers, but note that our CI system uses `uv`. We therefore recommend using the [uv](https://docs.astral.sh/uv/). + +With a supported environment manager installed, set up your development environment using the `lock` command. This will create a virtual environment. + +=== "uv" + + ``` bash + git clone https://github.com/Deltares/Fm2Prof.git + cd Fm2Prof + uv lock + ``` + +=== "pixi" + + ``` bash + git clone https://github.com/Deltares/Fm2Prof.git + cd Fm2Prof + pixi lock + ``` + + + +## Style & documentation conventions + +We use [ruff](https://github.com/astral-sh/ruff) for linting and code formatting. +Documentation is based on [mkdocs](https://www.mkdocs.org/) and [mkdocstringds](https://mkdocstrings.github.io/#:~:text=mkdocstrings.%20Automatic%20documentation%20from%20sources,%20for). Numpy, sphinx and google-style +docstrings are supported, but when writing new code please use [Google-style docstring syntax](https://mkdocstrings.github.io/griffe/docstrings/#google-style) + +To support documentation for multiple versions, we use the [mike](https://github.com/jimporter/mike) preprocessor. +See "How to make a new release" below on how to use mike. + +## Testing + +Automatic tests are run on each pull request and push. A PR cannot be merged +unless all tests are passing. To run tests locally, use `pytest`: + +=== "uv" + + ``` bash + uv run pytest --cov=fm2prof + ``` + +=== "pixi" + + ``` bash + pixi run -e dev pytest --cov=fm2prof + ``` + + +## Deploying + +### Locally build executable (optional) + +To build a local version of an FM2PROF executable, run: + +`uv run pyinstaller FM2PROF_WINDOWS.spec` + +!!! note + + Executables are no longer automatically made since fm2prof was published on pypi + + +### How to make a new release + +Publishing a new release takes some steps. + +#### Tag your version +After merging a PR to `master`, first make a new tag. Using version `v2.3.0` as an example, +a tag can be made via the terminal: + +``` bash +git tag v2.3.0 +``` +#### Make a new release + +Use Github interface to draft a new release using the appropriate. Document all changes since the previous version. +If possible, refer to Github Issues. + +#### Update the documentation +We use [mike](https://github.com/jimporter/mike) as a pre-processor for `mkdocs`. To update the documentation +for a new release, use the following line in a terminal: + +``` bash +uv run mike deploy 2.3.0 latest -u +``` + +This will build the documentation for a specific version (e.g. `2.3.0` for version v2.3.0). The keyword +`latest` will set this to be the default version. The flag `-u` will overwrite any +existing documentation for this versino. + +Finally, you need to push the documentation to github. First, checkout the documentation branch + +``` bash +git checkout gh-pages +``` + +and then push changes to github + +``` bash +git push +``` + +The documentation is hosted on github pages, no other steps are necessary. + + + + diff --git a/docs/end-user-docs/source/fm2prof-release-notes.tex b/docs/end-user-docs/source/fm2prof-release-notes.tex deleted file mode 100644 index 5ae8090f..00000000 --- a/docs/end-user-docs/source/fm2prof-release-notes.tex +++ /dev/null @@ -1,68 +0,0 @@ -\documentclass[git]{deltares_manual} -\usepackage{adjustbox} - -%------------------------------------------------------------------------------ -\newcommand{\fmprof}{\textrm{FM2Prof}\xspace} -\newcommand{\fmprofversion}{2.4.0} -\hypersetup -{ - pdfauthor = {Deltares}, - pdftitle = {\fmprof}, - pdfkeywords = {Release Notes \fmprof} -} - -\begin{document} - \pagestyle{empty} - \includepdf[pages=1, offset=72 -70]{cover/fm2prof-omslagen_RN.pdf} % links-rechts past precies - \cleardoublepage - - \title{\fmprof \fmprofversion} - \subtitle{} - \manualtype{Release Notes} - - \version{\the\year.\the\month} - - \author{Koen Berends} - - \setgitdirectory{./../../.git} - \deltarestitle - - \chapter{Introduction}\label{ch:introduction} - - \section{Release contents}\label{sec:release-contents} - - \begin{tabular}{ll} - Description: & \fmprof \\ - Version: & \fmprofversion \\ - Status: & release - \end{tabular} - - \fbox{% - \parbox{\textwidth}{% - \fmprof~\fmprofversion <<>> - <> - .}} - - \section{Installation}\label{sec:installation} - \fmprof is distributed as a plain zip-file. - The installation procedure is described in the \fmprof, User Manual. - - \section {Documentation list}\label{sec:documentation-list} - The following documentation is distributed with this release: - - \begin{enumerate} - \item \fmprof, Release notes (this document) - \item \fmprof, User Manual - \end{enumerate} - - \chapter{Release summary}\label{ch:release-summary} - - - \section{Version \fmprofversion}\label{sec:version-fmprofversion} - - \pagestyle{empty} % will omit the footer (page info). This is still better than the footer also on the extra page after / behind the cover - %\cleardoublepage % will - \mbox{} - \includepdf[pages=1, offset=75 0]{cover/fm2prof-omslagen_achterzijde.pdf} - -\end{document} diff --git a/docs/end_user_docs/build_pdf.sh b/docs/end_user_docs/build_pdf.sh new file mode 100644 index 00000000..ff823e10 --- /dev/null +++ b/docs/end_user_docs/build_pdf.sh @@ -0,0 +1,163 @@ +#!/bin/bash +# Build FM2PROF PDF documentation with version number +# This script fetches the current version, updates the LaTeX file, and compiles the PDF + +set -e # Exit on error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +echo -e "${GREEN}=== FM2PROF PDF Build Script ===${NC}" + +# Change to the source directory +cd "$(dirname "$0")/source" +echo "Working directory: $(pwd)" + +# Step 1: Fetch the current version from pyproject.toml +echo -e "\n${YELLOW}Step 1: Fetching version from pyproject.toml${NC}" + +# Navigate up to find pyproject.toml (from docs/end-user-docs/source to project root) +PYPROJECT_FILE="../../../pyproject.toml" + +if [ ! -f "$PYPROJECT_FILE" ]; then + echo -e "${RED}Error: pyproject.toml not found at $PYPROJECT_FILE${NC}" + exit 1 +fi + +# Extract version using grep and sed +VERSION=$(grep -E '^version\s*=' "$PYPROJECT_FILE" | sed -E 's/version\s*=\s*"([^"]+)".*/\1/') + +if [ -z "$VERSION" ]; then + echo -e "${RED}Error: Could not extract version from pyproject.toml${NC}" + exit 1 +fi + +echo -e "${GREEN}✓ Found version: $VERSION${NC}" + +# Step 2: Update the LaTeX file with the version +echo -e "\n${YELLOW}Step 2: Updating version in LaTeX files${NC}" + +TEX_FILES=("fm2prof_user_manual.tex" "fm2prof-release-notes.tex") + +for TEX_FILE in "${TEX_FILES[@]}"; do + if [ -f "$TEX_FILE" ]; then + echo "Updating $TEX_FILE..." + + # Backup the original file + cp "$TEX_FILE" "${TEX_FILE}.bak" + + # Replace the version line + sed -i 's/\r//' "$TEX_FILE" + sed -i 's/\\newcommand{\\fmprofversion}{[^}]*}/\\newcommand{\\fmprofversion}{'"$VERSION"'}/' "$TEX_FILE" + + # Remove the .tmp file created by sed on some systems + rm -f "${TEX_FILE}.tmp" + + # Verify the replacement + if grep -q "\\newcommand{\\\\fmprofversion}{$VERSION}" "$TEX_FILE"; then + echo -e "${GREEN}✓ Version updated to $VERSION in $TEX_FILE${NC}" + else + echo -e "${RED}✗ Failed to update version in $TEX_FILE${NC}" + + # Restore backup + mv "${TEX_FILE}.bak" "$TEX_FILE" + exit 1 + fi + + # Remove backup + rm -f "${TEX_FILE}.bak" + else + echo -e "${YELLOW}⚠ $TEX_FILE not found, skipping${NC}" + fi +done + +# Step 3: Compile PDFs with pdflatex and bibtex +echo -e "\n${YELLOW}Step 3: Compiling PDFs${NC}" + +compile_pdf() { + local tex_file=$1 + local base_name=$(basename "$tex_file" .tex) + + echo -e "\n${GREEN}Compiling $tex_file...${NC}" + + # First pdflatex run + echo " → First pdflatex pass..." + pdflatex -interaction=nonstopmode "$tex_file" > "${base_name}_build.log" 2>&1 || { + echo -e "${RED}✗ First pdflatex pass failed${NC}" + echo "Last 20 lines of log:" + tail -20 "${base_name}_build.log" + return 1 + } + + # Check if bibtex is needed + if grep -q '\\citation' "${base_name}.aux" 2>/dev/null; then + echo " → Running bibtex..." + bibtex "$base_name" >> "${base_name}_build.log" 2>&1 || { + echo -e "${YELLOW}⚠ bibtex warnings (continuing)${NC}" + } + + # Second pdflatex run (after bibtex) + echo " → Second pdflatex pass (post-bibtex)..." + pdflatex -interaction=nonstopmode "$tex_file" >> "${base_name}_build.log" 2>&1 || { + echo -e "${RED}✗ Second pdflatex pass failed${NC}" + tail -20 "${base_name}_build.log" + return 1 + } + else + echo " → No citations found, skipping bibtex" + fi + + # Third pdflatex run (resolve references) + echo " → Third pdflatex pass (resolve references)..." + pdflatex -interaction=nonstopmode "$tex_file" >> "${base_name}_build.log" 2>&1 || { + echo -e "${RED}✗ Third pdflatex pass failed${NC}" + tail -20 "${base_name}_build.log" + return 1 + } + + # Final pdflatex run (ensure everything is correct) + echo " → Final pdflatex pass..." + pdflatex -interaction=nonstopmode "$tex_file" >> "${base_name}_build.log" 2>&1 || { + echo -e "${RED}✗ Final pdflatex pass failed${NC}" + tail -20 "${base_name}_build.log" + return 1 + } + + # Check if PDF was created + if [ -f "${base_name}.pdf" ]; then + echo -e "${GREEN}✓ Successfully created ${base_name}.pdf${NC}" + return 0 + else + echo -e "${RED}✗ PDF file was not created${NC}" + return 1 + fi +} + +# Compile both PDFs +SUCCESS=true + +for TEX_FILE in "${TEX_FILES[@]}"; do + if [ -f "$TEX_FILE" ]; then + if ! compile_pdf "$TEX_FILE"; then + SUCCESS=false + fi + fi +done + +# Step 4: Report results +echo -e "\n${YELLOW}Step 4: Build Summary${NC}" + +echo -e "\n${GREEN}Generated PDF files:${NC}" +ls -lh *.pdf 2>/dev/null || echo "No PDF files found" + +if [ "$SUCCESS" = true ]; then + echo -e "\n${GREEN}✓✓✓ All PDFs compiled successfully! ✓✓✓${NC}" + echo -e "${GREEN}Version: $VERSION${NC}" + exit 0 +else + echo -e "\n${RED}✗✗✗ Some PDFs failed to compile ✗✗✗${NC}" + exit 1 +fi diff --git a/docs/end-user-docs/source/cover/fm2prof-omslagen_IM.pdf b/docs/end_user_docs/source/cover/fm2prof-omslagen_IM.pdf similarity index 100% rename from docs/end-user-docs/source/cover/fm2prof-omslagen_IM.pdf rename to docs/end_user_docs/source/cover/fm2prof-omslagen_IM.pdf diff --git a/docs/end-user-docs/source/cover/fm2prof-omslagen_RN.pdf b/docs/end_user_docs/source/cover/fm2prof-omslagen_RN.pdf similarity index 100% rename from docs/end-user-docs/source/cover/fm2prof-omslagen_RN.pdf rename to docs/end_user_docs/source/cover/fm2prof-omslagen_RN.pdf diff --git a/docs/end-user-docs/source/cover/fm2prof-omslagen_UM.pdf b/docs/end_user_docs/source/cover/fm2prof-omslagen_UM.pdf similarity index 100% rename from docs/end-user-docs/source/cover/fm2prof-omslagen_UM.pdf rename to docs/end_user_docs/source/cover/fm2prof-omslagen_UM.pdf diff --git a/docs/end-user-docs/source/cover/fm2prof-omslagen_achterzijde.pdf b/docs/end_user_docs/source/cover/fm2prof-omslagen_achterzijde.pdf similarity index 100% rename from docs/end-user-docs/source/cover/fm2prof-omslagen_achterzijde.pdf rename to docs/end_user_docs/source/cover/fm2prof-omslagen_achterzijde.pdf diff --git a/docs/end-user-docs/source/fm2prof_user_manual.tex b/docs/end_user_docs/source/fm2prof_release_notes.tex similarity index 77% rename from docs/end-user-docs/source/fm2prof_user_manual.tex rename to docs/end_user_docs/source/fm2prof_release_notes.tex index 97faba33..92efecfe 100644 --- a/docs/end-user-docs/source/fm2prof_user_manual.tex +++ b/docs/end_user_docs/source/fm2prof_release_notes.tex @@ -31,13 +31,13 @@ %------------------------------------------------------------------------------ \newcommand{\fmprof}{\textrm{FM2Prof}\xspace} -\newcommand{\fmprofversion}{2.4.0} +\newcommand{\fmprofversion}{2.5.1} \hypersetup { pdfauthor = {Deltares}, pdftitle = {\fmprof}, - pdfkeywords = {User Manual \fmprof} + pdfkeywords = {Release notes \fmprof} } \begin{document} @@ -47,7 +47,7 @@ \title{\fmprof} \subtitle{} - \manualtype{User Manual} + \manualtype{Release notes} \distribution{Geschikt voor: \newline \phantom{M} \fmprof \fmprofversion~(of hoger)} \version{\the\year.\the\month} @@ -57,26 +57,13 @@ \deltarestitle - \chapter{Introductie}\label{ch:introductie} - - - - \section{Versie en compatibiliteit}\label{sec:versie-en-compatibiliteit} - - - \section {Documentatie}\label{sec:documentatie} - De volgende documentatie komt mee met deze release: - - \chapter{Installatie}\label{ch:installatie} - - %\input{installation-zip-file} - - - \chapter{Command Line Interface}\label{ch:command-line-interface} - - %\input{cli} + \chapter{Introduction}\label{ch:introductie} + \input{overview} + \chapter{Release notes}\label{ch:release-notes} + \input{changelog} + \pagestyle{empty} % will omit the footer (page info). This is still better than the footer also on the extra page after / behind the cover %\cleardoublepage % will \mbox{} diff --git a/docs/end_user_docs/source/fm2prof_user_manual.tex b/docs/end_user_docs/source/fm2prof_user_manual.tex new file mode 100644 index 00000000..5e420c0d --- /dev/null +++ b/docs/end_user_docs/source/fm2prof_user_manual.tex @@ -0,0 +1,87 @@ +\documentclass[git]{deltares_manual} +\usepackage{listings} +\usepackage{xcolor} +% Configure listings to preserve hyphens and equals signs literally + +\definecolor{codebackground}{RGB}{248,248,248} +\definecolor{codeframe}{RGB}{220,220,220} +\definecolor{codekeyword}{RGB}{0,0,255} +\definecolor{codecomment}{RGB}{0,128,0} +\definecolor{codestring}{RGB}{163,21,21} + +\lstset{ + basicstyle=\ttfamily\small, + backgroundcolor=\color{codebackground}, + frame=single, + framesep=3pt, + frameround=tttt, % Round corners: tttt = all corners + rulecolor=\color{codeframe}, + columns=fullflexible, + keepspaces=true, + showstringspaces=false, + breaklines=true, + breakatwhitespace=true, % Break only at whitespace + postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space}, + literate={-}{{-}}1 {=}{{=}}1, + xleftmargin=1em, + xrightmargin=1em, + aboveskip=1em, + belowskip=1em, +} + +%------------------------------------------------------------------------------ +\newcommand{\fmprof}{\textrm{FM2Prof}\xspace} +\newcommand{\fmprofversion}{2.5.1} + +\hypersetup +{ + pdfauthor = {Deltares}, + pdftitle = {\fmprof}, + pdfkeywords = {User Manual \fmprof} +} + +\begin{document} + \pagestyle{empty} + \includepdf[pages=1, offset=72 -70]{cover/fm2prof-omslagen_UM.pdf} % links-rechts past precies + \cleardoublepage + + \title{\fmprof} + \subtitle{} + \manualtype{User Manual} + \distribution{Geschikt voor: \newline \phantom{M} \fmprof \fmprofversion~(of hoger)} + \version{\the\year.\the\month} + + \author{Koen Berends} + + \setgitdirectory{./../../.git} + \deltarestitle + + + \chapter{Introduction}\label{ch:introductie} + + \input{overview} + + + \section{Version and compatibility}\label{sec:versie-en-compatibiliteit} + This is the manual for FM2PROF version \fmprofversion. + + \section{Full documentation} + The PDF version of this manual does not provide all information. For the + full documentation, including helpful Notebooks and examples, please + visit to \url{https://deltares.github.io/Fm2Prof/latest/}. + + \chapter{Installation}\label{ch:installatie} + \input{installation} + + \chapter{Tutorial}\label{ch:quickstart} + \input{quickstart} + + %%\chapter{Files and settings}\label{ch:command-line-interface} + %%\input{output_files} + %%\input{configuration} + + \pagestyle{empty} % will omit the footer (page info). This is still better than the footer also on the extra page after / behind the cover + %\cleardoublepage % will + \mbox{} + \includepdf[pages=1, offset=75 0]{cover/fm2prof-omslagen_achterzijde.pdf} +\end{document} diff --git a/docs/markdown/configuration.md b/docs/markdown/configuration.md deleted file mode 100644 index b9dbc24d..00000000 --- a/docs/markdown/configuration.md +++ /dev/null @@ -1,26 +0,0 @@ -# Settings - -Settings are managed in the FM2PROF Configuration file - -```python exec="on" -import json - -with open('fm2prof/configurationfile_template.json', 'r') as f: - config = json.load(f) - for section_name, section_content in config["sections"].items(): - print(f"## " + section_name.capitalize()) - for key_value, key_content in section_content.items(): - print (f"### {key_value}") - print (f""" - -{key_content.get('hint')} - -| Input | Value | -|----------|:-------------:| -| Type | {key_content.get('type')} | -| Default value |{key_content.get('value')}| - -""") - - -``` \ No newline at end of file diff --git a/docs/markdown/files/2DMapOutput.md b/docs/markdown/files/2DMapOutput.md deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/markdown/files/branch_rule_file.md b/docs/markdown/files/branch_rule_file.md deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/markdown/output_files.md b/docs/markdown/output_files.md index 1a78ca40..e69de29b 100644 --- a/docs/markdown/output_files.md +++ b/docs/markdown/output_files.md @@ -1,224 +0,0 @@ -# Output Files - -FM2PROF generates a set of output files that can be used to set up 1D hydraulic models. This page describes the output files that are generated and their purpose. - -## Output Directory Structure - -After running FM2PROF, the output files are organized in subdirectories: - -``` -output/ -├── fm2prof.log -├── dflow1d/ # D-Flow 1D format files -│ ├── CrossSectionLocations.ini -│ ├── CrossSectionDefinitions.ini -│ ├── roughness-Main.ini -│ ├── roughness-FloodPlain1.ini -│ ├── roughness-FloodPlain2.ini -│ └── volumes.csv -└── dhydro/ # D-Hydro (1D) format files -│ ├── crsloc.ini -│ ├── crsdef.ini -│ ├── roughness-Main.ini -│ ├── roughness-FloodPlain1.ini -│ ├── roughness-FloodPlain2.ini -│ └── volumes.csv -└── debug/ # Optional debug files (if enabled in configuration) - ├── cross_section_volumes.geojson - ├── face_output.geojson - └── edge_output.geojson -``` - - -!!! note - The "dflow1d" format is only used by the SOBEK 3 software from version 3.5 - and higher. Support for SOBEK 3.4 and lower has been dropped since FM2PROF - version 2.5 - - - - - -### File Differences between dhydro and dflow1d (SOBEK 3) -The `dhydro` and `dflow1d` formats are alternative output formats with slightly different file naming conventions. The `dflow1d` is used by SOBEK 3, while `dhydro` is used by the D-Hydro 1D2D software. - -| `dflow1d` | `dhydro` | Description | -|-----------|--------------|-------------| -| CrossSectionLocations.ini | crsloc.ini | Cross-section locations | -| CrossSectionDefinitions.ini | crsdef.ini | Cross-section definitions | -| roughness-*.ini | roughness-*.ini | Roughness files (same naming) | -| volumes.csv | volumes.csv | Volume comparison (same naming) | - - -## Output Format - -The D-Flow 1D format is the default output format and generates files compatible with Deltares D-Flow 1D software. - -### CrossSectionLocations.ini / crsloc.ini - -This file contains the spatial locations of the cross-sections along the river or channel network. - -**Example:** -=== "dflow1d" - - ```ini - [CrossSection] - id = channel1_125.000 - branchid = Channel1 - chainage = 125.0 - shift = 0.000 - definition = channel1_125.000 - - ``` -=== "dhydro" - - ```ini - [CrossSection] - Id = channel1_125.000 - branchId = Channel1 - chainage = 125.0 - shift = 0.000 - definitionId = channel1_125.000 - - ``` - -### CrossSectionDefinitions.ini / crsdef.ini - -This file contains the geometrical definitions of each cross-section, including the shape and dimensions. - -**Example** - -=== "dflow1d" - - ```ini - [Definition] - id = channel1_125.000 - type = tabulated - thalweg = 0.000 - numLevels = 20 - levels = -2.0249 -1.9486 -1.9476 -1.8829 -1.8261 -1.7498 -1.6281 -1.5567 -1.4315 -1.3622 -0.5710 -0.0747 -0.0391 -0.0216 -0.0049 0.0695 0.4215 0.8350 1.2430 1.7807 - flowWidths = 50.0000 50.0090 50.0100 50.0150 50.0210 50.0250 50.0330 50.0370 50.0450 50.0490 50.0980 50.1290 50.1310 50.1320 150.0000 150.0040 150.0240 150.0480 150.0720 150.1040 - totalWidths = 50.0000 50.0090 50.0100 50.0150 50.0210 50.0250 50.0330 50.0370 50.0450 50.0490 50.0980 50.1290 50.1310 100.0000 150.0000 150.0040 150.0240 150.0480 150.0720 150.1040 - sd_crest = -0.2912 - sd_flowArea = 1.0473561480652571 - sd_totalArea = 1.0474 - sd_baseLevel = -0.7912269469444795 - main = 50.1040 - floodPlain1 = 100.0000 - floodPlain2 = 0.0000 - groundlayerUsed = 0 - groundLayer = 0.000 - ``` - -=== "dhydro" - - ```ini - [Definition] - Id = channel1_125.000 - Type = zwRiver - Thalweg = 0.000 - numLevels = 20 - levels = -2.0249 -1.9486 -1.9476 -1.8829 -1.8261 -1.7498 -1.6281 -1.5567 -1.4315 -1.3622 -0.5710 -0.0747 -0.0391 -0.0216 -0.0049 0.0695 0.4215 0.8350 1.2430 1.7807 - flowWidths = 50.0000 50.0090 50.0100 50.0150 50.0210 50.0250 50.0330 50.0370 50.0450 50.0490 50.0980 50.1290 50.1310 50.1320 150.0000 150.0040 150.0240 150.0480 150.0720 150.1040 - totalWidths = 50.0000 50.0090 50.0100 50.0150 50.0210 50.0250 50.0330 50.0370 50.0450 50.0490 50.0980 50.1290 50.1310 100.0000 150.0000 150.0040 150.0240 150.0480 150.0720 150.1040 - leveeCrestLevel = -0.2912 - leveeFlowArea = 1.0473561480652571 - leveeTotalArea = 1.0474 - levelBaseLevel = -0.7912269469444795 - mainWidth = 50.1040 - fp1Width = 100.0000 - fp2Width = 0.0000 - ``` - - - -### roughness-x.ini - -This file contains roughness coefficients for a section of the cross-section. Valid sections are "main", "floodplain1" and "floodplain2". FM2PROF always output the values as Chézy coefficient. - - -**Example:** -=== "dflow1d" - ```ini - [Content] - sectionId = Main - flowDirection = False - interpolate = 1 - globalType = 1 - globalValue = 45 - - [BranchProperties] - branchId = Channel1 - roughnessType = 1 - functionType = 2 - numLevels = 42 - levels = -2.4028 -2.3028 -2.2028 -2.1028 -2.0028 -1.9028 -1.8028 -1.7028 -1.6028 -1.5028 -1.4028 -1.3028 -1.2028 -1.1028 -1.0028 -0.9028 -0.8028 -0.7028 -0.6028 -0.5028 -0.4028 -0.3028 -0.2028 -0.1028 -0.0028 0.0972 0.1972 0.2972 0.3972 0.4972 0.5972 0.6972 0.7972 0.8972 0.9972 1.0972 1.1972 1.2972 1.3972 1.4972 1.5972 1.6972 - - [Definition] - branchId = Channel1 - chainage = 125.0 - values = 22.71 22.71 22.71 22.71 22.71 23.47 25.93 27.59 28.86 29.91 30.79 31.57 32.26 32.88 33.45 33.98 34.47 34.92 35.35 35.75 36.13 36.49 36.84 37.17 37.48 37.79 38.08 38.36 38.62 38.89 39.14 39.38 39.62 39.85 40.07 40.29 40.5 40.71 40.91 41.11 41.3 41.49 - ``` - -=== "dhydro" - - ```ini - [Global] - frictionId = Main - frictionType = Chezy - frictionValue = 45 - - [Branch] - branchId = Channel1 - frictionType = Chezy - functionType = Waterlevel - numLevels = 42 - levels = -2.4028 -2.3028 -2.2028 -2.1028 -2.0028 -1.9028 -1.8028 -1.7028 -1.6028 -1.5028 -1.4028 -1.3028 -1.2028 -1.1028 -1.0028 -0.9028 -0.8028 -0.7028 -0.6028 -0.5028 -0.4028 -0.3028 -0.2028 -0.1028 -0.0028 0.0972 0.1972 0.2972 0.3972 0.4972 0.5972 0.6972 0.7972 0.8972 0.9972 1.0972 1.1972 1.2972 1.3972 1.4972 1.5972 1.6972 - numLocations = 14 - chainage = 125.0000 225.0000 325.0000 425.0000 525.0000 625.0000 725.0000 825.0000 925.0000 1025.0000 1125.0000 1225.0000 1325.0000 1425.0000 - frictionValues = 22.7097 22.7097 22.7097 22.7097 22.7097 23.4671 25.9284 27.5925 28.8645 29.9081 30.7947 31.5704 32.2605 32.8842 33.4534 33.9782 34.4652 34.9203 35.3474 35.7501 36.1314 36.4936 36.8386 37.1682 37.4836 37.7854 38.0757 38.3553 38.6250 38.8857 39.1379 39.3824 39.6195 39.8498 40.0737 40.2915 40.5037 40.7105 40.9122 41.1091 41.3015 41.4894 - 22.7097 22.7097 22.7097 22.7097 22.7097 24.4354 26.5433 28.0504 29.2338 30.2186 31.0641 31.8090 32.4751 33.0796 33.6330 34.1445 34.6203 35.0657 35.4842 35.8795 36.2541 36.6105 36.9502 37.2749 37.5855 37.8843 38.1715 38.4485 38.7156 38.9739 39.2239 39.4661 39.7011 39.9294 40.1513 40.3673 40.5776 40.7827 40.9826 41.1779 41.3687 41.5551 - 22.7097 22.7097 22.7097 22.7097 22.7097 25.2428 27.0931 28.4730 29.5806 30.5140 31.3224 32.0391 32.6829 33.2692 33.8078 34.3068 34.7720 35.2079 35.6184 36.0066 36.3749 36.7254 37.0601 37.3800 37.6866 37.9814 38.2654 38.5390 38.8033 39.0589 39.3063 39.5463 39.7791 40.0053 40.2253 40.4394 40.6480 40.8514 41.0498 41.2435 41.4328 41.6179 - 22.7097 22.7097 22.7097 22.7097 23.4664 25.9278 27.5927 28.8645 29.9081 30.7947 31.5704 32.2606 32.8842 33.4535 33.9783 34.4653 34.9204 35.3475 35.7502 36.1315 36.4937 36.8387 37.1683 37.4838 37.7864 38.0774 38.3578 38.6283 38.8896 39.1424 39.3874 39.6249 39.8555 40.0797 40.2977 40.5100 40.7168 40.9186 41.1154 41.3077 41.4956 41.6171 - 22.7097 22.7097 22.7097 22.7097 24.4352 26.5437 28.0502 29.2337 30.2186 31.0641 31.8091 32.4752 33.0796 33.6330 34.1446 34.6204 35.0657 35.4843 35.8796 36.2542 36.6106 36.9502 37.2751 37.5858 37.8847 38.1721 38.4491 38.7164 38.9749 39.2250 39.4675 39.7026 39.9311 40.1531 40.3693 40.5797 40.7849 40.9849 41.1803 41.3711 41.5576 41.6163 - 22.7097 22.7097 22.7097 22.7097 25.2430 27.0933 28.4729 29.5806 30.5140 31.3225 32.0392 32.6829 33.2692 33.8079 34.3068 34.7720 35.2080 35.6185 36.0067 36.3750 36.7255 37.0602 37.3802 37.6868 37.9816 38.2656 38.5392 38.8036 39.0592 39.3067 39.5467 39.7795 40.0058 40.2259 40.4401 40.6487 40.8522 41.0507 41.2445 41.4338 41.6164 41.6164 - 22.7097 22.7097 22.7097 23.4659 25.9273 27.5928 28.8644 29.9081 30.7948 31.5705 32.2606 32.8843 33.4535 33.9784 34.4654 34.9205 35.3475 35.7503 36.1316 36.4938 36.8388 37.1685 37.4840 37.7865 38.0775 38.3579 38.6283 38.8897 39.1425 39.3875 39.6250 39.8557 40.0799 40.2979 40.5102 40.7172 40.9189 41.1158 41.3081 41.4961 41.6168 41.6168 - 22.7097 22.7097 22.7097 24.4351 26.5439 28.0501 29.2337 30.2186 31.0641 31.8091 32.4752 33.0797 33.6331 34.1447 34.6205 35.0658 35.4844 35.8797 36.2544 36.6107 36.9504 37.2752 37.5859 37.8848 38.1721 38.4492 38.7165 38.9750 39.2251 39.4675 39.7027 39.9312 40.1532 40.3694 40.5798 40.7850 40.9851 41.1805 41.3713 41.5578 41.6174 41.6174 - 22.7097 22.7097 22.7170 25.2431 27.0935 28.4729 29.5805 30.5141 31.3225 32.0392 32.6830 33.2693 33.8080 34.3069 34.7721 35.2081 35.6187 36.0068 36.3751 36.7257 37.0603 37.3803 37.6869 37.9818 38.2656 38.5393 38.8036 39.0592 39.3067 39.5467 39.7796 40.0059 40.2259 40.4401 40.6488 40.8523 41.0507 41.2446 41.4339 41.6181 41.6181 41.6181 - 22.7097 22.7097 23.4656 25.9269 27.5930 28.8644 29.9081 30.7948 31.5705 32.2607 32.8843 33.4536 33.9784 34.4655 34.9206 35.3476 35.7505 36.1317 36.4939 36.8389 37.1686 37.4841 37.7866 38.0776 38.3580 38.6284 38.8898 39.1426 39.3876 39.6251 39.8558 40.0799 40.2980 40.5103 40.7172 40.9190 41.1159 41.3082 41.4961 41.6188 41.6188 41.6188 - 22.7097 22.7097 24.4350 26.5434 28.0500 29.2336 30.2186 31.0642 31.8092 32.4753 33.0797 33.6332 34.1448 34.6206 35.0659 35.4845 35.8799 36.2545 36.6108 36.9505 37.2754 37.5860 37.8849 38.1722 38.4493 38.7165 38.9750 39.2251 39.4676 39.7027 39.9312 40.1533 40.3694 40.5798 40.7850 40.9851 41.1805 41.3713 41.5579 41.6196 41.6196 41.6196 - 22.7097 22.7217 25.2429 27.0938 28.4729 29.5805 30.5141 31.3225 32.0392 32.6830 33.2694 33.8081 34.3071 34.7722 35.2082 35.6188 36.0070 36.3753 36.7258 37.0604 37.3804 37.6871 37.9819 38.2657 38.5394 38.8037 39.0593 39.3068 39.5468 39.7796 40.0059 40.2260 40.4402 40.6488 40.8523 41.0508 41.2446 41.4340 41.6191 41.6205 41.6205 41.6205 - 22.7097 23.4654 25.9266 27.5928 28.8644 29.9081 30.7948 31.5705 32.2608 32.8844 33.4537 33.9786 34.4656 34.9207 35.3478 35.7506 36.1319 36.4941 36.8391 37.1687 37.4842 37.7867 38.0777 38.3581 38.6285 38.8899 39.1427 39.3876 39.6251 39.8558 40.0800 40.2980 40.5103 40.7172 40.9190 41.1159 41.3082 41.4962 41.6213 41.6213 41.6213 41.6213 - 22.7097 24.4351 26.5430 28.0499 29.2336 30.2186 31.0642 31.8092 32.4754 33.0798 33.6333 34.1449 34.6207 35.0661 35.4846 35.8801 36.2547 36.6110 36.9507 37.2755 37.5862 37.8851 38.1723 38.4493 38.7166 38.9751 39.2252 39.4676 39.7028 39.9312 40.1533 40.3694 40.5799 40.7850 40.9852 41.1805 41.3713 41.5579 41.6222 41.6222 41.6222 41.6222 - ``` - - -### volumes.csv - -This file contains a comparison between 2D model volumes and the reconstructed 1D cross-section volumes. - -**Columns:** - -| Column Name | Description | -|-------------|-------------| -| `id` | Cross-section identifier | -| `z` | Water level (elevation) | -| `2D_total_volume` | Total storage volume from 2D model | -| `2D_flow_volume` | Flow (conveyance) volume from 2D model | -| `2D_wet_area` | Wetted area from 2D model | -| `2D_flow_area` | Flow area from 2D model | -| `1D_total_volume_sd` | Total volume for 1D cross-section including levee (summer dike)| -| `1D_total_volume` | Total storage volume for 1D cross-section | -| `1D_flow_volume_sd` | Flow volume for 1D cross-section including levee (summer dike)| -| `1D_flow_volume` | Flow volume for 1D cross-section | -| `1D_total_width` | Total width of 1D cross-section | -| `1D_flow_width` | Flow width of 1D cross-section | - -**Example:** -```csv -id,z,2D_total_volume,2D_flow_volume,2D_wet_area,2D_flow_area,1D_total_volume_sd,1D_total_volume,1D_flow_volume_sd,1D_flow_volume,1D_total_width,1D_flow_width -CS_001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -CS_001,0.5,125.5,100.2,250.0,200.0,124.8,125.0,99.8,100.0,250.0,200.0 -CS_001,1.0,502.3,400.5,502.0,401.0,501.5,502.0,399.9,400.0,502.0,401.0 -... -``` diff --git a/docs/notebooks/generate_cross_section_loc_file.ipynb b/docs/notebooks/generate_cross_section_loc_file.ipynb new file mode 100644 index 00000000..5ea6e839 --- /dev/null +++ b/docs/notebooks/generate_cross_section_loc_file.ipynb @@ -0,0 +1,245 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3b149940-de9f-4ff9-ac90-20640d251b7c", + "metadata": {}, + "source": [ + "# Generate a Cross-Section Location File\n", + "\n", + "Build a cross-section input file for FM2PROF from a SOBEK 3 DIMR network definition file.\n", + "\n", + "The distance between cross-section is computed from the differences between the offsets/chainages.\n", + "The beginning and end point of each branch are treated as half-distance control volumes.\n", + "\n", + "It supports an optional :ref:`branchRuleFile.\n", + "\n", + "Use as a function i.e. this code will generate a cross-section location file:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "3fceccda-fede-4fc7-ad89-bf43f0a74c96", + "metadata": {}, + "outputs": [], + "source": [ + "from fm2prof.utils import GenerateCrossSectionLocationFile" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e866e14a-21df-479e-9265-d63503fcdc32", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on class GenerateCrossSectionLocationFile in module fm2prof.utils:\n", + "\n", + "class GenerateCrossSectionLocationFile(fm2prof.common.FM2ProfBase)\n", + " | GenerateCrossSectionLocationFile(network_definition_file: 'str | Path', cross_section_location_file: 'str | Path', branch_rule_file: 'str | Path' = '') -> 'None'\n", + " |\n", + " | Build a cross-section input file for FM2PROF from a SOBEK 3 DIMR network definition file.\n", + " |\n", + " | The distance between cross-section is computed from the differences between the offsets/chainages.\n", + " | The beginning and end point of each branch are treated as half-distance control volumes.\n", + " |\n", + " | It supports an optional :ref:`branchRuleFile.\n", + " |\n", + " | Use as a function i.e. this code will generate a cross-section location file:\n", + " |\n", + " | >>> GenerateCrossSectionLocationFile(**input)\n", + " |\n", + " | Parameters\n", + " | ----------\n", + " | networkdefinitionfile: path to NetworkDefinitionFile.ini\n", + " |\n", + " | crossectionlocationfile: path to the desired output file\n", + " |\n", + " | branchrulefile: OPTIONAL path to a branchrulefile\n", + " |\n", + " |\n", + " |\n", + " |\n", + " | branchrulefile\n", + " | ^^^^^^^^^^^^^^\n", + " | This file may be used to exclude certain computational points from being\n", + " | used as the location of a cross-section. This is particularily useful\n", + " | when smaller branches connect to a major branch.\n", + " |\n", + " | The branchrule file is a comma-seperates file with the following syntaxt:\n", + " |\n", + " | .. code-block:: shell\n", + " |\n", + " | branch,rules\n", + " |\n", + " | Here, `branch` is the name of the branch and `rules` are rules for exclusion\n", + " |\n", + " | Supported general rules are:\n", + " |\n", + " | - onlyFirst: only keep the first cross-section, and exclude all others\n", + " | - onlyLast: only keep the last cross-section, and exclude all others\n", + " | - onlyEdges: only keep the first and last cross-section, and exclude all others\n", + " | - ignoreFirst: exclude the first cross-section on a branch\n", + " | - ignoreLast: exclude the last cross-section on a branch\n", + " | - ignoreEdges: exclude the first and last cross-section on a branch\n", + " | - noRule: use to not use any of the above rules\n", + " |\n", + " | Additionally, specific cross-sections can be excluded by id. For example:\n", + " |\n", + " |\n", + " | .. code-block:: shell\n", + " |\n", + " | Channel1, noRule, channel_1_350.000\n", + " |\n", + " | In this case, the computational point with name `channel_1_350.000` will\n", + " | not be used as the location of a cross-section.\n", + " |\n", + " | Rules and individual exclusions can be mixed, e.g.:\n", + " |\n", + " | .. code-block:: shell\n", + " |\n", + " | Channel1, ignoreLast, channel_1_350.000\n", + " |\n", + " | Method resolution order:\n", + " | GenerateCrossSectionLocationFile\n", + " | fm2prof.common.FM2ProfBase\n", + " | builtins.object\n", + " |\n", + " | Methods defined here:\n", + " |\n", + " | __init__(self, network_definition_file: 'str | Path', cross_section_location_file: 'str | Path', branch_rule_file: 'str | Path' = '') -> 'None'\n", + " | Generate cross section location file object.\n", + " |\n", + " | Args:\n", + " | network_definition_file (str | Path): network definition file\n", + " | crossection_location_file (str | Path): crosssection location file\n", + " | branchrule_file (str | Path, optional): . Defaults to \"\".\n", + " |\n", + " | ----------------------------------------------------------------------\n", + " | Methods inherited from fm2prof.common.FM2ProfBase:\n", + " |\n", + " | finish_log_task(self) -> 'None'\n", + " | Use this method to finish task.\n", + " |\n", + " | :param task_name: task name, will be displayed in log message\n", + " |\n", + " | get_filelogformatter(self) -> 'ElapsedFormatter'\n", + " | Return file log formatter.\n", + " |\n", + " | get_inifile(self) -> 'IniFile'\n", + " | Get the inifile object.\n", + " |\n", + " | get_logformatter(self) -> 'ElapsedFormatter'\n", + " | Return log formatter.\n", + " |\n", + " | get_logger(self) -> 'Logger'\n", + " | Use this method to return logger object.\n", + " |\n", + " | set_inifile(self, inifile: 'IniFile' = None) -> 'None'\n", + " | Use this method to set configuration file object.\n", + " |\n", + " | For loading from file, use ``load_inifile`` instead\n", + " |\n", + " | Args:\n", + " | ----\n", + " | inifile (IniFile): inifile object. Obtain using e.g. ``get_inifile``.\n", + " |\n", + " | set_logfile(self, output_dir: 'str | Path', filename: 'str' = 'fm2prof.log') -> 'None'\n", + " | Set log file.\n", + " |\n", + " | Args:\n", + " | ----\n", + " | output_dir (str): _description_\n", + " | filename (str, optional): _description_. Defaults to \"fm2prof.log\".\n", + " |\n", + " | set_logger(self, logger: 'Logger') -> 'None'\n", + " | Use to set logger.\n", + " |\n", + " | Args:\n", + " | ----\n", + " | logger (Logger): Logger instance\n", + " |\n", + " | set_logger_message(self, err_mssg: 'str' = '', level: 'str' = 'info', *, header: 'bool' = False) -> 'None'\n", + " | Set message to logger if this is set.\n", + " |\n", + " | Args:\n", + " | ----\n", + " | err_mssg (str, optional): Error message to log. Defaults to \"\".\n", + " | level (str, optional): Log level. Defaults to \"info\".\n", + " | header (bool, optional): Set error message as header. Defaults to False.\n", + " |\n", + " | start_new_log_task(self, task_name: 'str' = 'NOT DEFINED', pbar: 'tqdm.tqdm' = None) -> 'None'\n", + " | Use this method to start a new task. Will reset the internal clock.\n", + " |\n", + " | :param task_name: task name, will be displayed in log message\n", + " |\n", + " | ----------------------------------------------------------------------\n", + " | Static methods inherited from fm2prof.common.FM2ProfBase:\n", + " |\n", + " | create_logger() -> 'Logger'\n", + " | Create logger instance.\n", + " |\n", + " | ----------------------------------------------------------------------\n", + " | Data descriptors inherited from fm2prof.common.FM2ProfBase:\n", + " |\n", + " | __dict__\n", + " | dictionary for instance variables\n", + " |\n", + " | __weakref__\n", + " | list of weak references to the object\n", + " |\n", + " | ----------------------------------------------------------------------\n", + " | Data and other attributes inherited from fm2prof.common.FM2ProfBase:\n", + " |\n", + " | __authors__ = 'Koen Berends, Asako Fujisaki, Carles Soriano Perez, Ili...\n", + " |\n", + " | __contact__ = 'koen.berends@deltares.nl'\n", + " |\n", + " | __copyright__ = 'Copyright 2016-2020, University of Twente & Deltares'\n", + " |\n", + " | __license__ = 'LPGL'\n", + " |\n", + " | __url__ = 'https://deltares.github.io/Fm2Prof/'\n", + "\n" + ] + } + ], + "source": [ + "help(GenerateCrossSectionLocationFile)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89592010-56fb-4bb8-a9a3-6a913acc8f69", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/markdown/api.md b/docs/tech_docs/api.md similarity index 100% rename from docs/markdown/api.md rename to docs/tech_docs/api.md diff --git a/docs/markdown/conceptual_design.md b/docs/tech_docs/conceptual_design.md similarity index 92% rename from docs/markdown/conceptual_design.md rename to docs/tech_docs/conceptual_design.md index 3a2ae330..c8bab6ee 100644 --- a/docs/markdown/conceptual_design.md +++ b/docs/tech_docs/conceptual_design.md @@ -1,161 +1,161 @@ -# Methodology - -This chapter describes in more detail the steps FM2PROF takes to go from -a 2D representation of reality to a 1D representation of reality. -Conceptually, FM2PROF works in three distinct steps: (1) initialisation, -(2) building cross-sections and (3) finalisation. - -## Initialisation - -
- ![Image title](../figures/conceptual_initialisation.png){ width="300" } -
Image caption
-
- -The initialisation step involves parsing (i.e. reading and making -available for further analysis) the input. In this step control -volumes and sections are defined as well. This step may take some time -to complete, but this preprocessing greatly reduces the computation -times in the next step. - -### Region polygon file - -The region polygon file (*Dutch: gebiedsvakken*) is provided in the configuration and should be a valid [MultiPolygon geojson file](api.md#fm2prof.polygon_file.MultiPolygon). If a polygon file is provided, FM2PROF will perform an `inpolygon` algorithm during initialisation and write the results to a `.region_cache.json` file which is placed in the same directory as the 2D map file. This can take up to 30 minutes for a sizable river. If a cache file is already present and valid, it will be read instead. A cache file is invalidated if the 2D input has changed since the cache was created. - -!!! note - - There are special conditions for the geojson file, see [MultiPolygon](api.md#fm2prof.polygon_file.MultiPolygon). - -The region file is used to map each point (node, edge or face) in the 2D input grid to one -unique region. They are used to determine what 2D points are assigned to which cross-section, see [Classification of volumes](#classification-of-control-volumes) - - -### Section polygon file - -The section polygon file (*Dutch: gebiedsvakken*) is provided in the configuration and should be a valid [MultiPolygon geojson file](api/#fm2prof.polygon_file.MultiPolygon). If a polygon file is provided, FM2PROF will perform an `inpolygon` algorithm during initialisation and write the results to a `.section_cache.json` file which is placed in the same directory as the 2D map file. This can take up to 30 minutes for a sizable river. If a cache file is already present and valid, it will be read instead. A cache file is invalidated if the 2D input has changed since the cache was created. - -[Sections](glossary.md#sections) are used to divide the cross-section between floodplain and main channel (e.g. the 'floodplain' section and the 'main channel' section). This distinction is only used to assign different roughness values to each section. - -!!! tip - - The default section is "floodplain1". To reduce initialisation time, provide only a section polygon - covering the main channel (so a polygon with attribute `section` set to `main`). By default, all - points not covered by the main channel will be floodplain1. - - -### Import 2D data - -#### Parsing 2D data - -Dflow2d uses a staggered grid to solve the (hydrostatic) flow equations. -Because of this staggered approach, there is not a single 2D point that -has all information. Flow information (flow velocity, discharge) is -stored in *flow links* (or edges), while geometry (bed level) is stored -in *cell faces*. FM2PROF needs both information from the faces, as from the links. - -
- ![Image title](../figures/dflow2d_grid.PNG){ width="300" } -
The dflow2d staggered grid.
-
- -#### Classification of control volumes - -`Control volumes` are used to define -which 2D datapoints are linked to which 1D cross-section. This is done -in the following steps: - -- Each 2D point (node, edge and face) is assigned a [Region](glossary.md#regions). If a [region polygon](#region-polygon-file) is provided, each 2D point is assigned the same region as the polygon they are in. If no region polygon is provided, each point will be assigned to the same default region. -- Each cross-section is assigned a region following the same principle. -- For each region seperately, we perform [nearest neighbour classification](api.md#nearest_neighbour) to uniquely identify each 2D point to a 1D cross-section. Only 2D points that have the same region as the cross-section can be assigned to a cross-section. - -#### Classification of sections - -[Sections](glossary/md#sections) are used to output a -different roughness function for the main channel and the floodplains. -The purpose of the classification is to determine whether a 2D point -belongs to the main channel section, or to the floodplain section (see -warning below). - -Two methods are implemented: - -- `Variance based classification`{.interpreted-text - role="ref"} -- Polygon-based classification - -## Build Cross-Section - - -
- ![Image title](../figures/conceptual_build.png){ width="300" } -
The dflow2d staggered grid.
-
- -Once initialisation is complete, will loop over each -`cross-section location`{.interpreted-text -role="term"}. In each iteration, the program takes two steps: (1) -building the geometry and (2) building the roughness tables. - -!!! warning - - No cross-section will be generated for locations that have no 2D data - assigned or have less than 10 faces assigned. This may happen if a - location lies outside the 2D grid, or if there are many cross-section - closely together. If this happens, an error is raised by FM2PROF. The - user should check the cross-section location input file to resolve the - problem. - -### Build Geometry - -In each loop, a number of steps is taken based on the 2D data that is -uniquely assigned to that cross-section: - -- `Lakes`{.interpreted-text role="term"} are identified using the - `identify_lakes`{.interpreted-text role="ref"} -- `Flow volume`{.interpreted-text role="term"} and - `Storage volume`{.interpreted-text role="term"} are seperated using - the `distinguish_storage`{.interpreted-text role="ref"} -- The - `water level dependent geometry`{.interpreted-text - role="term"} is computed using `wl_dependent_css`{.interpreted-text - role="ref"} -- The - `water level independent geometry`{.interpreted-text - role="term"} is computed using - `wl_independent_css`{.interpreted-text role="ref"} -- The parameters for `Summerdikes`{.interpreted-text role="term"} are - defined using the `sd_optimisation`{.interpreted-text role="ref"} -- Finally, the cross-section is simplified using the - Visvalingam-Whyatt method of poly-line vertex reduction - `simplify_css`{.interpreted-text role="ref"} - -### Build roughness - -At each cross-section point, a roughness look-up table is constructed -that relates water level (in m + NAP) to a Chézy roughness coefficient. -This is done in three steps: - -- For each section, a roughness table is constructed by averaging the - 2D points - -## Finalisation - -
- ![Image title](../figures/conceptual_finalisation.png){ width="300" } -
The dflow2d staggered grid.
-
- -### Interpolate friction tables - -Some output formats (e.g. SOBEK 3) require that the friction tables are uniform -for each branch: each point on the branch must have the same dimensions. This means -that if friction is defined as a function of water level, that each point on a branch must have -the same water level dimension. - -During cross-section generation, it is not yet known what the water levels are for each -point. During finalisation, a uniform water level dimension is defined. For each point on -the branch, the friction value is interpolated to the uniform dimension. - -### Export output files - -Output files are written to the required 1D format. Optionally, additional files are written as well. -These optional output files can be enabled in the `debug` section of the configuration file. +# Methodology + +This chapter describes in more detail the steps FM2PROF takes to go from +a 2D representation of reality to a 1D representation of reality. +Conceptually, FM2PROF works in three distinct steps: (1) initialisation, +(2) building cross-sections and (3) finalisation. + +## Initialisation + +
+ ![Image title](../figures/conceptual_initialisation.png){ width="300" } +
Image caption
+
+ +The initialisation step involves parsing (i.e. reading and making +available for further analysis) the input. In this step control +volumes and sections are defined as well. This step may take some time +to complete, but this preprocessing greatly reduces the computation +times in the next step. + +### Region polygon file + +The region polygon file (*Dutch: gebiedsvakken*) is provided in the configuration and should be a valid [MultiPolygon geojson file](api.md#fm2prof.polygon_file.MultiPolygon). If a polygon file is provided, FM2PROF will perform an `inpolygon` algorithm during initialisation and write the results to a `.region_cache.json` file which is placed in the same directory as the 2D map file. This can take up to 30 minutes for a sizable river. If a cache file is already present and valid, it will be read instead. A cache file is invalidated if the 2D input has changed since the cache was created. + +!!! note + + There are special conditions for the geojson file, see [MultiPolygon](api.md#fm2prof.polygon_file.MultiPolygon). + +The region file is used to map each point (node, edge or face) in the 2D input grid to one +unique region. They are used to determine what 2D points are assigned to which cross-section, see [Classification of volumes](#classification-of-control-volumes) + + +### Section polygon file + +The section polygon file (*Dutch: gebiedsvakken*) is provided in the configuration and should be a valid [MultiPolygon geojson file](api.md#fm2prof.polygon_file.MultiPolygon). If a polygon file is provided, FM2PROF will perform an `inpolygon` algorithm during initialisation and write the results to a `.section_cache.json` file which is placed in the same directory as the 2D map file. This can take up to 30 minutes for a sizable river. If a cache file is already present and valid, it will be read instead. A cache file is invalidated if the 2D input has changed since the cache was created. + +[Sections](glossary.md#sections) are used to divide the cross-section between floodplain and main channel (e.g. the 'floodplain' section and the 'main channel' section). This distinction is only used to assign different roughness values to each section. + +!!! tip + + The default section is "floodplain1". To reduce initialisation time, provide only a section polygon + covering the main channel (so a polygon with attribute `section` set to `main`). By default, all + points not covered by the main channel will be floodplain1. + + +### Import 2D data + +#### Parsing 2D data + +Dflow2d uses a staggered grid to solve the (hydrostatic) flow equations. +Because of this staggered approach, there is not a single 2D point that +has all information. Flow information (flow velocity, discharge) is +stored in *flow links* (or edges), while geometry (bed level) is stored +in *cell faces*. FM2PROF needs both information from the faces, as from the links. + +
+ ![Image title](../figures/dflow2d_grid.PNG){ width="300" } +
The dflow2d staggered grid.
+
+ +#### Classification of control volumes + +`Control volumes` are used to define +which 2D datapoints are linked to which 1D cross-section. This is done +in the following steps: + +- Each 2D point (node, edge and face) is assigned a [Region](glossary.md#regions). If a [region polygon](#region-polygon-file) is provided, each 2D point is assigned the same region as the polygon they are in. If no region polygon is provided, each point will be assigned to the same default region. +- Each cross-section is assigned a region following the same principle. +- For each region seperately, we perform [nearest neighbour classification](api.md#nearest_neighbour) to uniquely identify each 2D point to a 1D cross-section. Only 2D points that have the same region as the cross-section can be assigned to a cross-section. + +#### Classification of sections + +[Sections](glossary/md#sections) are used to output a +different roughness function for the main channel and the floodplains. +The purpose of the classification is to determine whether a 2D point +belongs to the main channel section, or to the floodplain section (see +warning below). + +Two methods are implemented: + +- `Variance based classification`{.interpreted-text + role="ref"} +- Polygon-based classification + +## Build Cross-Section + + +
+ ![Image title](../figures/conceptual_build.png){ width="300" } +
The dflow2d staggered grid.
+
+ +Once initialisation is complete, will loop over each +`cross-section location`{.interpreted-text +role="term"}. In each iteration, the program takes two steps: (1) +building the geometry and (2) building the roughness tables. + +!!! warning + + No cross-section will be generated for locations that have no 2D data + assigned or have less than 10 faces assigned. This may happen if a + location lies outside the 2D grid, or if there are many cross-section + closely together. If this happens, an error is raised by FM2PROF. The + user should check the cross-section location input file to resolve the + problem. + +### Build Geometry + +In each loop, a number of steps is taken based on the 2D data that is +uniquely assigned to that cross-section: + +- `Lakes`{.interpreted-text role="term"} are identified using the + `identify_lakes`{.interpreted-text role="ref"} +- `Flow volume`{.interpreted-text role="term"} and + `Storage volume`{.interpreted-text role="term"} are seperated using + the `distinguish_storage`{.interpreted-text role="ref"} +- The + `water level dependent geometry`{.interpreted-text + role="term"} is computed using `wl_dependent_css`{.interpreted-text + role="ref"} +- The + `water level independent geometry`{.interpreted-text + role="term"} is computed using + `wl_independent_css`{.interpreted-text role="ref"} +- The parameters for `Summerdikes`{.interpreted-text role="term"} are + defined using the `sd_optimisation`{.interpreted-text role="ref"} +- Finally, the cross-section is simplified using the + Visvalingam-Whyatt method of poly-line vertex reduction + `simplify_css`{.interpreted-text role="ref"} + +### Build roughness + +At each cross-section point, a roughness look-up table is constructed +that relates water level (in m + NAP) to a Chézy roughness coefficient. +This is done in three steps: + +- For each section, a roughness table is constructed by averaging the + 2D points + +## Finalisation + +
+ ![Image title](../figures/conceptual_finalisation.png){ width="300" } +
The dflow2d staggered grid.
+
+ +### Interpolate friction tables + +Some output formats (e.g. SOBEK 3) require that the friction tables are uniform +for each branch: each point on the branch must have the same dimensions. This means +that if friction is defined as a function of water level, that each point on a branch must have +the same water level dimension. + +During cross-section generation, it is not yet known what the water levels are for each +point. During finalisation, a uniform water level dimension is defined. For each point on +the branch, the friction value is interpolated to the uniform dimension. + +### Export output files + +Output files are written to the required 1D format. Optionally, additional files are written as well. +These optional output files can be enabled in the `debug` section of the configuration file. diff --git a/docs/markdown/glossary.md b/docs/tech_docs/glossary.md similarity index 94% rename from docs/markdown/glossary.md rename to docs/tech_docs/glossary.md index fa42c159..9fde78e5 100644 --- a/docs/markdown/glossary.md +++ b/docs/tech_docs/glossary.md @@ -1,149 +1,149 @@ -# Important concepts - -## Control volume - -A control volume is a bounded area that describes a section of -a 2D model that is assigned to a 1D cross-section. The figure -below shows a schematical overview. - -Control volumes are a conceptual concept and not defined in their -own right. Instead, all relevant 2D data, such as bed levels, -flow velocities and roughness information is assigned to a -cross-section by k-Nearest Neighbour classification. As such, -the bounds of the control volumes are not uniquely defined by -a polygon but rather by a collection of points. - -Control volumes use the 2D coordinates of each cross-section as -specified in the CrossSectionLocationFile during the nearest-neighbour -classification. The 2D input data used during classification is -filtered by [region](#region) in the following way: a cross-section within -a certain region can only be assigned 2D information from that region. - -The `CrossSectionLocationFile` additionally contains information on the 1D -coordinates (branch and chainage) and the length. -The figure below shows how cross-section length -is defined. We recommend that this file is generated using the -[GenerateCrossSectionLocations](utils/GenerateCrossSectionsLocations.md) -tool. - -An approximation of the control volumes is generated by the program -during the finalisation step. This is a convex hull approximation, -which is usefull for debugging input errors (see [Troubleshooting](troubleshooting.md)) - - -!!! note - - Control volumes are the equivalent of WAQ2PROF's sobekvakken - -
- ![Image title](../figures/controlvolume.png){ width="300" } -
A control volume
-
- - -## Regions - -Regions are used to have some finer control over which 2D model -output is assigned to which 1D cross-section. If no region are -defined, 2D model output is assigned to cross-section using -k-nearest neighbour. This is not always a good approach, for example -if a tributary or retention area. In the figure a section of the -River Meuse is plotted near the [Blitterswijck retention -area](https://www.openstreetmap.org/search?query=blitterswijck#map=16/51.5405/6.1122). -The retention area is demarcated from the main river by levees. -Cross-sections generated for the retention area should therefore not -'eat out of' the area of the main channel - which could results in -a small cross-section non-physical constriction of the flow. - -
- ![Image title](../figures/region_polygon_blitwijk.PNG){ width="300" } -
Region polygons are used to prevent cross-sections generated - in the retention area to 'eat out of' the main channel. Within each - region polygon (red borders) nearest neighour is used to assign 2D - points to cross-sections. Points with the same color are associated with - the same 1D cross-section
-
- - -## Sections - -Sections are used to divide the cross-section between floodplain and -main channel (e.g. the 'floodplain' section and the 'main channel' section). This distinction is only used to assign -different roughness values to each section. - -## Water level (in)dependent geometry - -It is often not possible to start the 2D computation from a -completely dry bed - instead some initial water level is present in -the model. This initial condition divides the 1D geometry in water -level dependent part and a water level independent part. Below the -initial condition, we cannot take advantage of the 2D model to tell -us which cells are part of the conveyance and which cells are wet. -Instead, the water level is artificially lowered in a number of -steps to estimate the volume below the initial water levels. - -## Summerdikes - -Summerdikes are a Dutch term for levees that are designed to be -flooded with higher discharges, but not with relatively low floods -(i.e.: they withstand summer floods). They contrast with -'winterdikes', which are designed to not flood at all. Summerdikes -effectively comparimentalise the floodplain. They can have a -profound effect on stage-discharge relationships: as these levees -overflow the compartments start flowing which leads to a retention -effect. Such an effect cannot be modelled using regulare -cross-sections. SOBEK therefore has a 'summerdike' functionality. - -## Lakes - -Lakes are water bodies that are not hydraulically connected to the -main channel in the first few timesteps of the 2D model computation. -They do not contribute to the volume present in the control volume -until they connect with the rest of the river and will not feature -in the water level independent computation. -Water bodies that *are* connected to the main channel -in the first few timesteps **do** count as volume. However, as these -likely do not contribute to conveyance, they will be flagged as -'storage' instead. - -
- ![Image title](../figures/gis_visualisation_maas_03_annotated.png){ width="300" } -
-
- - -## Total volume - -The Total volume refers to the volume of water \[in m\^3\] within a -`Control volume`{.interpreted-text role="term"} for a given water -level at the `Cross-section location`{.interpreted-text -role="term"}. The total volume is the sum of the -`Flow volume`{.interpreted-text role="term"} and the -`Storage volume`{.interpreted-text role="term"}. - -## Flow volume - -The Flow volume is defined as the volume of water \[in m\^3\] for -which the conditions for flowing water are met. This volume is -considered to be available for the conveyance of water through the -`Control volume`{.interpreted-text role="term"}. - -See `distinguish_storage`{.interpreted-text role="ref"} - -## Storage volume - -The Storage volume is defined as the volume of water \[in m\^3\] for -which the conditions for flowing water are not met. Storage volume -does not contribute to conveyance, but serves only for water -retention. Examples include groyne fields and - -See `distinguish_storage`{.interpreted-text role="ref"} - -## Total width - -See `Total volume`{.interpreted-text role="term"} - -## Flow width - -See `Flow volume`{.interpreted-text role="term"} - +# Important concepts + +## Control volume + +A control volume is a bounded area that describes a section of +a 2D model that is assigned to a 1D cross-section. The figure +below shows a schematical overview. + +Control volumes are a conceptual concept and not defined in their +own right. Instead, all relevant 2D data, such as bed levels, +flow velocities and roughness information is assigned to a +cross-section by k-Nearest Neighbour classification. As such, +the bounds of the control volumes are not uniquely defined by +a polygon but rather by a collection of points. + +Control volumes use the 2D coordinates of each cross-section as +specified in the CrossSectionLocationFile during the nearest-neighbour +classification. The 2D input data used during classification is +filtered by [region](#regions) in the following way: a cross-section within +a certain region can only be assigned 2D information from that region. + +The `CrossSectionLocationFile` additionally contains information on the 1D +coordinates (branch and chainage) and the length. +The figure below shows how cross-section length +is defined. We recommend that this file is generated using the +[GenerateCrossSectionLocations](../user_docs/utils/GenerateCrossSectionsLocations.md) +tool. + +An approximation of the control volumes is generated by the program +during the finalisation step. This is a convex hull approximation, +which is usefull for debugging input errors (see [Troubleshooting](../user_docs/troubleshooting.md)) + + +!!! note + + Control volumes are the equivalent of WAQ2PROF's sobekvakken + +
+ ![Image title](../figures/controlvolume.png){ width="300" } +
A control volume
+
+ + +## Regions + +Regions are used to have some finer control over which 2D model +output is assigned to which 1D cross-section. If no region are +defined, 2D model output is assigned to cross-section using +k-nearest neighbour. This is not always a good approach, for example +if a tributary or retention area. In the figure a section of the +River Meuse is plotted near the [Blitterswijck retention +area](https://www.openstreetmap.org/search?query=blitterswijck#map=16/51.5405/6.1122). +The retention area is demarcated from the main river by levees. +Cross-sections generated for the retention area should therefore not +'eat out of' the area of the main channel - which could results in +a small cross-section non-physical constriction of the flow. + +
+ ![Image title](../figures/region_polygon_blitwijk.PNG){ width="300" } +
Region polygons are used to prevent cross-sections generated + in the retention area to 'eat out of' the main channel. Within each + region polygon (red borders) nearest neighour is used to assign 2D + points to cross-sections. Points with the same color are associated with + the same 1D cross-section
+
+ + +## Sections + +Sections are used to divide the cross-section between floodplain and +main channel (e.g. the 'floodplain' section and the 'main channel' section). This distinction is only used to assign +different roughness values to each section. + +## Water level (in)dependent geometry + +It is often not possible to start the 2D computation from a +completely dry bed - instead some initial water level is present in +the model. This initial condition divides the 1D geometry in water +level dependent part and a water level independent part. Below the +initial condition, we cannot take advantage of the 2D model to tell +us which cells are part of the conveyance and which cells are wet. +Instead, the water level is artificially lowered in a number of +steps to estimate the volume below the initial water levels. + +## Summerdikes + +Summerdikes are a Dutch term for levees that are designed to be +flooded with higher discharges, but not with relatively low floods +(i.e.: they withstand summer floods). They contrast with +'winterdikes', which are designed to not flood at all. Summerdikes +effectively comparimentalise the floodplain. They can have a +profound effect on stage-discharge relationships: as these levees +overflow the compartments start flowing which leads to a retention +effect. Such an effect cannot be modelled using regulare +cross-sections. SOBEK therefore has a 'summerdike' functionality. + +## Lakes + +Lakes are water bodies that are not hydraulically connected to the +main channel in the first few timesteps of the 2D model computation. +They do not contribute to the volume present in the control volume +until they connect with the rest of the river and will not feature +in the water level independent computation. +Water bodies that *are* connected to the main channel +in the first few timesteps **do** count as volume. However, as these +likely do not contribute to conveyance, they will be flagged as +'storage' instead. + +
+ ![Image title](../figures/gis_visualisation_maas_03_annotated.png){ width="300" } +
+
+ + +## Total volume + +The Total volume refers to the volume of water \[in m\^3\] within a +`Control volume`{.interpreted-text role="term"} for a given water +level at the `Cross-section location`{.interpreted-text +role="term"}. The total volume is the sum of the +`Flow volume`{.interpreted-text role="term"} and the +`Storage volume`{.interpreted-text role="term"}. + +## Flow volume + +The Flow volume is defined as the volume of water \[in m\^3\] for +which the conditions for flowing water are met. This volume is +considered to be available for the conveyance of water through the +`Control volume`{.interpreted-text role="term"}. + +See `distinguish_storage`{.interpreted-text role="ref"} + +## Storage volume + +The Storage volume is defined as the volume of water \[in m\^3\] for +which the conditions for flowing water are not met. Storage volume +does not contribute to conveyance, but serves only for water +retention. Examples include groyne fields and + +See `distinguish_storage`{.interpreted-text role="ref"} + +## Total width + +See `Total volume`{.interpreted-text role="term"} + +## Flow width + +See `Flow volume`{.interpreted-text role="term"} + diff --git a/docs/markdown/numerical_methods.md b/docs/tech_docs/numerical_methods.md similarity index 95% rename from docs/markdown/numerical_methods.md rename to docs/tech_docs/numerical_methods.md index 2b59d4d9..b8b5c1cd 100644 --- a/docs/markdown/numerical_methods.md +++ b/docs/tech_docs/numerical_methods.md @@ -1,15 +1,15 @@ -# Numerical methods - -## Cross-section construction - -### Conveyance-storage separation - -::: fm2prof.cross_section.CrossSection._distinguish_conveyance_from_storage - -### Simplification - -::: fm2prof.cross_section.CrossSection.reduce_points - -### Lake identification - +# Numerical methods + +## Cross-section construction + +### Conveyance-storage separation + +::: fm2prof.cross_section.CrossSection._distinguish_conveyance_from_storage + +### Simplification + +::: fm2prof.cross_section.CrossSection.reduce_points + +### Lake identification + ::: fm2prof.cross_section.CrossSection._identify_lakes \ No newline at end of file diff --git a/docs/user_docs/configuration.md b/docs/user_docs/configuration.md new file mode 100644 index 00000000..a308eaef --- /dev/null +++ b/docs/user_docs/configuration.md @@ -0,0 +1,42 @@ +# Configuration file + +Settings are managed in the FM2PROF configuration file. This is an *.ini file. + +```python exec="on" +import json +print('```') +with open('fm2prof/configurationfile_template.json', 'r') as f: + config = json.load(f) + for section_name, section_content in config["sections"].items(): + print(f"[" + section_name.capitalize() + "]") + for key_value, key_content in section_content.items(): + print (f"{key_value} = {key_content.get('value')}") + +print('```') + +``` + +## Configuration file parameters + +```python exec="on" +import json + +with open('fm2prof/configurationfile_template.json', 'r') as f: + config = json.load(f) + for section_name, section_content in config["sections"].items(): + print(f"### " + section_name.capitalize()) + for key_value, key_content in section_content.items(): + print (f"#### {key_value}") + print (f""" + +{key_content.get('hint')} + +| Input | Value | +|----------|:-------------:| +| Type | {key_content.get('type')} | +| Default value |{key_content.get('value')}| + +""") + + +``` \ No newline at end of file diff --git a/docs/markdown/installation.md b/docs/user_docs/installation.md similarity index 100% rename from docs/markdown/installation.md rename to docs/user_docs/installation.md diff --git a/docs/user_docs/output_files.md b/docs/user_docs/output_files.md new file mode 100644 index 00000000..1a78ca40 --- /dev/null +++ b/docs/user_docs/output_files.md @@ -0,0 +1,224 @@ +# Output Files + +FM2PROF generates a set of output files that can be used to set up 1D hydraulic models. This page describes the output files that are generated and their purpose. + +## Output Directory Structure + +After running FM2PROF, the output files are organized in subdirectories: + +``` +output/ +├── fm2prof.log +├── dflow1d/ # D-Flow 1D format files +│ ├── CrossSectionLocations.ini +│ ├── CrossSectionDefinitions.ini +│ ├── roughness-Main.ini +│ ├── roughness-FloodPlain1.ini +│ ├── roughness-FloodPlain2.ini +│ └── volumes.csv +└── dhydro/ # D-Hydro (1D) format files +│ ├── crsloc.ini +│ ├── crsdef.ini +│ ├── roughness-Main.ini +│ ├── roughness-FloodPlain1.ini +│ ├── roughness-FloodPlain2.ini +│ └── volumes.csv +└── debug/ # Optional debug files (if enabled in configuration) + ├── cross_section_volumes.geojson + ├── face_output.geojson + └── edge_output.geojson +``` + + +!!! note + The "dflow1d" format is only used by the SOBEK 3 software from version 3.5 + and higher. Support for SOBEK 3.4 and lower has been dropped since FM2PROF + version 2.5 + + + + + +### File Differences between dhydro and dflow1d (SOBEK 3) +The `dhydro` and `dflow1d` formats are alternative output formats with slightly different file naming conventions. The `dflow1d` is used by SOBEK 3, while `dhydro` is used by the D-Hydro 1D2D software. + +| `dflow1d` | `dhydro` | Description | +|-----------|--------------|-------------| +| CrossSectionLocations.ini | crsloc.ini | Cross-section locations | +| CrossSectionDefinitions.ini | crsdef.ini | Cross-section definitions | +| roughness-*.ini | roughness-*.ini | Roughness files (same naming) | +| volumes.csv | volumes.csv | Volume comparison (same naming) | + + +## Output Format + +The D-Flow 1D format is the default output format and generates files compatible with Deltares D-Flow 1D software. + +### CrossSectionLocations.ini / crsloc.ini + +This file contains the spatial locations of the cross-sections along the river or channel network. + +**Example:** +=== "dflow1d" + + ```ini + [CrossSection] + id = channel1_125.000 + branchid = Channel1 + chainage = 125.0 + shift = 0.000 + definition = channel1_125.000 + + ``` +=== "dhydro" + + ```ini + [CrossSection] + Id = channel1_125.000 + branchId = Channel1 + chainage = 125.0 + shift = 0.000 + definitionId = channel1_125.000 + + ``` + +### CrossSectionDefinitions.ini / crsdef.ini + +This file contains the geometrical definitions of each cross-section, including the shape and dimensions. + +**Example** + +=== "dflow1d" + + ```ini + [Definition] + id = channel1_125.000 + type = tabulated + thalweg = 0.000 + numLevels = 20 + levels = -2.0249 -1.9486 -1.9476 -1.8829 -1.8261 -1.7498 -1.6281 -1.5567 -1.4315 -1.3622 -0.5710 -0.0747 -0.0391 -0.0216 -0.0049 0.0695 0.4215 0.8350 1.2430 1.7807 + flowWidths = 50.0000 50.0090 50.0100 50.0150 50.0210 50.0250 50.0330 50.0370 50.0450 50.0490 50.0980 50.1290 50.1310 50.1320 150.0000 150.0040 150.0240 150.0480 150.0720 150.1040 + totalWidths = 50.0000 50.0090 50.0100 50.0150 50.0210 50.0250 50.0330 50.0370 50.0450 50.0490 50.0980 50.1290 50.1310 100.0000 150.0000 150.0040 150.0240 150.0480 150.0720 150.1040 + sd_crest = -0.2912 + sd_flowArea = 1.0473561480652571 + sd_totalArea = 1.0474 + sd_baseLevel = -0.7912269469444795 + main = 50.1040 + floodPlain1 = 100.0000 + floodPlain2 = 0.0000 + groundlayerUsed = 0 + groundLayer = 0.000 + ``` + +=== "dhydro" + + ```ini + [Definition] + Id = channel1_125.000 + Type = zwRiver + Thalweg = 0.000 + numLevels = 20 + levels = -2.0249 -1.9486 -1.9476 -1.8829 -1.8261 -1.7498 -1.6281 -1.5567 -1.4315 -1.3622 -0.5710 -0.0747 -0.0391 -0.0216 -0.0049 0.0695 0.4215 0.8350 1.2430 1.7807 + flowWidths = 50.0000 50.0090 50.0100 50.0150 50.0210 50.0250 50.0330 50.0370 50.0450 50.0490 50.0980 50.1290 50.1310 50.1320 150.0000 150.0040 150.0240 150.0480 150.0720 150.1040 + totalWidths = 50.0000 50.0090 50.0100 50.0150 50.0210 50.0250 50.0330 50.0370 50.0450 50.0490 50.0980 50.1290 50.1310 100.0000 150.0000 150.0040 150.0240 150.0480 150.0720 150.1040 + leveeCrestLevel = -0.2912 + leveeFlowArea = 1.0473561480652571 + leveeTotalArea = 1.0474 + levelBaseLevel = -0.7912269469444795 + mainWidth = 50.1040 + fp1Width = 100.0000 + fp2Width = 0.0000 + ``` + + + +### roughness-x.ini + +This file contains roughness coefficients for a section of the cross-section. Valid sections are "main", "floodplain1" and "floodplain2". FM2PROF always output the values as Chézy coefficient. + + +**Example:** +=== "dflow1d" + ```ini + [Content] + sectionId = Main + flowDirection = False + interpolate = 1 + globalType = 1 + globalValue = 45 + + [BranchProperties] + branchId = Channel1 + roughnessType = 1 + functionType = 2 + numLevels = 42 + levels = -2.4028 -2.3028 -2.2028 -2.1028 -2.0028 -1.9028 -1.8028 -1.7028 -1.6028 -1.5028 -1.4028 -1.3028 -1.2028 -1.1028 -1.0028 -0.9028 -0.8028 -0.7028 -0.6028 -0.5028 -0.4028 -0.3028 -0.2028 -0.1028 -0.0028 0.0972 0.1972 0.2972 0.3972 0.4972 0.5972 0.6972 0.7972 0.8972 0.9972 1.0972 1.1972 1.2972 1.3972 1.4972 1.5972 1.6972 + + [Definition] + branchId = Channel1 + chainage = 125.0 + values = 22.71 22.71 22.71 22.71 22.71 23.47 25.93 27.59 28.86 29.91 30.79 31.57 32.26 32.88 33.45 33.98 34.47 34.92 35.35 35.75 36.13 36.49 36.84 37.17 37.48 37.79 38.08 38.36 38.62 38.89 39.14 39.38 39.62 39.85 40.07 40.29 40.5 40.71 40.91 41.11 41.3 41.49 + ``` + +=== "dhydro" + + ```ini + [Global] + frictionId = Main + frictionType = Chezy + frictionValue = 45 + + [Branch] + branchId = Channel1 + frictionType = Chezy + functionType = Waterlevel + numLevels = 42 + levels = -2.4028 -2.3028 -2.2028 -2.1028 -2.0028 -1.9028 -1.8028 -1.7028 -1.6028 -1.5028 -1.4028 -1.3028 -1.2028 -1.1028 -1.0028 -0.9028 -0.8028 -0.7028 -0.6028 -0.5028 -0.4028 -0.3028 -0.2028 -0.1028 -0.0028 0.0972 0.1972 0.2972 0.3972 0.4972 0.5972 0.6972 0.7972 0.8972 0.9972 1.0972 1.1972 1.2972 1.3972 1.4972 1.5972 1.6972 + numLocations = 14 + chainage = 125.0000 225.0000 325.0000 425.0000 525.0000 625.0000 725.0000 825.0000 925.0000 1025.0000 1125.0000 1225.0000 1325.0000 1425.0000 + frictionValues = 22.7097 22.7097 22.7097 22.7097 22.7097 23.4671 25.9284 27.5925 28.8645 29.9081 30.7947 31.5704 32.2605 32.8842 33.4534 33.9782 34.4652 34.9203 35.3474 35.7501 36.1314 36.4936 36.8386 37.1682 37.4836 37.7854 38.0757 38.3553 38.6250 38.8857 39.1379 39.3824 39.6195 39.8498 40.0737 40.2915 40.5037 40.7105 40.9122 41.1091 41.3015 41.4894 + 22.7097 22.7097 22.7097 22.7097 22.7097 24.4354 26.5433 28.0504 29.2338 30.2186 31.0641 31.8090 32.4751 33.0796 33.6330 34.1445 34.6203 35.0657 35.4842 35.8795 36.2541 36.6105 36.9502 37.2749 37.5855 37.8843 38.1715 38.4485 38.7156 38.9739 39.2239 39.4661 39.7011 39.9294 40.1513 40.3673 40.5776 40.7827 40.9826 41.1779 41.3687 41.5551 + 22.7097 22.7097 22.7097 22.7097 22.7097 25.2428 27.0931 28.4730 29.5806 30.5140 31.3224 32.0391 32.6829 33.2692 33.8078 34.3068 34.7720 35.2079 35.6184 36.0066 36.3749 36.7254 37.0601 37.3800 37.6866 37.9814 38.2654 38.5390 38.8033 39.0589 39.3063 39.5463 39.7791 40.0053 40.2253 40.4394 40.6480 40.8514 41.0498 41.2435 41.4328 41.6179 + 22.7097 22.7097 22.7097 22.7097 23.4664 25.9278 27.5927 28.8645 29.9081 30.7947 31.5704 32.2606 32.8842 33.4535 33.9783 34.4653 34.9204 35.3475 35.7502 36.1315 36.4937 36.8387 37.1683 37.4838 37.7864 38.0774 38.3578 38.6283 38.8896 39.1424 39.3874 39.6249 39.8555 40.0797 40.2977 40.5100 40.7168 40.9186 41.1154 41.3077 41.4956 41.6171 + 22.7097 22.7097 22.7097 22.7097 24.4352 26.5437 28.0502 29.2337 30.2186 31.0641 31.8091 32.4752 33.0796 33.6330 34.1446 34.6204 35.0657 35.4843 35.8796 36.2542 36.6106 36.9502 37.2751 37.5858 37.8847 38.1721 38.4491 38.7164 38.9749 39.2250 39.4675 39.7026 39.9311 40.1531 40.3693 40.5797 40.7849 40.9849 41.1803 41.3711 41.5576 41.6163 + 22.7097 22.7097 22.7097 22.7097 25.2430 27.0933 28.4729 29.5806 30.5140 31.3225 32.0392 32.6829 33.2692 33.8079 34.3068 34.7720 35.2080 35.6185 36.0067 36.3750 36.7255 37.0602 37.3802 37.6868 37.9816 38.2656 38.5392 38.8036 39.0592 39.3067 39.5467 39.7795 40.0058 40.2259 40.4401 40.6487 40.8522 41.0507 41.2445 41.4338 41.6164 41.6164 + 22.7097 22.7097 22.7097 23.4659 25.9273 27.5928 28.8644 29.9081 30.7948 31.5705 32.2606 32.8843 33.4535 33.9784 34.4654 34.9205 35.3475 35.7503 36.1316 36.4938 36.8388 37.1685 37.4840 37.7865 38.0775 38.3579 38.6283 38.8897 39.1425 39.3875 39.6250 39.8557 40.0799 40.2979 40.5102 40.7172 40.9189 41.1158 41.3081 41.4961 41.6168 41.6168 + 22.7097 22.7097 22.7097 24.4351 26.5439 28.0501 29.2337 30.2186 31.0641 31.8091 32.4752 33.0797 33.6331 34.1447 34.6205 35.0658 35.4844 35.8797 36.2544 36.6107 36.9504 37.2752 37.5859 37.8848 38.1721 38.4492 38.7165 38.9750 39.2251 39.4675 39.7027 39.9312 40.1532 40.3694 40.5798 40.7850 40.9851 41.1805 41.3713 41.5578 41.6174 41.6174 + 22.7097 22.7097 22.7170 25.2431 27.0935 28.4729 29.5805 30.5141 31.3225 32.0392 32.6830 33.2693 33.8080 34.3069 34.7721 35.2081 35.6187 36.0068 36.3751 36.7257 37.0603 37.3803 37.6869 37.9818 38.2656 38.5393 38.8036 39.0592 39.3067 39.5467 39.7796 40.0059 40.2259 40.4401 40.6488 40.8523 41.0507 41.2446 41.4339 41.6181 41.6181 41.6181 + 22.7097 22.7097 23.4656 25.9269 27.5930 28.8644 29.9081 30.7948 31.5705 32.2607 32.8843 33.4536 33.9784 34.4655 34.9206 35.3476 35.7505 36.1317 36.4939 36.8389 37.1686 37.4841 37.7866 38.0776 38.3580 38.6284 38.8898 39.1426 39.3876 39.6251 39.8558 40.0799 40.2980 40.5103 40.7172 40.9190 41.1159 41.3082 41.4961 41.6188 41.6188 41.6188 + 22.7097 22.7097 24.4350 26.5434 28.0500 29.2336 30.2186 31.0642 31.8092 32.4753 33.0797 33.6332 34.1448 34.6206 35.0659 35.4845 35.8799 36.2545 36.6108 36.9505 37.2754 37.5860 37.8849 38.1722 38.4493 38.7165 38.9750 39.2251 39.4676 39.7027 39.9312 40.1533 40.3694 40.5798 40.7850 40.9851 41.1805 41.3713 41.5579 41.6196 41.6196 41.6196 + 22.7097 22.7217 25.2429 27.0938 28.4729 29.5805 30.5141 31.3225 32.0392 32.6830 33.2694 33.8081 34.3071 34.7722 35.2082 35.6188 36.0070 36.3753 36.7258 37.0604 37.3804 37.6871 37.9819 38.2657 38.5394 38.8037 39.0593 39.3068 39.5468 39.7796 40.0059 40.2260 40.4402 40.6488 40.8523 41.0508 41.2446 41.4340 41.6191 41.6205 41.6205 41.6205 + 22.7097 23.4654 25.9266 27.5928 28.8644 29.9081 30.7948 31.5705 32.2608 32.8844 33.4537 33.9786 34.4656 34.9207 35.3478 35.7506 36.1319 36.4941 36.8391 37.1687 37.4842 37.7867 38.0777 38.3581 38.6285 38.8899 39.1427 39.3876 39.6251 39.8558 40.0800 40.2980 40.5103 40.7172 40.9190 41.1159 41.3082 41.4962 41.6213 41.6213 41.6213 41.6213 + 22.7097 24.4351 26.5430 28.0499 29.2336 30.2186 31.0642 31.8092 32.4754 33.0798 33.6333 34.1449 34.6207 35.0661 35.4846 35.8801 36.2547 36.6110 36.9507 37.2755 37.5862 37.8851 38.1723 38.4493 38.7166 38.9751 39.2252 39.4676 39.7028 39.9312 40.1533 40.3694 40.5799 40.7850 40.9852 41.1805 41.3713 41.5579 41.6222 41.6222 41.6222 41.6222 + ``` + + +### volumes.csv + +This file contains a comparison between 2D model volumes and the reconstructed 1D cross-section volumes. + +**Columns:** + +| Column Name | Description | +|-------------|-------------| +| `id` | Cross-section identifier | +| `z` | Water level (elevation) | +| `2D_total_volume` | Total storage volume from 2D model | +| `2D_flow_volume` | Flow (conveyance) volume from 2D model | +| `2D_wet_area` | Wetted area from 2D model | +| `2D_flow_area` | Flow area from 2D model | +| `1D_total_volume_sd` | Total volume for 1D cross-section including levee (summer dike)| +| `1D_total_volume` | Total storage volume for 1D cross-section | +| `1D_flow_volume_sd` | Flow volume for 1D cross-section including levee (summer dike)| +| `1D_flow_volume` | Flow volume for 1D cross-section | +| `1D_total_width` | Total width of 1D cross-section | +| `1D_flow_width` | Flow width of 1D cross-section | + +**Example:** +```csv +id,z,2D_total_volume,2D_flow_volume,2D_wet_area,2D_flow_area,1D_total_volume_sd,1D_total_volume,1D_flow_volume_sd,1D_flow_volume,1D_total_width,1D_flow_width +CS_001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +CS_001,0.5,125.5,100.2,250.0,200.0,124.8,125.0,99.8,100.0,250.0,200.0 +CS_001,1.0,502.3,400.5,502.0,401.0,501.5,502.0,399.9,400.0,502.0,401.0 +... +``` diff --git a/docs/markdown/overview.md b/docs/user_docs/overview.md similarity index 100% rename from docs/markdown/overview.md rename to docs/user_docs/overview.md diff --git a/docs/markdown/quickstart.md b/docs/user_docs/quickstart.md similarity index 97% rename from docs/markdown/quickstart.md rename to docs/user_docs/quickstart.md index 196e5d75..b51811c7 100644 --- a/docs/markdown/quickstart.md +++ b/docs/user_docs/quickstart.md @@ -130,4 +130,4 @@ All `outputFiles` are written to the `output` directory specified in the FM2PROF After generating output it is important to check whether everything went well. See the following links to learn more about available tools: -- [Inspection cross-sections using a notebook](../../notebooks/cross_section_data) \ No newline at end of file +- [Inspection cross-sections using a notebook](../notebooks/cross_section_data) \ No newline at end of file diff --git a/docs/markdown/troubleshooting.md b/docs/user_docs/troubleshooting.md similarity index 93% rename from docs/markdown/troubleshooting.md rename to docs/user_docs/troubleshooting.md index 483656f2..5586bd8e 100644 --- a/docs/markdown/troubleshooting.md +++ b/docs/user_docs/troubleshooting.md @@ -5,9 +5,9 @@ One of the output files is a geojson file called `cross_section_volumes.geojson`. This file can be opened and visualised using common GIS software, for example QGIS. This file contains convex hull approximation of the -[control volumes](glossary.md#control-volume). +[control volumes](../tech_docs/glossary.md#control-volume). -A good file has cleary delineated polygon within each [region](glossary.md#region). +A good file has cleary delineated polygon within each [region](../tech_docs/glossary.md#region). Common problems that can be spotted by visualising this file are detailed below. @@ -29,7 +29,7 @@ this often results in something like the figure below. ### Problem: Cross-section in wrong region -A [region](glossary.md#region) is used to prevent side-branches from limiting +A [region](../tech_docs/glossary.md#region) is used to prevent side-branches from limiting the cross-sectional volume of the main channel. Users should take care to make sure that all cross-section locations lie within the appropriate region. The figure below shows an example where this is not the case. diff --git a/docs/markdown/utils/GenerateCrossSectionsLocations.md b/docs/user_docs/utils/GenerateCrossSectionsLocations.md similarity index 100% rename from docs/markdown/utils/GenerateCrossSectionsLocations.md rename to docs/user_docs/utils/GenerateCrossSectionsLocations.md diff --git a/docs/markdown/utils/compare1d2d.md b/docs/user_docs/utils/compare1d2d.md similarity index 100% rename from docs/markdown/utils/compare1d2d.md rename to docs/user_docs/utils/compare1d2d.md diff --git a/docs/markdown/utils/visualiseoutput.md b/docs/user_docs/utils/visualiseoutput.md similarity index 100% rename from docs/markdown/utils/visualiseoutput.md rename to docs/user_docs/utils/visualiseoutput.md diff --git a/fm2prof/cross_section.py b/fm2prof/cross_section.py index a319d0dc..c648bd44 100644 --- a/fm2prof/cross_section.py +++ b/fm2prof/cross_section.py @@ -2,9 +2,7 @@ from __future__ import annotations -import math import pickle -import traceback from functools import reduce from pathlib import Path from typing import TYPE_CHECKING @@ -1015,11 +1013,11 @@ def _compute_floodplain_base(self) -> None: ) def _identify_lakes(self, waterdepth: pd.DataFrame) -> np.ndarray: - """Determine whether a 2D cell should be marked as [Lake](glossary.md#Lakes). + """Determine whether a 2D cell should be marked as [Lake](glossary.md#lakes). Cells are marked as lake if the following conditions are both met: - - the waterdepth on timestep [LakeTimeSteps](configuration.md#exec-1--laketimesteps) is positive - - the waterdepth on timestep [LakeTimeSteps](configuration.md#exec-1--laketimesteps) is at least + - the waterdepth on timestep [LakeTimeSteps](../user_docs/configuration.md) is positive + - the waterdepth on timestep [LakeTimeSteps](../user_docs/configuration.md) is at least 1 cm higher than the waterlevel on timestep 0. Next, the following steps are taken @@ -1157,9 +1155,9 @@ def _distinguish_conveyance_from_storage( **`max_method`** A cell is considered flowing if the velocity magnitude is more than the average of the three higher flow velocities per outputmap multiplied by the - [`relative velocity threshold`](configuration.md#exec-1--relativevelocitythreshold) OR + [`relative velocity threshold`](../user_docs/configuration.md#exec-1--relativevelocitythreshold) OR if the flow velocity meets the absolute threshold [`absolute velocity threshold`] - (configuration.md#exec-1--absolutevelocitythreshold) + (../user_docs/configuration.md#exec-1--absolutevelocitythreshold) **`mean_method`** Not recommended. Legacy method. diff --git a/fm2prof/utils.py b/fm2prof/utils.py index 417b6f82..1752d1b5 100644 --- a/fm2prof/utils.py +++ b/fm2prof/utils.py @@ -82,7 +82,7 @@ class GenerateCrossSectionLocationFile(FM2ProfBase): A [`CrossSectionInputFile`](../configuration.md) is a file that contains the locations of cross-sections as X,Y coordinates, the lengths of each cross-section and the branch and offset/chainage on which they are located. For a conceptual overview of how this data is used in FM2PROF, see - [Control Volumes](../glossary.md#control-volume). + [Control Volumes](../../tech_docs/glossary.md#control-volume). This is a vitally important file for FM2PROF, as it defines not only where the cross-sections are located, but also how 2D volumes are mapped to 1D widths. This utility helps to generate a @@ -116,7 +116,7 @@ class GenerateCrossSectionLocationFile(FM2ProfBase): This optional file is used to exclude certain computational points from being used as the location of a cross-section. This is particularly useful - when smaller branches connect to a major branch, see [Troubleshooting](troubleshooting.md). + when smaller branches connect to a major branch, see [Troubleshooting](../troubleshooting.md). The branch_rule_file is a comma-separated file with the following syntax: @@ -1168,7 +1168,7 @@ def _style_figure( ) return fig, lgd - return fig, handles, labels + return fig, [handles, labels] class ModelOutputReader(FM2ProfBase): diff --git a/mkdocs.yml b/mkdocs.yml index f35cb1cc..4773c4ac 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -86,36 +86,32 @@ extra_css: nav: - Home: index.md - - Guides: - - release procedures: guides/release.md - User Manual: - - Overview: markdown/overview.md - - Installation: markdown/installation.md - - Quickstart: markdown/quickstart.md - - Output files: markdown/output_files.md - - Analysing results: + - Overview: user_docs/overview.md + - Installation: user_docs/installation.md + - Quickstart: user_docs/quickstart.md + - Files and Settings: + - user_docs/configuration.md + - user_docs/output_files.md + - Advanced use: + - user_docs/troubleshooting.md - notebooks/cross_section_data.ipynb - - markdown/troubleshooting.md - Utilities: - Generate CrossSection Location file: - - markdown/utils/GenerateCrossSectionsLocations.md + - user_docs/utils/GenerateCrossSectionsLocations.md - Compare 1D and 2D model results: - - markdown/utils/compare1d2d.md + - user_docs/utils/compare1d2d.md - Example: notebooks/compare1d2d.ipynb - VisualiseOutput: - - markdown/utils/visualiseoutput.md + - user_docs/utils/visualiseoutput.md - notebooks/VisualiseOutput.ipynb - - Files and Settings: - - markdown/configuration.md - - Files: - - markdown/files/2DMapOutput.md - - markdown/files/branch_rule_file.md - Technical Manual: - - Methodology: markdown/conceptual_design.md - - Important concepts: markdown/glossary.md - - Numerical methods: markdown/numerical_methods.md - - API: markdown/api.md - - Contributing: markdown/contributing.md + - Methodology: tech_docs/conceptual_design.md + - Important concepts: tech_docs/glossary.md + - Numerical methods: tech_docs/numerical_methods.md + - API: tech_docs/api.md + - Contributing: + - dev_docs/contributing.md - Changelog: CHANGELOG.md markdown_extensions: - admonition diff --git a/tests/test_utils.py b/tests/test_utils.py index fa25c821..482e09c7 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -3,14 +3,60 @@ from datetime import datetime from pathlib import Path +import matplotlib.pyplot as plt import pytest +from matplotlib.legend import Legend from fm2prof import Project -from fm2prof.utils import Compare1D2D, GenerateCrossSectionLocationFile, VisualiseOutput +from fm2prof.utils import Compare1D2D, GenerateCrossSectionLocationFile, PlotStyles, VisualiseOutput from tests.TestUtils import TestUtils _root_output_dir = None +@pytest.fixture +def simple_figure(): + """Create a simple figure with a single plot for testing.""" + fig, ax = plt.subplots() + ax.plot([1, 2, 3], [1, 2, 3], label="test line") + yield fig + plt.close(fig) + +class TestPlotStylesApply: + def test_use_legend_true_returns_legend_object(self, simple_figure): + """When use_legend=True, second return value should be a Legend object.""" + fig, lgd = PlotStyles.apply(fig=simple_figure, use_legend=True) + assert isinstance(lgd, Legend) + + def test_use_legend_false_returns_list(self, simple_figure): + """When use_legend=False, second return value should be a list.""" + fig, result = PlotStyles.apply(fig=simple_figure, use_legend=False) + assert isinstance(result, list) + + def test_use_legend_false_returns_list_of_handles_and_labels(self, simple_figure): + """When use_legend=False, returned list should contain [handles, labels].""" + fig, result = PlotStyles.apply(fig=simple_figure, use_legend=False) + assert len(result) == 2 # [handles, labels] + handles, labels = result + assert isinstance(handles, list) + assert isinstance(labels, list) + + def test_use_legend_false_labels_match_plot_labels(self, simple_figure): + """When use_legend=False, labels in result should match plot labels.""" + fig, result = PlotStyles.apply(fig=simple_figure, use_legend=False) + _, labels = result + assert "test line" in labels + + def test_first_return_value_is_always_figure(self, simple_figure): + """First return value should always be a Figure, regardless of use_legend.""" + from matplotlib.figure import Figure + fig_true, _ = PlotStyles.apply(fig=simple_figure, use_legend=True) + assert isinstance(fig_true, Figure) + + fig2, ax2 = plt.subplots() + ax2.plot([1, 2], [1, 2], label="test") + fig_false, _ = PlotStyles.apply(fig=fig2, use_legend=False) + assert isinstance(fig_false, Figure) + plt.close(fig2) class Test_GenerateCrossSectionLocationFile: def test_given_networkdefinitionfile_cssloc_file_is_generated(self, tmp_path: Path):