diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index a79930d913..38648c3988 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -29,7 +29,7 @@
folder.
-->
-- [ ] Add a [news fragment](https://landlab.readthedocs.io/en/master/development/contribution/index.html#news-entries) file entry if necessary?
+- [ ] Add a [news fragment](https://landlab.csdms.io/development/contribution/#news-entries) file entry if necessary?
- [ ] Add / update tests if necessary?
- [ ] Add new / update outdated documentation?
- [ ] All tests have passed?
@@ -42,7 +42,7 @@
Helpful links:
- Developer guide: https://landlab.readthedocs.io/en/master/development
+ Developer guide: https://landlab.csdms.io/development/
Ask a question or submit an issue: https://github.com/landlab/landlab/issues
Landlab Slack channel: https://landlab.slack.com
-->
diff --git a/.github/actions/build-bdist/action.yml b/.github/actions/build-bdist/action.yml
new file mode 100644
index 0000000000..b1f718a6ba
--- /dev/null
+++ b/.github/actions/build-bdist/action.yml
@@ -0,0 +1,37 @@
+name: "Build a binary distribution"
+inputs:
+ cibw-only:
+ required: true
+ upload-name:
+ required: true
+runs:
+ using: "composite"
+ steps:
+ - name: Python 3.12
+ uses: actions/setup-python@v5
+ with:
+ python-version: 3.12
+
+ - name: Print build identifiers
+ shell: bash -l {0}
+ run: |
+ python -m pip install cibuildwheel
+ python -m cibuildwheel --only ${{ inputs.cibw-only }} --print-build-identifiers
+
+ - name: Install openmp
+ if: runner.os == 'macOS'
+ shell: bash -l {0}
+ run: |
+ curl -O https://mac.r-project.org/openmp/openmp-13.0.0-darwin21-Release.tar.gz
+ sudo tar fvxz openmp-13.0.0-darwin21-Release.tar.gz -C /
+
+ - name: Build wheels
+ uses: pypa/cibuildwheel@v2.21.2
+ with:
+ only: ${{ inputs.cibw-only }}
+
+ - uses: actions/upload-artifact@v4
+ with:
+ name: ${{ inputs.upload-name }}
+ path: ${{ github.workspace }}/wheelhouse/*.whl
+ overwrite: true
diff --git a/.github/actions/run-notebooks/action.yml b/.github/actions/run-notebooks/action.yml
new file mode 100644
index 0000000000..5a108ab8c9
--- /dev/null
+++ b/.github/actions/run-notebooks/action.yml
@@ -0,0 +1,56 @@
+name: "Run notebooks"
+inputs:
+ python-version:
+ required: true
+ pytest-addopts:
+ required: false
+ default: ''
+ nox-session:
+ required: true
+ upload-name:
+ required: false
+ default: ''
+runs:
+ using: "composite"
+ steps:
+ - uses: actions/checkout@v4
+ - name: Python ${{ inputs.python-version }}
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ inputs.python-version }}
+
+ - uses: actions/download-artifact@v4
+ name: Download build artifacts
+ with:
+ pattern: "build-*"
+ merge-multiple: true
+ path: ${{ github.workspace }}/dist
+
+ - name: Test
+ env:
+ OPENTOPOGRAPHY_API_KEY: ${{ inputs.opentopography_api_key }}
+ MPLBACKEND: "module://matplotlib_inline.backend_inline"
+ PYTEST_ADDOPTS: ${{ inputs.pytest-addopts }}
+ shell: bash -l {0}
+ run: |
+ pip install nox
+ nox --verbose -s ${{ inputs.nox-session }} \
+ --force-pythons=${{ inputs.python-version }} \
+ -- dist/
+
+ - name: Find executed notebooks
+ shell: bash -l {0}
+ run: |
+ for f in $(git diff --name-only); do
+ mkdir -p executed/$(dirname $f);
+ cp $f executed/$(dirname $f);
+ done
+ ls -R executed/
+
+ - name: Upload executed notebooks
+ if: ${{ inputs.upload-name != '' }}
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ inputs.upload-name }}
+ path: executed/
+ overwrite: true
diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml
new file mode 100644
index 0000000000..21bdccee12
--- /dev/null
+++ b/.github/actions/run-tests/action.yml
@@ -0,0 +1,43 @@
+name: "Run tests"
+inputs:
+ python-version:
+ required: true
+ pytest-addopts:
+ required: true
+ nox-session:
+ required: true
+ codedov-token:
+ required: true
+
+runs:
+ using: "composite"
+ steps:
+ - uses: actions/checkout@v4
+ - name: Python ${{ inputs.python-version }}
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ inputs.python-version }}
+
+ - uses: actions/download-artifact@v4
+ name: Download build artifacts
+ with:
+ pattern: "build-*"
+ merge-multiple: true
+ path: ${{ github.workspace }}/dist
+
+ - name: Test
+ env:
+ HYPOTHESIS_PROFILE: "ci"
+ MPLBACKEND: "Agg"
+ PYTEST_ADDOPTS: ${{ inputs.pytest-addopts }}
+ shell: bash -l {0}
+ run: |
+ pip install nox
+ nox --verbose -s ${{ inputs.nox-session }} \
+ --force-pythons=${{ inputs.python-version }} \
+ -- dist/
+
+ - name: Upload coverage reports to Codecov
+ uses: codecov/codecov-action@v5
+ with:
+ token: ${{ inputs.codecov-token }}
diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml
index 319c8d831d..15815ace8a 100644
--- a/.github/workflows/changelog.yml
+++ b/.github/workflows/changelog.yml
@@ -23,6 +23,6 @@ jobs:
if: contains(github.event.pull_request.labels.*.name, 'skip news') != true
run: |
if ! pipx run towncrier check --compare-with origin/${{ github.base_ref }}; then
- echo "Please see https://landlab.readthedocs.io/en/master/development/contribution/index.html?highlight=towncrier#news-entries for guidance."
+ echo "Please see https://landlab.csdms.io/en/master/development/contribution/index.html?highlight=towncrier#news-entries for guidance."
false
fi
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 9d0ca8d90f..b748809a6b 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -50,132 +50,90 @@ jobs:
name: build-sdist
path: ${{ github.workspace }}/dist/*.tar.gz
- # Until GA has native aarch64 runners, this step is extremely
- # slow so we run it as a separate job and hope if finishes
- # around the same time as everything else.
- build-aarch64:
+ build-wheels:
+ name: Build wheels on ${{ matrix.cibw-only }}
needs: check-tag
- name: Build aarch64 wheels on ${{ matrix.cibw-only }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- - cibw-only: "cp310-manylinux_aarch64"
- os: "ubuntu-latest"
- - cibw-only: "cp311-manylinux_aarch64"
- os: "ubuntu-latest"
- - cibw-only: "cp312-manylinux_aarch64"
- os: "ubuntu-latest"
+ - { os: macos-13, cibw-only: cp311-macosx_x86_64 }
+ - { os: macos-13, cibw-only: cp312-macosx_x86_64 }
+ - { os: macos-13, cibw-only: cp313-macosx_x86_64 }
+ - { os: macos-14, cibw-only: cp311-macosx_arm64 }
+ - { os: macos-14, cibw-only: cp312-macosx_arm64 }
+ - { os: macos-14, cibw-only: cp313-macosx_arm64 }
+ - { os: ubuntu-24.04, cibw-only: cp311-manylinux_x86_64 }
+ - { os: ubuntu-24.04, cibw-only: cp312-manylinux_x86_64 }
+ - { os: ubuntu-24.04, cibw-only: cp313-manylinux_x86_64 }
+ - { os: ubuntu-24.04-arm, cibw-only: cp311-manylinux_aarch64 }
+ - { os: ubuntu-24.04-arm, cibw-only: cp312-manylinux_aarch64 }
+ - { os: ubuntu-24.04-arm, cibw-only: cp313-manylinux_aarch64 }
+ - { os: windows-2022, cibw-only: cp311-win_amd64 }
+ - { os: windows-2022, cibw-only: cp312-win_amd64 }
+ - { os: windows-2022, cibw-only: cp313-win_amd64 }
+
steps:
- uses: actions/checkout@v4
- - name: Use Python 3.12
- uses: actions/setup-python@v5
- with:
- python-version: '3.12'
-
- # Needed to build aarch64 wheels
- - name: Set up QEMU
- if: runner.os == 'Linux'
- uses: docker/setup-qemu-action@v3
+ - uses: ./.github/actions/build-bdist/
with:
- platforms: all
-
- - name: Print build identifiers
- run: |
- python -m pip install cibuildwheel
- python -m cibuildwheel --only ${{ matrix.cibw-only }} --print-build-identifiers
+ cibw-only: ${{ matrix.cibw-only }}
+ upload-name: build-wheels-${{ matrix.cibw-only }}
- - name: Build wheels
- if: ${{ startsWith(needs.check-tag.outputs.publish_url, 'http') }}
- uses: pypa/cibuildwheel@v2.21.2
- with:
- only: ${{ matrix.cibw-only }}
-
- - uses: actions/upload-artifact@v4
- with:
- name: build-wheels-${{ matrix.os }}-${{ matrix.cibw-only }}
- path: ${{ github.workspace }}/wheelhouse/*.whl
- if-no-files-found: ignore
-
- build-wheels:
- name: Build wheels on ${{ matrix.cibw-only }}
- needs: check-tag
+ test-landlab:
+ name: Run the tests
+ needs: build-wheels
runs-on: ${{ matrix.os }}
+
strategy:
fail-fast: false
matrix:
- include:
- # Linux x86_64
- - cibw-only: "cp310-manylinux_x86_64"
- os: "ubuntu-latest"
- - cibw-only: "cp311-manylinux_x86_64"
- os: "ubuntu-latest"
- - cibw-only: "cp312-manylinux_x86_64"
- os: "ubuntu-latest"
-
- # Mac x86_64
- - cibw-only: "cp310-macosx_x86_64"
- os: "macos-13"
- - cibw-only: "cp311-macosx_x86_64"
- os: "macos-13"
- - cibw-only: "cp312-macosx_x86_64"
- os: "macos-13"
-
- # Mac arm64
- - cibw-only: "cp310-macosx_arm64"
- os: "macos-14"
- - cibw-only: "cp311-macosx_arm64"
- os: "macos-14"
- - cibw-only: "cp312-macosx_arm64"
- os: "macos-14"
-
- # Windows 64bit
- - cibw-only: "cp310-win_amd64"
- os: "windows-latest"
- - cibw-only: "cp311-win_amd64"
- os: "windows-latest"
- - cibw-only: "cp312-win_amd64"
- os: "windows-latest"
+ os: [ubuntu-latest, ubuntu-24.04-arm, macos-13, macos-latest, windows-latest]
+ python-version: ["3.11", "3.12", "3.13"]
+ pytest-marker: ["slow", "not slow"]
steps:
- uses: actions/checkout@v4
- - name: Use Python 3.12
- uses: actions/setup-python@v5
+ - uses: ./.github/actions/run-tests/
with:
- python-version: '3.12'
+ python-version: ${{ matrix.python-version }}
+ nox-session: "test"
+ pytest-addopts: "-m '${{ matrix.pytest-marker }} and not richdem'"
+ codecov-token: ${{ secrets.CODECOV_TOKEN }}
- - name: Print build identifiers
- run: |
- python -m pip install cibuildwheel
- python -m cibuildwheel --only ${{ matrix.cibw-only }} --print-build-identifiers
+ test-notebooks:
+ name: Run the notebooks
+ needs: build-wheels
+ runs-on: ${{ matrix.os }}
- - name: Install openmp
- if: runner.os == 'macOS'
- run: |
- curl -O https://mac.r-project.org/openmp/openmp-13.0.0-darwin21-Release.tar.gz
- sudo tar fvxz openmp-13.0.0-darwin21-Release.tar.gz -C /
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [macos-latest, windows-latest]
+ python-version: ["3.13"]
+ pytest-marker: ["slow", "not slow"]
- - name: Build wheels
- uses: pypa/cibuildwheel@v2.21.2
+ steps:
+ - uses: actions/checkout@v4
+ - uses: ./.github/actions/run-notebooks/
with:
- only: ${{ matrix.cibw-only }}
+ python-version: ${{ matrix.python-version }}
+ nox-session: "test-notebooks"
+ pytest-addopts: "--overwrite -m '${{ matrix.pytest-marker }} and not richdem'"
+ opentopography-api-key: ${{ secrets.OPENTOPOGRAPHY_API_KEY }}
+ upload-name: ${{ matrix.os == 'macos-latest' && format('notebooks-{0}', matrix.pytest-marker) || '' }}
- - uses: actions/upload-artifact@v4
- with:
- name: build-wheels-${{ matrix.os }}-${{ matrix.cibw-only }}
- path: ${{ github.workspace }}/wheelhouse/*.whl
- test-landlab:
+ test-richdem:
needs: build-wheels
- name: Run the tests
+ name: Run the richdem tests
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
- python-version: ["3.10", "3.11", "3.12"]
- pytest-marker: ["slow", "not slow"]
+ python-version: ["3.11", "3.12", "3.13"]
runs-on: ${{ matrix.os }}
@@ -191,44 +149,35 @@ jobs:
miniforge-variant: Miniforge3
miniforge-version: latest
auto-update-conda: true
+ channels: conda-forge,defaults
- uses: actions/download-artifact@v4
name: Download build artifacts
with:
- pattern: "build-*"
+ pattern: "build-wheels-*"
merge-multiple: true
path: ${{ github.workspace }}/dist
- name: Test
env:
- HYPOTHESIS_PROFILE: "ci"
- MPLBACKEND: "Agg"
+ OPENTOPOGRAPHY_API_KEY: ${{ secrets.OPENTOPOGRAPHY_API_KEY }}
+ MPLBACKEND: "module://matplotlib_inline.backend_inline"
+ PYTEST_ADDOPTS: "--overwrite"
run: |
+ pip install matplotlib_inline
pip install nox
- nox --verbose -s test \
+ nox --verbose -s test-richdem \
--force-pythons=${{ matrix.python-version }} \
- -- -m '${{ matrix.pytest-marker }}' --path=dist
+ -- dist/
- - name: Coveralls
- if: ${{ matrix.os == 'ubuntu-latest' }}
- uses: AndreMiras/coveralls-python-action@develop
+ - name: Upload coverage reports to Codecov
+ uses: codecov/codecov-action@v5
with:
- parallel: true
- flag-name: py${{ matrix.python-version }}-${{ matrix.os }}-${{ matrix.pytest-marker }}
- debug: true
+ token: ${{ secrets.CODECOV_TOKEN }}
- test-notebooks:
- needs: build-wheels
- name: Run the notebook tests
-
- strategy:
- fail-fast: false
- matrix:
- os: [macos-latest, windows-latest]
- python-version: ["3.12"]
- pytest-marker: ["slow", "not slow"]
-
- runs-on: ${{ matrix.os }}
+ check-links:
+ needs: check-tag
+ runs-on: ubuntu-latest
defaults:
run:
@@ -236,56 +185,22 @@ jobs:
steps:
- uses: actions/checkout@v4
- - uses: conda-incubator/setup-miniconda@v3
+ - name: Use Python 3.12
+ uses: actions/setup-python@v5
with:
- python-version: ${{ matrix.python-version }}
- miniforge-variant: Miniforge3
- miniforge-version: latest
- auto-update-conda: true
+ python-version: '3.12'
- - uses: actions/download-artifact@v4
- name: Download build artifacts
- with:
- pattern: "build-*"
- merge-multiple: true
- path: ${{ github.workspace }}/dist
+ - name: Install Pandoc
+ run: sudo apt-get update && sudo apt-get install -y pandoc
- - name: Test
- env:
- OPENTOPOGRAPHY_API_KEY: ${{ secrets.OPENTOPOGRAPHY_API_KEY }}
- MPLBACKEND: "module://matplotlib_inline.backend_inline"
- PYTEST_ADDOPTS: "--overwrite"
+ - name: Check documentation links
run: |
- pip install matplotlib_inline
pip install nox
- nox --verbose -s test-notebooks \
- --force-pythons=${{ matrix.python-version }} \
- -- -m '${{ matrix.pytest-marker }}' --path=dist
-
- - name: Find executed notebooks
- run: |
- for f in $(git diff --name-only); do
- mkdir -p executed/$(dirname $f);
- cp $f executed/$(dirname $f);
- done
- ls -R executed/
-
- - name: Upload executed notebooks
- if: ${{ matrix.os == 'macos-latest' }}
- uses: actions/upload-artifact@v4
- with:
- name: notebooks-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.pytest-marker }}
- path: executed/
- overwrite: true
+ nox -s docs-check-links
docs:
needs: test-notebooks
- strategy:
- matrix:
- os: [macos-latest]
- python-version: ["3.12"]
-
- runs-on: ${{ matrix.os }}
+ runs-on: ubuntu-latest
defaults:
run:
@@ -293,12 +208,10 @@ jobs:
steps:
- uses: actions/checkout@v4
- - uses: conda-incubator/setup-miniconda@v3
+ - name: Use Python 3.13
+ uses: actions/setup-python@v5
with:
- python-version: ${{ matrix.python-version }}
- miniforge-variant: Miniforge3
- miniforge-version: latest
- auto-update-conda: true
+ python-version: '3.13'
- uses: actions/download-artifact@v4
name: Download build artifact
@@ -309,45 +222,44 @@ jobs:
- name: Display structure of downloaded files
run: ls -R
- - name: install and check pandoc
- run: |
- conda install pandoc -c conda-forge
- pandoc --help
- pandoc --version
+ - name: Install Pandoc
+ run: sudo apt-get update && sudo apt-get install -y pandoc
- name: Build documentation
run: |
pip install nox
- pip install -r requirements/docs.txt
- nox -s docs-build --no-venv
-
- - name: Create zip
- run: zip -r docs.zip build/html
+ nox -s docs-build
- - name: Upload docs
- uses: actions/upload-artifact@v4
+ - name: Upload static files as artifact
+ id: deployment
+ uses: actions/upload-pages-artifact@v3
with:
- name: docs-${{ matrix.os }}-${{ matrix.python-version }}
- path: docs.zip
-
- coveralls_finish:
- needs: test-landlab
+ path: build/html/
+
+ deploy-docs:
+ if: github.ref == 'refs/heads/master'
+ needs: docs
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pages: write
+ id-token: write
steps:
- - name: Coveralls Finished
- uses: AndreMiras/coveralls-python-action@develop
- with:
- parallel-finished: true
- debug: true
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
publish:
needs:
- check-tag
- test-landlab
- test-notebooks
+ - test-richdem
- build-sdist
- - build-aarch64
name: "Publish to PyPI/TestPyPI"
runs-on: ubuntu-latest
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ff2c496c2d..6954ec49b4 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/MarcoGorelli/cython-lint
- rev: v0.16.2
+ rev: v0.16.6
hooks:
- id: cython-lint
- id: double-quote-cython-strings
@@ -20,7 +20,7 @@ repos:
language: pygrep
- repo: https://github.com/psf/black
- rev: 24.8.0
+ rev: 25.1.0
hooks:
- id: black
name: black
@@ -47,7 +47,7 @@ repos:
hooks:
- id: blackdoc
description: "Black for doctests"
- additional_dependencies: ["black==24.8.0"]
+ additional_dependencies: ["black==25.1.0"]
- id: blackdoc-autoupdate-black
@@ -61,16 +61,16 @@ repos:
- flake8-simplify
- repo: https://github.com/mcflugen/heartfelt-hooks
- rev: v1.3.3
+ rev: v0.3.3
hooks:
- id: check-whitespace
- id: check-heading-levels
- repo: https://github.com/nbQA-dev/nbQA
- rev: 1.8.7
+ rev: 1.9.1
hooks:
- id: nbqa-pyupgrade
- args: ["--py310-plus"]
+ args: ["--py311-plus"]
- id: nbqa-isort
- id: nbqa-flake8
args: ["--extend-ignore=E402"]
@@ -80,20 +80,20 @@ repos:
)
- repo: https://github.com/kynan/nbstripout
- rev: 0.7.1
+ rev: 0.8.1
hooks:
- id: nbstripout
description: Strip output from jupyter notebooks
args: [--drop-empty-cells]
- repo: https://github.com/asottile/pyupgrade
- rev: v3.17.0
+ rev: v3.19.1
hooks:
- id: pyupgrade
- args: [--py310-plus]
+ args: [--py311-plus]
- repo: https://github.com/PyCQA/isort
- rev: 5.13.2
+ rev: 6.0.0
hooks:
- id: isort
name: isort (python)
@@ -105,7 +105,7 @@ repos:
types: [cython]
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.6.0
+ rev: v5.0.0
hooks:
- id: check-builtin-literals
- id: check-added-large-files
@@ -116,6 +116,11 @@ repos:
- id: end-of-file-fixer
- id: forbid-new-submodules
- id: mixed-line-ending
+ args: [--fix=lf]
+ exclude: \.bat$
+ - id: mixed-line-ending
+ args: [--fix=crlf]
+ files: \.bat$
- id: trailing-whitespace
- id: file-contents-sorter
files: |
diff --git a/AUTHORS.md b/AUTHORS.md
index 731f06e816..7c39333c19 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -42,7 +42,7 @@
- [Annie Thompson](https://github.com/anweiii)
- [Giuseppecipolla95](https://github.com/Giuseppecipolla95)
- [Dylan Ward](https://github.com/ddoubleprime)
-- [Amanda Manaster](https://github.com/amanaster2)
+- [Amanda Alvis](https://github.com/adalvis)
- [Mark Piper](https://github.com/mdpiper)
- [Jay Hariharan](https://github.com/elbeejay)
- [Shelby Ahrendt](https://github.com/shelbyahrendt)
diff --git a/CHANGES.md b/CHANGES.md
index b08ed5d7a9..1225af7adc 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -437,7 +437,7 @@
### 📖 Documentation Enhancements
- Added missing documentation files for `BedrockLandslider` and `SpaceLargeScaleEroder`. ([#1373](https://github.com/landlab/landlab/issues/1373))
-- Set up *\[towncrier\](https://towncrier.readthedocs.io/en/actual-freaking-docs/)*
+- Set up *\[towncrier\](https://towncrier.readthedocs.io/)*
to update and manage the *landlab* changelog. New fragments are placed in the
`news/` folder. ([#1396](https://github.com/landlab/landlab/issues/1396))
diff --git a/CITATION.cff b/CITATION.cff
index 4dd8e66412..b9d856526a 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -104,7 +104,7 @@ identifiers:
value: 10.5281/zenodo.595872
description: The concept DOI for the collection containing all versions of landlab.
repository-code: "https://github.com/landlab/landlab"
-url: "https://landlab.readthedocs.io"
+url: "https://landlab.csdms.io"
date-released: "2020-04-29"
keywords:
- "bmi"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d581f65b59..316607983c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -91,7 +91,7 @@ Changes to landlab should be submitted as
If you would like to create a new component, we a few conventions that we would
like you to follow.
-Please visit [this part](https://landlab.readthedocs.io/en/master/development/index.html)
+Please visit [this part](https://landlab.csdms.io/install/)
of the main Landlab documentation page to read about developer installation,
guidelines to contributing code, and our software development practices.
diff --git a/README.md b/README.md
index 82bd202edc..6b07020f4d 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@
[lint-badge]: https://github.com/landlab/landlab/actions/workflows/lint.yml/badge.svg
[lint-link]: https://github.com/landlab/landlab/actions/workflows/lint.yml
[rtd-badge]:https://readthedocs.org/projects/landlab/badge/?version=latest
-[rtd-link]: https://landlab.readthedocs.org
+[rtd-link]: https://landlab.csdms.io
[test-badge]: https://github.com/landlab/landlab/actions/workflows/test.yml/badge.svg
[test-link]: https://github.com/landlab/landlab/actions/workflows/test.yml
@@ -51,7 +51,7 @@ at CSDMS to learn more.
______________________________________________________________________
-[Read the documentation on ReadTheDocs!](https://landlab.readthedocs.io/)
+[Read the documentation on ReadTheDocs!](https://landlab.csdms.io/)
______________________________________________________________________
@@ -129,9 +129,9 @@ During workshops and clinics, we sometimes use the
-[citation guidelines]: https://landlab.readthedocs.io/en/master/citing.html
+[citation guidelines]: https://landlab.csdms.io/about/citing.html
[earthscapehub]: https://csdms.colorado.edu/wiki/JupyterHub
[explore the notebooks click here]: https://mybinder.org/v2/gh/landlab/landlab/master?filepath=notebooks/welcome.ipynb
-[install landlab from source]: https://landlab.readthedocs.io/en/master/install/developer_install.html
-[installation instructions]: https://landlab.readthedocs.io/en/master/installation.html
+[install landlab from source]: https://landlab.csdms.io/install/
+[installation instructions]: https://landlab.csdms.io/installation.html
[teaching notebooks click here]: https://mybinder.org/v2/gh/landlab/landlab/master?filepath=notebooks/teaching/welcome_teaching.ipynb
diff --git a/USEDBY.md b/USEDBY.md
index bb79502c00..7d42be06ff 100644
--- a/USEDBY.md
+++ b/USEDBY.md
@@ -8,8 +8,27 @@ Bower, S. J., Shobe, C. M., Maxwell, A. E., & Campforts, B. (2024). **The uncert
Chen, H., Wang, X., Yu, Y., Lu, H., & Van Balen, R. (2024). **Past anthropogenic land use change caused a regime shift of the fluvial response to Holocene climate change in the Chinese Loess Plateau.** *Earth Surface Dynamics,* 12(1), 163-180.
+Chen, H., Wang, X., Lu, H., & Van Balen, R. (2024). **The impacts of climate change, early agriculture and internal fluvial dynamics on paleo-flooding episodes in Central China.** *Science of The Total Environment,* 954, 176431.
+
+Chrapkiewicz, K., Lipp, A. G., Barron, L. P., Barnes, R., & Roberts, G. G. (2024). **Apportioning sources of chemicals of emerging concern along an urban river with inverse modelling.** *Science of The Total Environment,* 933, 172827.
+
Gan, T., Tucker, G. E., Hutton, E. W., Piper, M. D., Overeem, I., Kettner, A. J., Campforts, B., Moriarty, J.M., Undzis, B., Pierce, E. and McCready, L., (2024). **CSDMS Data Components: data–model integration tools for Earth surface processes modeling**. *Geoscientific Model Development,* 17(5), 2165-2185, [DOI](https://doi.org/10.5194/gmd-17-2165-2024).
+Gasparini, N. M., Forte, A. M., & Barnhart, K. R. (2024). **Numerically simulated time to steady state is not a reliable measure of landscape response time.** *Earth Surface Dynamics,* 12(6), 1227-1242.
+
+Guryan, G., Johnson, J., & Gasparini, N. (2024). **Sediment cover modulates landscape erosion patterns and channel steepness in layered rocks: Insights from the SPACE model.** *Journal of Geophysical Research: Earth Surface,* 129(7), e2023JF007509.
+
+Keck, J., Istanbulluoglu, E., Campforts, B., Tucker, G., and Horner-Devine, A. (2024) **A landslide runout model for sediment transport, landscape evolution, and hazard assessment applications**. *Earth Surface Dynamics,* [DOI](https://doi.org/10.5194/esurf-12-1165-2024).
+
+
+Lee, C. H., Seong, Y. B., Weber, J., Ha, S., Kim, D. E., & Yu, B. Y. (2024). **Topographic metrics for unveiling fault segmentation and tectono-geomorphic evolution with insights into the impact of inherited topography, Ulsan Fault Zone, South Korea.** *Earth Surface Dynamics,* 12(5), 1091-1120.
+
+Litwin, D. G., Tucker, G. E., Barnhart, K. R., & Harman, C. J. (2024). **Catchment coevolution and the geomorphic origins of variable source area hydrology.** *Water Resources Research,* 60(6), e2023WR034647.
+
+Lu, X., Lai, J., Wang, L., Ji, J., & Zhong, D. (2024). **Numerical modelling of coupled climate, tectonics, and surface processes on the eastern Himalayan syntaxis.** *Earth-Science Reviews,* 104964.
+
+Lu, X., Wang, L., Ji, J., & Chen, Z. (2024). **Investigating the influence of climate on the evolution of fold-and-thrust belts in Chinese Tianshan: A 2D doubly vergent numerical model approach.** *Journal of Asian Earth Sciences,* 276, 106344.
+
Mohr, C. H., Dietze, M., Tolorza, V., Gonzalez, E., Sotomayor, B., Iroume, A., Mohr, C.H., Dietze, M., Tolorza, V., Gonzalez, E., Sotomayor, B., Iroume, A., Gilfert, S., and Tautz, F. (2024). **Ideas and perspectives: Sensing energy and matter fluxes in a biota-dominated Patagonian landscape through environmental seismology–introducing the Pumalín Critical Zone Observatory.** *Biogeosciences,* 21(6), 1583-1599.
Rosier, I., Diels, J., Somers, B., & Van Orshoven, J. (2024). **Maximising runoff retention by vegetated landscape elements positioned through spatial optimisation.** *Landscape and Urban Planning,* 243, 104968.
@@ -22,6 +41,8 @@ Walker, S. J., Wilkinson, S. N., & Hairsine, P. B. (2024). **Advancing gully top
Wang, Y. (2024) **Identifying geomorphic domains using hierarchically clustered drainage area‐slope scaling.** *Earth Surface Processes and Landforms,* [DOI](https://doi.org/10.1002/esp.5796).
+Wu, H., Wang, X., He, C., Zhang, D., Zhang, H., Li, Z., ... & Lu, H. (2024). **Tectonic-triggered drainage reorganizations between the two largest tributaries of the Yangtze River, China.** *The Innovation Geoscience,* 100115-1.
+
### 2023
Cardenas, B. T., & Stacey, K. (2023). **Landforms Associated With the Aspect-Controlled Exhumation of Crater-Filling Alluvial Strata on Mars.** Geophysical Research Letters, 50(15), e2023GL103618.
@@ -38,6 +59,8 @@ Raistrick, A., Lipson, L., Ma, Z., Mei, L., Wang, M., Zuo, Y., Kayan, K., Wen, H
Rosier, I., Diels, J., Somers, B., & Van Orshoven, J. (2023). **The impact of vegetated landscape elements on runoff in a small agricultural watershed: A modelling study.** *Journal of Hydrology,* 129144, [DOI](https://doi.org/10.1016/j.jhydrol.2023.129144).
+Sharma, H., & Ehlers, T. A. (2023). **Effects of seasonal variations in vegetation and precipitation on catchment erosion rates along a climate and ecological gradient: insights from numerical modeling.** *Earth Surface Dynamics,* 11(6), 1161-1181.
+
Shmilovitz, Y., Marra, F., Enzel, Y., Morin, E., Armon, M., Matmon, A., ... & Haviv, I. (2023). **The impact of extreme rainstorms on escarpment morphology in arid areas: Insights from the central Negev Desert.** *Journal of Geophysical Research: Earth Surface,* e2023JF007093.
Wang, Y., Chen, S. M., Xiong, L. Y., & Li, S. J. (2023). **Paleotopography-constrained numerical modeling of loess landform evolution.** *Geomorphology,* 433, 108725.
@@ -116,7 +139,7 @@ Barnhart, K. R., Tucker, G. E., Doty, S., Shobe, C. M., Glade, R. C., Rossi, M.
Carriere, A., Le Bouteiller, C., Tucker, G.E., Klotz, S., and Naaim, M. (2020) **Impact of vegetation on erosion: Insights from the calibration and test of a landscape evolution model in alpine badland catchments.** *Earth Surface Processes and Landforms*. [DOI](https://doi.org/10.1002/esp.4741).
-Evans, M. J., Scheele, B. C., Westgate, M. J., Yebra, M., Newport, J. S., & Manning, A. D. (2020). Beyond the pond: Terrestrial habitat use by frogs in a changing climate. Biological Conservation, 249, 108712., [DOI](https://doi.org/10.1016/j.biocon.2020.108712).
+Evans, M. J., Scheele, B. C., Westgate, M. J., Yebra, M., Newport, J. S., & Manning, A. D. (2020). **Beyond the pond: Terrestrial habitat use by frogs in a changing climate.** *Biological Conservation,* 249, 108712., [DOI](https://doi.org/10.1016/j.biocon.2020.108712).
Lai, J., & Anders, A. M. (2020). **Tectonic controls on rates and spatial patterns of glacial erosion through geothermal heat flux.** *Earth and Planetary Science Letters,* 543, 116348, [DOI](https://doi.org/10.1016/j.epsl.2020.116348).
@@ -152,9 +175,11 @@ Phuong J., C. Bandaragoda, E. Istanbulluoglu, C. Beveridge, R. Strauch, L. Setia
Reitman, N.G., Mueller, K.J., Tucker, G.E., Gold, R.D., Briggs, R.D., and Barnhart, K.R. (2019) **Landscape Evolution Models Demonstrate that Offset Channels are Incomplete Records of Strike-Slip Fault Displacement.** *Journal of Geophysical Research: Solid Earth*, 124, [DOI](https://doi.org/10.1029/2019JB018596).
-Sharman, G. R., Sylvester, Z., & Covault, J. A. (2019). **Conversion of tectonic and climatic forcings into records of sediment supply and provenance.** *Scientific Reports*, 9(1), 4115, [DOI](https://doi.org/10.1038/s41598-019-39754-6).
+Sharman, G. R., Sylvester, Z., & Covault, J. A. (2019).
+**Conversion of tectonic and climatic forcings into records of sediment supply and provenance.** *Scientific Reports*, 9(1), 4115, [DOI](https://doi.org/10.1038/s41598-019-39754-6).
-Zebari, M., Grützner, C., Navabpour, P., & Ustaszewski, K. (2019). **Relative timing of uplift along the Zagros Mountain Front Flexure (Kurdistan Region of Iraq): Constrained by geomorphic indices and landscape evolution modeling.** *Solid Earth*, 10(3), 663-682
+Zebari, M., Grützner, C., Navabpour, P., & Ustaszewski, K. (2019).
+**Relative timing of uplift along the Zagros Mountain Front Flexure (Kurdistan Region of Iraq): Constrained by geomorphic indices and landscape evolution modeling.** *Solid Earth*, 10(3), 663-682
[DOI](https://doi.org/10.5194/se-10-663-2019).
### 2018
@@ -183,8 +208,6 @@ Rasmussen, C., Richardson, P., Swetnam, T.L., and Tucker, G.E. (2018)
**Which way do you lean? Using slope aspect variations to understand
Critical Zone processes and feedbacks.** *Earth Surface Processes and
Landforms*, [DOI](https://doi.org/10.1002/esp.4306).
-[abstract](https://onlinelibrary.wiley.com/doi/abs/10.1002/esp.4306)
-[paper](https://onlinelibrary.wiley.com/doi/epdf/10.1002/esp.4306)
Schmid, M., Ehlers, T.A., Werner, C., Hickler, T., and Fuentes-Espoz, J.
P. (2018). **Effect of changing vegetation and precipitation on
@@ -225,7 +248,6 @@ Harbert, S.A., and Owen, L.A. (2017) **Off-fault deformation rate along
the southern San Andreas fault at Mecca Hills, southern California,
inferred from landscape modeling of curved drainages.** *Geology*, v.
46(1), p. 59-62, [DOI](https://doi.org/10.1130/G39820.1).
-[abstract and paper](https://pubs.geoscienceworld.org/gsa/geology/article-abstract/46/1/59/522872/Off-fault-deformation-rate-along-the-southern-San?redirectedFrom=fulltext)
Hobley, D.E.J., Adams, J.M., Nudurupati, S.S., Hutton, E.W.H, Gasparini,
N.M., Istanbulluoglu, E., and Tucker, G.E., **Creative computing with
diff --git a/docs/index.toml b/docs/index.toml
index b50a574c9f..a7f5ffbaf5 100644
--- a/docs/index.toml
+++ b/docs/index.toml
@@ -3894,6 +3894,43 @@ mapping = 'node'
optional = false
units = 'm'
+[components.river_flow_dynamics]
+name = 'landlab.components.river_flow_dynamics.river_flow_dynamics.river_flow_dynamics'
+unit_agnostic = false
+summary = 'Simulate surface fluid flow based on Casulli and Cheng (1992).'
+
+[components.river_flow_dynamics.info.surface_water__depth]
+doc = 'Depth of water on the surface'
+dtype = 'float64'
+intent = 'inout'
+mapping = 'node'
+optional = false
+units = 'm'
+
+[components.river_flow_dynamics.info.surface_water__elevation]
+doc = 'Water surface elevation at time N'
+dtype = 'float64'
+intent = 'inout'
+mapping = 'node'
+optional = false
+units = 'm'
+
+[components.river_flow_dynamics.info.surface_water__velocity]
+doc = 'Speed of water flow above the surface'
+dtype = 'float64'
+intent = 'inout'
+mapping = 'link'
+optional = false
+units = 'm/s'
+
+[components.river_flow_dynamics.info.topographic__elevation]
+doc = 'Land surface topographic elevation'
+dtype = 'float64'
+intent = 'in'
+mapping = 'node'
+optional = false
+units = 'm'
+
# Generated using `landlab index fields`
[fields]
@@ -5083,6 +5120,7 @@ used_by = [
'landlab.components.overland_flow.generate_overland_flow_Bates.OverlandFlowBates',
'landlab.components.overland_flow.generate_overland_flow_deAlmeida.OverlandFlow',
'landlab.components.overland_flow.kinematic_wave_rengers.KinematicWaveRengers',
+ 'landlab.components.river_flow_dynamics.river_flow_dynamics.river_flow_dynamics',
'landlab.components.soil_moisture.infiltrate_soil_green_ampt.SoilInfiltrationGreenAmpt',
]
provided_by = [
@@ -5093,6 +5131,7 @@ provided_by = [
'landlab.components.overland_flow.kinematic_wave_rengers.KinematicWaveRengers',
'landlab.components.overland_flow.linear_diffusion_overland_flow_router.LinearDiffusionOverlandFlowRouter',
'landlab.components.potentiality_flowrouting.route_flow_by_boundary.PotentialityFlowRouter',
+ 'landlab.components.river_flow_dynamics.river_flow_dynamics.river_flow_dynamics',
'landlab.components.soil_moisture.infiltrate_soil_green_ampt.SoilInfiltrationGreenAmpt',
]
@@ -5133,6 +5172,15 @@ provided_by = [
'landlab.components.flow_accum.lossy_flow_accumulator.LossyFlowAccumulator',
]
+[fields.surface_water__elevation]
+desc = 'Water surface elevation at time N'
+used_by = [
+ 'landlab.components.river_flow_dynamics.river_flow_dynamics.river_flow_dynamics',
+]
+provided_by = [
+ 'landlab.components.river_flow_dynamics.river_flow_dynamics.river_flow_dynamics',
+]
+
[fields.surface_water__specific_discharge]
desc = 'rate of seepage to surface'
used_by = []
@@ -5149,9 +5197,12 @@ provided_by = []
[fields.surface_water__velocity]
desc = 'Speed of water flow above the surface'
-used_by = []
+used_by = [
+ 'landlab.components.river_flow_dynamics.river_flow_dynamics.river_flow_dynamics',
+]
provided_by = [
'landlab.components.overland_flow.kinematic_wave_rengers.KinematicWaveRengers',
+ 'landlab.components.river_flow_dynamics.river_flow_dynamics.river_flow_dynamics',
]
[fields.surface_water_inflow__discharge]
@@ -5219,6 +5270,7 @@ used_by = [
'landlab.components.potentiality_flowrouting.route_flow_by_boundary.PotentialityFlowRouter',
'landlab.components.priority_flood_flow_router.priority_flood_flow_router.PriorityFloodFlowRouter',
'landlab.components.radiation.radiation.Radiation',
+ 'landlab.components.river_flow_dynamics.river_flow_dynamics.river_flow_dynamics',
'landlab.components.sink_fill.fill_sinks.SinkFiller',
'landlab.components.sink_fill.sink_fill_barnes.SinkFillerBarnes',
'landlab.components.space.space.Space',
diff --git a/docs/requirements.in b/docs/requirements.in
index 47fa7f647d..a94267f747 100644
--- a/docs/requirements.in
+++ b/docs/requirements.in
@@ -3,11 +3,10 @@ ipython
myst-parser
nbsphinx
numpy
-pandoc
sphinx-copybutton
sphinx-inline-tabs
sphinx-jinja
sphinx>=4
+sphinx_design
sphinxcontrib.towncrier
-tomli
towncrier
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 7a057f8bec..4724a85692 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -2,10 +2,10 @@
import pathlib
import re
import sys
+import tomllib
from datetime import date
import packaging
-import tomli
def get_version_from_file(path):
@@ -38,6 +38,7 @@ def get_version_from_file(path):
"sphinx.ext.napoleon",
"sphinx.ext.autosummary",
"sphinx_copybutton",
+ "sphinx_design",
"sphinx_inline_tabs",
"sphinxcontrib.towncrier",
"sphinx_jinja",
@@ -52,19 +53,7 @@ def get_version_from_file(path):
# The encoding of source files.
# source_encoding = 'utf-8-sig'
-# Regex for links that we know work in browser, but do not work in sphinx/CI
-# (BE VERY CAREFUL ADDING LINKS TO THIS LIST)
-if os.getenv("GITHUB_ACTIONS"):
- linkcheck_ignore = [
- # Added by KRB Dec 2019, at this point two links match this pattern
- r"https://pubs.geoscienceworld.org/gsa/geology.*",
- r"https://doi.org/10.1130/*", # Added by KRB Jan 2019. Four links match this pattern
- r"https://dx.doi.org/10.1029/2011jf002181", # Added by EWHH April 2020
- r"https://doi.org/10.1029/2019JB018596", # Added by EWHH April 2020
- r"https://doi.org/10.3133/pp294B", # Added by EWHH September 2021
- # r"https://yaml.org/start.html", # Added by EWHH September 2021
- ]
- linkcheck_retries = 5
+linkcheck_retries = 5
master_doc = "index"
@@ -72,8 +61,8 @@ def get_version_from_file(path):
copyright = str(date.today().year) + ", The Landlab Team"
v = get_version_from_file(version_file)
-version = f"{v.major}.{v.minor}"
-release = v.public
+version = "master"
+release = f"{v.major}.{v.minor}"
language = "en"
@@ -127,7 +116,6 @@ def get_version_from_file(path):
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {
- "announcement": "Landlab 2.9 released!",
"source_repository": "https://github.com/landlab/landlab/",
"source_branch": "master",
"source_directory": "docs/source",
@@ -158,6 +146,13 @@ def get_version_from_file(path):
],
}
+if "READTHEDOCS" in os.environ:
+ html_theme_options["announcement"] = (
+ "This documentation is hosted on Read the Docs only for testing. Please use"
+ " the main documentation"
+ " instead."
+ )
+
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
@@ -250,10 +245,11 @@ def get_version_from_file(path):
"numpy": ("https://numpy.org/doc/stable/", None),
"scipy": ("https://docs.scipy.org/doc/scipy/", None),
"xarray": ("https://docs.xarray.dev/en/stable/", None),
+ "matplotlib": ("https://matplotlib.org/stable/", None),
}
with open("../index.toml", "rb") as fp:
- cats = tomli.load(fp)
+ cats = tomllib.load(fp)
cats["grids"].pop("ModelGrid")
jinja_contexts = {"llcats": cats}
@@ -311,13 +307,13 @@ def get_version_from_file(path):
# This is processed by Jinja2 and inserted before each notebook
nbsphinx_prolog = """
-{% set docname = 'notebooks/' + env.doc2path(env.docname, base=None) %}
+{% set docname = 'docs/source/' + env.doc2path(env.docname, base=None) | string() %}
.. note::
This page was generated from a jupyter notebook_.
-.. _notebook: https://github.com/landlab/landlab/blob/{{ env.config.release|e }}/{{ docname|e }}
+.. _notebook: https://github.com/landlab/landlab/blob/{{ env.config.version|e }}/{{ docname|e }}
"""
nbsphinx_epilog = """
diff --git a/docs/source/development/contribution/develop_a_component.md b/docs/source/development/contribution/develop_a_component.md
index d5c9f52f59..212a683648 100644
--- a/docs/source/development/contribution/develop_a_component.md
+++ b/docs/source/development/contribution/develop_a_component.md
@@ -35,13 +35,7 @@ have finished reading the documentation, consider making an
[Issue](https://github.com/landlab/landlab/issues/) to ask the
development team for help.
-We recommend that you review the Landlab development practices:
-
-```{toctree}
-:maxdepth: 2
-
-../practices/index
-```
+We recommend that you review the Landlab [development practices](/development/practices/index).
## Files structure
diff --git a/docs/source/development/index.md b/docs/source/development/index.md
index bce19109f9..891b55151d 100644
--- a/docs/source/development/index.md
+++ b/docs/source/development/index.md
@@ -18,10 +18,11 @@ The most important things to remember are to:
## Supported Python Versions
-Python 3.10, 3.11, and 3.12
+*Landlab* supports the [current Python version](https://devguide.python.org/versions/)
+plus the two previous versions.
If you need to introduce a new dependency, that dependency must be compatible
-with Python 3.10+ and be available on Linux, Mac, and Windows.
+with the oldest supported Python version and be available on Linux, Mac, and Windows.
```{toctree}
:hidden: true
diff --git a/docs/source/install/developer_install.md b/docs/source/install/developer_install.md
index 72cc6b8d7a..d5ac92a797 100644
--- a/docs/source/install/developer_install.md
+++ b/docs/source/install/developer_install.md
@@ -51,12 +51,14 @@ mamba install --file=requirements.in -c nodefaults -c conda-forge --override-cha
````
````{tab} conda
+```bash
cd landlab
conda install --file=requirements.in -c nodefaults -c conda-forge --override-channels
```
````
````{tab} pip
+```bash
cd landlab
pip install -r requirements.in
```
@@ -68,7 +70,7 @@ pip install -r requirements.in
you to have a C++ compiler installed. *Linux* will usually already have one,
on *Mac* you can use *XCode*, and on *Windows* you will need to install *MSVC*.
For help on installing *MSVC*, you may want to refer to the *conda-forge* page
-on [compiling code on Windows](https://conda-forge.org/docs/maintainer/knowledge_base.html#notes-on-native-code)
+on [compiling code on Windows](https://conda-forge.org/docs/maintainer/knowledge_base/#particularities-on-windows)
or the [Python wiki page for Windows compilers](https://wiki.python.org/moin/WindowsCompilers).
If you are using *conda*/*mamba*, set up your compilers to build libraries
diff --git a/docs/source/installation.md b/docs/source/installation.md
index cf46df8019..5df48e5228 100644
--- a/docs/source/installation.md
+++ b/docs/source/installation.md
@@ -10,7 +10,7 @@ not necessary, we **highly recommend** you install landlab into its own
In order to use *landlab* you will first need Python. While not
necessary, we recommend using the
-[Anaconda Python distribution](https://www.anaconda.com/distribution/)
+[Anaconda Python distribution](https://www.anaconda.com/download)
as it provides a large number of third-party packages useful for
scientific computing.
diff --git a/docs/source/teaching/welcome_teaching.ipynb b/docs/source/teaching/welcome_teaching.ipynb
index 98c7bbe92a..5745fca644 100644
--- a/docs/source/teaching/welcome_teaching.ipynb
+++ b/docs/source/teaching/welcome_teaching.ipynb
@@ -6,7 +6,7 @@
"source": [
"# Landlab Teaching Notebooks\n",
"\n",
- "Find information about how to use these notebooks in your classroom [on our documentation page](https://landlab.readthedocs.io/en/release/user_guide/teaching_tutorials.html).\n",
+ "Find information about how to use these notebooks in your classroom [on our documentation page](https://landlab.csdms.io/teaching/).\n",
"## Index of Teaching Notebooks\n",
"\n",
"- [Quantifying river channel evolution with Landlab](geomorphology_exercises/channels_streampower_notebooks/stream_power_channels_class_notebook.ipynb)\n",
diff --git a/docs/source/tutorials/agent_based_modeling/groundwater/landlab_mesa_groundwater_pumping.ipynb b/docs/source/tutorials/agent_based_modeling/groundwater/landlab_mesa_groundwater_pumping.ipynb
index 5025bcb64f..80e53fa7ac 100644
--- a/docs/source/tutorials/agent_based_modeling/groundwater/landlab_mesa_groundwater_pumping.ipynb
+++ b/docs/source/tutorials/agent_based_modeling/groundwater/landlab_mesa_groundwater_pumping.ipynb
@@ -36,6 +36,7 @@
"metadata": {},
"outputs": [],
"source": [
+ "import matplotlib.pyplot as plt\n",
"from tqdm.notebook import trange\n",
"\n",
"from landlab import RasterModelGrid\n",
@@ -294,7 +295,8 @@
" \"\"\"An agent who pumps from a well if it's not dry.\"\"\"\n",
"\n",
" def __init__(self, unique_id, model, well_depth=5.0):\n",
- " super().__init__(unique_id, model)\n",
+ " # super().__init__(unique_id, model)\n",
+ " super().__init__(model)\n",
" self.pumping = True\n",
" self.well_depth = well_depth\n",
"\n",
@@ -528,16 +530,9 @@
" print(f\"Total recharge: {np.sum(recharge)}\")\n",
" print(\"\")\n",
"\n",
- " grid.imshow(\"water_table__elevation\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "grid.imshow(\"water_table__elevation\")"
+ " plt.figure()\n",
+ " grid.imshow(\"water_table__elevation\")\n",
+ " plt.show()"
]
},
{
@@ -554,13 +549,6 @@
"\n",
"grid.imshow(too_deep)"
]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This foregoing example is very simple, and leaves out many aspects of the complex problem of water extraction as a \"tragedy of the commons\". But it does illustrate how one can build a model that integrates agent-based dynamics with continuum dynamics by combining Landlab grid-based model code with Mesa ABM code."
- ]
}
],
"metadata": {
@@ -584,7 +572,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.12.5"
+ "version": "3.12.4"
}
},
"nbformat": 4,
diff --git a/docs/source/tutorials/agent_based_modeling/wolf_sheep/wolf_sheep_with_soil_creep.ipynb b/docs/source/tutorials/agent_based_modeling/wolf_sheep/wolf_sheep_with_soil_creep.ipynb
index 653427a80e..3917487ba2 100644
--- a/docs/source/tutorials/agent_based_modeling/wolf_sheep/wolf_sheep_with_soil_creep.ipynb
+++ b/docs/source/tutorials/agent_based_modeling/wolf_sheep/wolf_sheep_with_soil_creep.ipynb
@@ -33,7 +33,9 @@
"outputs": [],
"source": [
"try:\n",
- " from mesa import Model\n",
+ " import mesa\n",
+ "\n",
+ " print(\"Mesa version\", mesa.__version__)\n",
"except ModuleNotFoundError:\n",
" print(\n",
" \"\"\"\n",
@@ -57,7 +59,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "Next, we'll define a Mesa model object, representing the wolf-sheep-grass model, along with an agent object, representing grass patches. Note that this Mesa code in the cell below, which implements the wolf-sheep-grass example, was written by the Mesa development team; the original can be found [here](https://github.com/projectmesa/mesa/tree/main/examples/wolf_sheep)."
+ "Next, we'll import the Mesa example Wolf-Sheep-Grass model from the *examples* collection ([more info here](https://mesa.readthedocs.io/stable/examples/advanced/wolf_sheep.html)."
]
},
{
@@ -66,391 +68,9 @@
"metadata": {},
"outputs": [],
"source": [
- "from collections import defaultdict\n",
- "\n",
- "from mesa import Agent\n",
- "from mesa.datacollection import DataCollector\n",
- "from mesa.space import MultiGrid\n",
- "from mesa.time import RandomActivation\n",
- "\n",
- "\n",
- "class RandomActivationByBreed(RandomActivation):\n",
- " \"\"\"\n",
- " A scheduler which activates each type of agent once per step, in random\n",
- " order, with the order reshuffled every step.\n",
- "\n",
- " This is equivalent to the NetLogo 'ask breed...' and is generally the\n",
- " default behavior for an ABM.\n",
- "\n",
- " Assumes that all agents have a step() method.\n",
- " \"\"\"\n",
- "\n",
- " def __init__(self, model):\n",
- " super().__init__(model)\n",
- " self.agents_by_breed = defaultdict(dict)\n",
- "\n",
- " def add(self, agent):\n",
- " \"\"\"\n",
- " Add an Agent object to the schedule\n",
- "\n",
- " Args:\n",
- " agent: An Agent to be added to the schedule.\n",
- " \"\"\"\n",
- "\n",
- " self._agents[agent.unique_id] = agent\n",
- " agent_class = type(agent)\n",
- " self.agents_by_breed[agent_class][agent.unique_id] = agent\n",
- "\n",
- " def remove(self, agent):\n",
- " \"\"\"\n",
- " Remove all instances of a given agent from the schedule.\n",
- " \"\"\"\n",
- "\n",
- " del self._agents[agent.unique_id]\n",
- "\n",
- " agent_class = type(agent)\n",
- " del self.agents_by_breed[agent_class][agent.unique_id]\n",
- "\n",
- " def step(self, by_breed=True):\n",
- " \"\"\"\n",
- " Executes the step of each agent breed, one at a time, in random order.\n",
- "\n",
- " Args:\n",
- " by_breed: If True, run all agents of a single breed before running\n",
- " the next one.\n",
- " \"\"\"\n",
- " if by_breed:\n",
- " for agent_class in self.agents_by_breed:\n",
- " self.step_breed(agent_class)\n",
- " self.steps += 1\n",
- " self.time += 1\n",
- " else:\n",
- " super().step()\n",
- "\n",
- " def step_breed(self, breed):\n",
- " \"\"\"\n",
- " Shuffle order and run all agents of a given breed.\n",
- "\n",
- " Args:\n",
- " breed: Class object of the breed to run.\n",
- " \"\"\"\n",
- " agent_keys = list(self.agents_by_breed[breed].keys())\n",
- " self.model.random.shuffle(agent_keys)\n",
- " for agent_key in agent_keys:\n",
- " self.agents_by_breed[breed][agent_key].step()\n",
- "\n",
- " def get_breed_count(self, breed_class):\n",
- " \"\"\"\n",
- " Returns the current number of agents of certain breed in the queue.\n",
- " \"\"\"\n",
- " return len(self.agents_by_breed[breed_class].values())\n",
- "\n",
- "\n",
- "class RandomWalker(Agent):\n",
- " \"\"\"\n",
- " Class implementing random walker methods in a generalized manner.\n",
- "\n",
- " Not indended to be used on its own, but to inherit its methods to multiple\n",
- " other agents.\n",
- "\n",
- " \"\"\"\n",
- "\n",
- " grid = None\n",
- " x = None\n",
- " y = None\n",
- " moore = True\n",
- "\n",
- " def __init__(self, unique_id, pos, model, moore=True):\n",
- " \"\"\"\n",
- " grid: The MultiGrid object in which the agent lives.\n",
- " x: The agent's current x coordinate\n",
- " y: The agent's current y coordinate\n",
- " moore: If True, may move in all 8 directions.\n",
- " Otherwise, only up, down, left, right.\n",
- " \"\"\"\n",
- " super().__init__(unique_id, model)\n",
- " self.pos = pos\n",
- " self.moore = moore\n",
- "\n",
- " def random_move(self):\n",
- " \"\"\"\n",
- " Step one cell in any allowable direction.\n",
- " \"\"\"\n",
- " # Pick the next cell from the adjacent cells.\n",
- " next_moves = self.model.grid.get_neighborhood(self.pos, self.moore, True)\n",
- " next_move = self.random.choice(next_moves)\n",
- " # Now move:\n",
- " self.model.grid.move_agent(self, next_move)\n",
- "\n",
- "\n",
- "class Sheep(RandomWalker):\n",
- " \"\"\"\n",
- " A sheep that walks around, reproduces (asexually) and gets eaten.\n",
- "\n",
- " The init is the same as the RandomWalker.\n",
- " \"\"\"\n",
- "\n",
- " energy = None\n",
- "\n",
- " def __init__(self, unique_id, pos, model, moore, energy=None):\n",
- " super().__init__(unique_id, pos, model, moore=moore)\n",
- " self.energy = energy\n",
- "\n",
- " def step(self):\n",
- " \"\"\"\n",
- " A model step. Move, then eat grass and reproduce.\n",
- " \"\"\"\n",
- " self.random_move()\n",
- " living = True\n",
- "\n",
- " if self.model.grass:\n",
- " # Reduce energy\n",
- " self.energy -= 1\n",
- "\n",
- " # If there is grass available, eat it\n",
- " this_cell = self.model.grid.get_cell_list_contents([self.pos])\n",
- " grass_patch = [obj for obj in this_cell if isinstance(obj, GrassPatch)][0]\n",
- " if grass_patch.fully_grown:\n",
- " self.energy += self.model.sheep_gain_from_food\n",
- " grass_patch.fully_grown = False\n",
- "\n",
- " # Death\n",
- " if self.energy < 0:\n",
- " # self.model.grid._remove_agent(self.pos, self)\n",
- " self.model.grid.remove_agent(self)\n",
- " self.model.schedule.remove(self)\n",
- " living = False\n",
- "\n",
- " if living and self.random.random() < self.model.sheep_reproduce:\n",
- " # Create a new sheep:\n",
- " if self.model.grass:\n",
- " self.energy /= 2\n",
- " lamb = Sheep(\n",
- " self.model.next_id(), self.pos, self.model, self.moore, self.energy\n",
- " )\n",
- " self.model.grid.place_agent(lamb, self.pos)\n",
- " self.model.schedule.add(lamb)\n",
- "\n",
- "\n",
- "class Wolf(RandomWalker):\n",
- " \"\"\"\n",
- " A wolf that walks around, reproduces (asexually) and eats sheep.\n",
- " \"\"\"\n",
- "\n",
- " energy = None\n",
- "\n",
- " def __init__(self, unique_id, pos, model, moore, energy=None):\n",
- " super().__init__(unique_id, pos, model, moore=moore)\n",
- " self.energy = energy\n",
- "\n",
- " def step(self):\n",
- " self.random_move()\n",
- " self.energy -= 1\n",
- "\n",
- " # If there are sheep present, eat one\n",
- " x, y = self.pos\n",
- " this_cell = self.model.grid.get_cell_list_contents([self.pos])\n",
- " sheep = [obj for obj in this_cell if isinstance(obj, Sheep)]\n",
- " if len(sheep) > 0:\n",
- " sheep_to_eat = self.random.choice(sheep)\n",
- " self.energy += self.model.wolf_gain_from_food\n",
- "\n",
- " # Kill the sheep\n",
- " # self.model.grid._remove_agent(self.pos, sheep_to_eat)\n",
- " self.model.grid.remove_agent(sheep_to_eat)\n",
- " self.model.schedule.remove(sheep_to_eat)\n",
- "\n",
- " # Death or reproduction\n",
- " if self.energy < 0:\n",
- " # self.model.grid._remove_agent(self.pos, self)\n",
- " self.model.grid.remove_agent(self)\n",
- " self.model.schedule.remove(self)\n",
- " else:\n",
- " if self.random.random() < self.model.wolf_reproduce:\n",
- " # Create a new wolf cub\n",
- " self.energy /= 2\n",
- " cub = Wolf(\n",
- " self.model.next_id(), self.pos, self.model, self.moore, self.energy\n",
- " )\n",
- " self.model.grid.place_agent(cub, cub.pos)\n",
- " self.model.schedule.add(cub)\n",
- "\n",
- "\n",
- "class GrassPatch(Agent):\n",
- " \"\"\"\n",
- " A patch of grass that grows at a fixed rate and it is eaten by sheep\n",
- " \"\"\"\n",
- "\n",
- " def __init__(self, unique_id, pos, model, fully_grown, countdown):\n",
- " \"\"\"\n",
- " Creates a new patch of grass\n",
- "\n",
- " Args:\n",
- " grown: (boolean) Whether the patch of grass is fully grown or not\n",
- " countdown: Time for the patch of grass to be fully grown again\n",
- " \"\"\"\n",
- " super().__init__(unique_id, model)\n",
- " self.fully_grown = fully_grown\n",
- " self.countdown = countdown\n",
- " self.pos = pos\n",
- "\n",
- " def step(self):\n",
- " if not self.fully_grown:\n",
- " if self.countdown <= 0:\n",
- " # Set as fully grown\n",
- " self.fully_grown = True\n",
- " self.countdown = self.model.grass_regrowth_time\n",
- " else:\n",
- " self.countdown -= 1\n",
- "\n",
- "\n",
- "\"\"\"\n",
- "Wolf-Sheep Predation Model\n",
- "================================\n",
- "\n",
- "Replication of the model found in NetLogo:\n",
- " Wilensky, U. (1997). NetLogo Wolf Sheep Predation model.\n",
- " http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation.\n",
- " Center for Connected Learning and Computer-Based Modeling,\n",
- " Northwestern University, Evanston, IL.\n",
- "\"\"\"\n",
- "\n",
- "\n",
- "class WolfSheep(Model):\n",
- " \"\"\"\n",
- " Wolf-Sheep Predation Model\n",
- " \"\"\"\n",
- "\n",
- " height = 20\n",
- " width = 20\n",
- "\n",
- " initial_sheep = 100\n",
- " initial_wolves = 50\n",
- "\n",
- " sheep_reproduce = 0.04\n",
- " wolf_reproduce = 0.05\n",
- "\n",
- " wolf_gain_from_food = 20\n",
- "\n",
- " grass = False\n",
- " grass_regrowth_time = 30\n",
- " sheep_gain_from_food = 4\n",
- "\n",
- " verbose = False # Print-monitoring\n",
- "\n",
- " description = (\n",
- " \"A model for simulating wolf and sheep (predator-prey) ecosystem modelling.\"\n",
- " )\n",
- "\n",
- " def __init__(\n",
- " self,\n",
- " height=20,\n",
- " width=20,\n",
- " initial_sheep=100,\n",
- " initial_wolves=50,\n",
- " sheep_reproduce=0.04,\n",
- " wolf_reproduce=0.05,\n",
- " wolf_gain_from_food=20,\n",
- " grass=False,\n",
- " grass_regrowth_time=30,\n",
- " sheep_gain_from_food=4,\n",
- " ):\n",
- " \"\"\"\n",
- " Create a new Wolf-Sheep model with the given parameters.\n",
- "\n",
- " Args:\n",
- " initial_sheep: Number of sheep to start with\n",
- " initial_wolves: Number of wolves to start with\n",
- " sheep_reproduce: Probability of each sheep reproducing each step\n",
- " wolf_reproduce: Probability of each wolf reproducing each step\n",
- " wolf_gain_from_food: Energy a wolf gains from eating a sheep\n",
- " grass: Whether to have the sheep eat grass for energy\n",
- " grass_regrowth_time: How long it takes for a grass patch to regrow\n",
- " once it is eaten\n",
- " sheep_gain_from_food: Energy sheep gain from grass, if enabled.\n",
- " \"\"\"\n",
- " super().__init__()\n",
- " # Set parameters\n",
- " self.height = height\n",
- " self.width = width\n",
- " self.initial_sheep = initial_sheep\n",
- " self.initial_wolves = initial_wolves\n",
- " self.sheep_reproduce = sheep_reproduce\n",
- " self.wolf_reproduce = wolf_reproduce\n",
- " self.wolf_gain_from_food = wolf_gain_from_food\n",
- " self.grass = grass\n",
- " self.grass_regrowth_time = grass_regrowth_time\n",
- " self.sheep_gain_from_food = sheep_gain_from_food\n",
- "\n",
- " self.schedule = RandomActivationByBreed(self)\n",
- " self.grid = MultiGrid(self.height, self.width, torus=True)\n",
- " self.datacollector = DataCollector(\n",
- " {\n",
- " \"Wolves\": lambda m: m.schedule.get_breed_count(Wolf),\n",
- " \"Sheep\": lambda m: m.schedule.get_breed_count(Sheep),\n",
- " }\n",
- " )\n",
- "\n",
- " # Create sheep:\n",
- " for i in range(self.initial_sheep):\n",
- " x = self.random.randrange(self.width)\n",
- " y = self.random.randrange(self.height)\n",
- " energy = self.random.randrange(2 * self.sheep_gain_from_food)\n",
- " sheep = Sheep(self.next_id(), (x, y), self, True, energy)\n",
- " self.grid.place_agent(sheep, (x, y))\n",
- " self.schedule.add(sheep)\n",
- "\n",
- " # Create wolves\n",
- " for i in range(self.initial_wolves):\n",
- " x = self.random.randrange(self.width)\n",
- " y = self.random.randrange(self.height)\n",
- " energy = self.random.randrange(2 * self.wolf_gain_from_food)\n",
- " wolf = Wolf(self.next_id(), (x, y), self, True, energy)\n",
- " self.grid.place_agent(wolf, (x, y))\n",
- " self.schedule.add(wolf)\n",
- "\n",
- " # Create grass patches\n",
- " if self.grass:\n",
- " for agent, (x, y) in self.grid.coord_iter():\n",
- " fully_grown = self.random.choice([True, False])\n",
- "\n",
- " if fully_grown:\n",
- " countdown = self.grass_regrowth_time\n",
- " else:\n",
- " countdown = self.random.randrange(self.grass_regrowth_time)\n",
- "\n",
- " patch = GrassPatch(self.next_id(), (x, y), self, fully_grown, countdown)\n",
- " self.grid.place_agent(patch, (x, y))\n",
- " self.schedule.add(patch)\n",
- "\n",
- " self.running = True\n",
- " self.datacollector.collect(self)\n",
- "\n",
- " def step(self):\n",
- " self.schedule.step()\n",
- " # collect data\n",
- " self.datacollector.collect(self)\n",
- " if self.verbose:\n",
- " print(\n",
- " [\n",
- " self.schedule.time,\n",
- " self.schedule.get_breed_count(Wolf),\n",
- " self.schedule.get_breed_count(Sheep),\n",
- " ]\n",
- " )\n",
- "\n",
- " def run_model(self, step_count=200):\n",
- " if self.verbose:\n",
- " print(\"Initial number wolves: \", self.schedule.get_breed_count(Wolf))\n",
- " print(\"Initial number sheep: \", self.schedule.get_breed_count(Sheep))\n",
- "\n",
- " for i in range(step_count):\n",
- " self.step()\n",
- "\n",
- " if self.verbose:\n",
- " print(\"\")\n",
- " print(\"Final number wolves: \", self.schedule.get_breed_count(Wolf))\n",
- " print(\"Final number sheep: \", self.schedule.get_breed_count(Sheep))"
+ "from mesa.examples.advanced.wolf_sheep.agents import GrassPatch\n",
+ "from mesa.examples.advanced.wolf_sheep.model import WolfSheep\n",
+ "from mesa.experimental.devs import ABMSimulator"
]
},
{
@@ -466,7 +86,8 @@
"metadata": {},
"outputs": [],
"source": [
- "ws = WolfSheep(grass=True)"
+ "simulator = ABMSimulator()\n",
+ "ws = WolfSheep(simulator=simulator, grass=True)"
]
},
{
@@ -493,8 +114,9 @@
"\n",
"def generate_grass_map(model):\n",
" grass_map = np.zeros((model.grid.width, model.grid.height))\n",
- " for cell in model.grid.coord_iter():\n",
- " cell_content, (x, y) = cell\n",
+ " for cell in model.grid:\n",
+ " (x, y) = cell.coordinate\n",
+ " cell_content = cell.agents\n",
" for agent in cell_content:\n",
" if type(agent) is GrassPatch:\n",
" if agent.fully_grown:\n",
@@ -522,7 +144,9 @@
"metadata": {},
"outputs": [],
"source": [
- "ws.run_model(step_count=25)\n",
+ "for _ in range(25):\n",
+ " ws.step()\n",
+ "\n",
"gm = generate_grass_map(ws)\n",
"plot_grass_map(gm)"
]
@@ -542,8 +166,12 @@
"metadata": {},
"outputs": [],
"source": [
- "ws = WolfSheep(grass=True)\n",
- "ws.run_model(step_count=3)\n",
+ "simulator = ABMSimulator()\n",
+ "ws = WolfSheep(simulator=simulator, grass=True)\n",
+ "\n",
+ "for _ in range(3):\n",
+ " ws.step()\n",
+ "\n",
"gm = generate_grass_map(ws)\n",
"plot_grass_map(gm)"
]
@@ -691,7 +319,14 @@
"metadata": {},
"outputs": [],
"source": [
- "ws = WolfSheep(grass=True)"
+ "simulator = ABMSimulator()\n",
+ "ws = WolfSheep(\n",
+ " simulator=simulator,\n",
+ " initial_sheep=20,\n",
+ " initial_wolves=10,\n",
+ " grass=True,\n",
+ " grass_regrowth_time=15, # give grass a fighting chance...\n",
+ ")"
]
},
{
@@ -700,7 +335,7 @@
"metadata": {},
"outputs": [],
"source": [
- "initial_soil_depth = 0.2\n",
+ "initial_soil_depth = 0.3\n",
"min_depth_for_grass = 0.2\n",
"hstar = 0.2\n",
"fast_creep = 0.1\n",
@@ -761,8 +396,9 @@
"source": [
"def limit_grass_by_soil(wsg_model, soil, min_soil_depth):\n",
" soilmatrix = soil.reshape((wsg_model.width, wsg_model.height))\n",
- " for cell in wsg_model.grid.coord_iter():\n",
- " cell_content, (x, y) = cell\n",
+ " for cell in wsg_model.grid:\n",
+ " (x, y) = cell.coordinate\n",
+ " cell_content = cell.agents\n",
" if soilmatrix[x][y] < min_soil_depth:\n",
" for agent in cell_content:\n",
" if type(agent) is GrassPatch:\n",
@@ -888,7 +524,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.0"
+ "version": "3.12.4"
}
},
"nbformat": 4,
diff --git a/docs/source/tutorials/data_record/DataRecord_tutorial.ipynb b/docs/source/tutorials/data_record/DataRecord_tutorial.ipynb
index 1cda3bfa55..86add3e080 100644
--- a/docs/source/tutorials/data_record/DataRecord_tutorial.ipynb
+++ b/docs/source/tutorials/data_record/DataRecord_tutorial.ipynb
@@ -16,7 +16,7 @@
"## What is DataRecord?\n",
"DataRecord is a data structure that can hold data variables relating to a Landlab model or to items living on the [Landlab grid](../grids/grid_object_demo.ipynb).\n",
"\n",
- "DataRecord is built on [xarray](http://xarray.pydata.org/en/stable/index.html)'s Dataset structure: a multi-dimensional, in memory, array database. Dataset implements the mapping interface with keys given by variable names and values given by DataArray objects for each variable name. DataRecord inherits all the methods and attributes from xarray.Dataset.\n",
+ "DataRecord is built on [xarray](http://xarray.pydata.org/en/stable/)'s Dataset structure: a multi-dimensional, in memory, array database. Dataset implements the mapping interface with keys given by variable names and values given by DataArray objects for each variable name. DataRecord inherits all the methods and attributes from xarray.Dataset.\n",
"\n",
"A DataRecord can have one or both (or none) of the following dimensions:\n",
"- `time`: The simulated time in the model.\n",
diff --git a/docs/source/tutorials/ecohydrology/cellular_automaton_vegetation_DEM/cellular_automaton_vegetation_DEM.ipynb b/docs/source/tutorials/ecohydrology/cellular_automaton_vegetation_DEM/cellular_automaton_vegetation_DEM.ipynb
index b782042e38..e906910a15 100644
--- a/docs/source/tutorials/ecohydrology/cellular_automaton_vegetation_DEM/cellular_automaton_vegetation_DEM.ipynb
+++ b/docs/source/tutorials/ecohydrology/cellular_automaton_vegetation_DEM/cellular_automaton_vegetation_DEM.ipynb
@@ -147,7 +147,7 @@
"- VEG: Vegetation dynamics object simulates net primary productivity and biomass and thus leaf area index at each cell based on inputs of root-zone average soil moisture.\n",
"- vegca: Cellular Automaton plant competition object. This object simulates the spatial dynamics of PFTs. It is run once every year at the end of the growing season. This object is initialized with a random cellular field of PFT. Each year, this object updates the field of PFTs based on probabilistic establishment and mortality rules employed at each cell of the modeled DEM.\n",
"\n",
- "Note: Almost every component in Landlab is coded as a 'class' (to harness the advantages of object oriented programming). An 'object' is the instantiation of the 'class' (for more information, please refer any object oriented programming book). A 'field' refers to a Landlab field (please refer to the [Landlab documentation](https://github.com/landlab/landlab/wiki/Grid#adding-data-to-a-landlab-grid-element-using-fields) to learn more about Landlab fields)."
+ "Note: Almost every component in Landlab is coded as a 'class' (to harness the advantages of object oriented programming). An 'object' is the instantiation of the 'class' (for more information, please refer any object oriented programming book). A 'field' refers to a Landlab field (please refer to the [Landlab documentation](https://landlab.csdms.io/user_guide/grid.html#adding-data-to-a-landlab-grid-element-using-fields) to learn more about Landlab fields)."
]
},
{
diff --git a/docs/source/tutorials/ecohydrology/cellular_automaton_vegetation_flat_surface/cellular_automaton_vegetation_flat_domain.ipynb b/docs/source/tutorials/ecohydrology/cellular_automaton_vegetation_flat_surface/cellular_automaton_vegetation_flat_domain.ipynb
index 41eafe5124..07c138acaa 100644
--- a/docs/source/tutorials/ecohydrology/cellular_automaton_vegetation_flat_surface/cellular_automaton_vegetation_flat_domain.ipynb
+++ b/docs/source/tutorials/ecohydrology/cellular_automaton_vegetation_flat_surface/cellular_automaton_vegetation_flat_domain.ipynb
@@ -145,7 +145,7 @@
"- VEG: Vegetation dynamics object simulates net primary productivity, biomass and leaf area index (LAI) at each cell based on inputs of root-zone average soil moisture.\n",
"- vegca: Cellular Automaton plant competition object is run once every year. This object is initialized with a random cellular field of PFT. Every year, this object updates the cellular field of PFT based on probabilistic establishment and mortality of PFT at each cell.\n",
"\n",
- "Note: Almost every component in landlab is coded as a 'class' (to harness the advantages of objective oriented programming). An 'object' is the instantiation of the 'class' (for more information, please refer any objective oriented programming book). A 'field' refers to a Landlab field (please refer to the [Landlab documentation](https://github.com/landlab/landlab/wiki/Grid#adding-data-to-a-landlab-grid-element-using-fields) to learn more about Landlab fields)."
+ "Note: Almost every component in landlab is coded as a 'class' (to harness the advantages of objective oriented programming). An 'object' is the instantiation of the 'class' (for more information, please refer any objective oriented programming book). A 'field' refers to a Landlab field (please refer to the [Landlab documentation](https://landlab.csdms.io/user_guide/grid.html#adding-data-to-a-landlab-grid-element-using-fields) to learn more about Landlab fields)."
]
},
{
diff --git a/docs/source/tutorials/fault_scarp/landlab-fault-scarp.ipynb b/docs/source/tutorials/fault_scarp/landlab-fault-scarp.ipynb
index 8ca2da006b..139b332793 100644
--- a/docs/source/tutorials/fault_scarp/landlab-fault-scarp.ipynb
+++ b/docs/source/tutorials/fault_scarp/landlab-fault-scarp.ipynb
@@ -568,7 +568,7 @@
"source": [
"And we can use the same code as before to create a diffusion model!\n",
"\n",
- "Landlab supports multiple grid types. You can read more about them [here](https://landlab.readthedocs.io/en/latest/reference/grid/index.html)."
+ "Landlab supports multiple grid types. You can read more about them [here](https://landlab.csdms.io/user_guide/grid.html)."
]
},
{
@@ -592,13 +592,13 @@
"source": [
"## Part 3: Landlab Components\n",
"\n",
- "Finally we will use a Landlab component, called the LinearDiffuser [link to its documentation](https://landlab.readthedocs.io/en/latest/reference/components/diffusion.html).\n",
+ "Finally we will use a Landlab component, called the LinearDiffuser [link to its documentation](https://landlab.csdms.io/generated/api/landlab.components.diffusion.diffusion.html).\n",
"\n",
"Landlab was designed to have many of the utilities like `calc_grad_at_link`, and `calc_flux_divergence_at_node` to help you make your own models. Sometimes, however, you may use such a model over and over and over. Then it is nice to be able to put it in its own python class with a standard interface. \n",
"\n",
"This is what a Landlab Component is. \n",
"\n",
- "There is a whole [tutorial on components](../component_tutorial/component_tutorial.ipynb) and a [page on the User Guide](https://landlab.readthedocs.io/en/latest/user_guide/components.html). For now we will just show you what the prior example looks like if we use the LinearDiffuser. \n",
+ "There is a whole [tutorial on components](../component_tutorial/component_tutorial.ipynb) and a [page on the User Guide](https://landlab.csdms.io/user_guide/components.html). For now we will just show you what the prior example looks like if we use the LinearDiffuser. \n",
"\n",
"First we import it, set up the grid, and uplift our fault block. "
]
diff --git a/docs/source/tutorials/flow_direction_and_accumulation/PriorityFlood_LandscapeEvolutionModel.ipynb b/docs/source/tutorials/flow_direction_and_accumulation/PriorityFlood_LandscapeEvolutionModel.ipynb
index 8b549c0d7f..114e3d30a8 100644
--- a/docs/source/tutorials/flow_direction_and_accumulation/PriorityFlood_LandscapeEvolutionModel.ipynb
+++ b/docs/source/tutorials/flow_direction_and_accumulation/PriorityFlood_LandscapeEvolutionModel.ipynb
@@ -95,6 +95,11 @@
}
],
"metadata": {
+ "execution": {
+ "nbmake": {
+ "markers": "richdem"
+ }
+ },
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
diff --git a/docs/source/tutorials/flow_direction_and_accumulation/PriorityFlood_realDEMs.ipynb b/docs/source/tutorials/flow_direction_and_accumulation/PriorityFlood_realDEMs.ipynb
index eb9e167a6f..c3e8934c04 100644
--- a/docs/source/tutorials/flow_direction_and_accumulation/PriorityFlood_realDEMs.ipynb
+++ b/docs/source/tutorials/flow_direction_and_accumulation/PriorityFlood_realDEMs.ipynb
@@ -364,6 +364,11 @@
}
],
"metadata": {
+ "execution": {
+ "nbmake": {
+ "markers": "richdem"
+ }
+ },
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
diff --git a/docs/source/tutorials/flow_direction_and_accumulation/the_Flow_Director_Accumulator_PriorityFlood.ipynb b/docs/source/tutorials/flow_direction_and_accumulation/the_Flow_Director_Accumulator_PriorityFlood.ipynb
index 11f3edbcab..fb1feef8ef 100644
--- a/docs/source/tutorials/flow_direction_and_accumulation/the_Flow_Director_Accumulator_PriorityFlood.ipynb
+++ b/docs/source/tutorials/flow_direction_and_accumulation/the_Flow_Director_Accumulator_PriorityFlood.ipynb
@@ -436,6 +436,11 @@
}
],
"metadata": {
+ "execution": {
+ "nbmake": {
+ "markers": "richdem"
+ }
+ },
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
diff --git a/docs/source/tutorials/landscape_evolution/hylands/HyLandsTutorial.ipynb b/docs/source/tutorials/landscape_evolution/hylands/HyLandsTutorial.ipynb
index c3060771e1..b1a809dab4 100644
--- a/docs/source/tutorials/landscape_evolution/hylands/HyLandsTutorial.ipynb
+++ b/docs/source/tutorials/landscape_evolution/hylands/HyLandsTutorial.ipynb
@@ -514,7 +514,10 @@
"metadata": {
"execution": {
"nbmake": {
- "markers": "slow"
+ "markers": [
+ "slow",
+ "richdem"
+ ]
}
},
"kernelspec": {
diff --git a/docs/source/tutorials/landscape_evolution/space/SPACE_large_scale_eroder_user_guide_and_examples.ipynb b/docs/source/tutorials/landscape_evolution/space/SPACE_large_scale_eroder_user_guide_and_examples.ipynb
index 06c4e6ebcf..46e8f257d1 100644
--- a/docs/source/tutorials/landscape_evolution/space/SPACE_large_scale_eroder_user_guide_and_examples.ipynb
+++ b/docs/source/tutorials/landscape_evolution/space/SPACE_large_scale_eroder_user_guide_and_examples.ipynb
@@ -216,7 +216,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "In this configuration, the model domain is set to drain water and sediment out of the only open boundary on the grid, the lower-left corner. There are several options for changing boundary conditions in Landlab. See Hobley et al. (2017) or the Landlab [online documentation](https://landlab.readthedocs.io)."
+ "In this configuration, the model domain is set to drain water and sediment out of the only open boundary on the grid, the lower-left corner. There are several options for changing boundary conditions in Landlab. See Hobley et al. (2017) or the Landlab [online documentation](https://landlab.csdms.io)."
]
},
{
@@ -380,6 +380,11 @@
}
],
"metadata": {
+ "execution": {
+ "nbmake": {
+ "markers": "richdem"
+ }
+ },
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
diff --git a/docs/source/tutorials/landscape_evolution/space/SPACE_user_guide_and_examples.ipynb b/docs/source/tutorials/landscape_evolution/space/SPACE_user_guide_and_examples.ipynb
index c7193e42c9..65828bc389 100644
--- a/docs/source/tutorials/landscape_evolution/space/SPACE_user_guide_and_examples.ipynb
+++ b/docs/source/tutorials/landscape_evolution/space/SPACE_user_guide_and_examples.ipynb
@@ -225,7 +225,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "In this configuration, the model domain is set to drain water and sediment out of the only open boundary on the grid, the lower-left corner. There are several options for changing boundary conditions in Landlab. See Hobley et al. (2017) or the Landlab [online documentation](https://landlab.readthedocs.io)."
+ "In this configuration, the model domain is set to drain water and sediment out of the only open boundary on the grid, the lower-left corner. There are several options for changing boundary conditions in Landlab. See Hobley et al. (2017) or the Landlab [online documentation](https://landlab.csdms.io)."
]
},
{
diff --git a/docs/source/tutorials/landscape_evolution/threshold_eroder/threshold_eroder.ipynb b/docs/source/tutorials/landscape_evolution/threshold_eroder/threshold_eroder.ipynb
index 652f7a8359..301a1bcb56 100644
--- a/docs/source/tutorials/landscape_evolution/threshold_eroder/threshold_eroder.ipynb
+++ b/docs/source/tutorials/landscape_evolution/threshold_eroder/threshold_eroder.ipynb
@@ -170,11 +170,16 @@
"id": "7",
"metadata": {},
"source": [
- "### Click here to learn about Landlab tutorials"
+ "### Click here to learn about Landlab tutorials"
]
}
],
"metadata": {
+ "execution": {
+ "nbmake": {
+ "markers": "richdem"
+ }
+ },
"kernelspec": {
"display_name": "CSDMS",
"language": "python",
diff --git a/docs/source/tutorials/lithology/lithology_and_litholayers.ipynb b/docs/source/tutorials/lithology/lithology_and_litholayers.ipynb
index 1fa799ef26..bf14d2788a 100644
--- a/docs/source/tutorials/lithology/lithology_and_litholayers.ipynb
+++ b/docs/source/tutorials/lithology/lithology_and_litholayers.ipynb
@@ -70,7 +70,7 @@
"\n",
"Both the Lithology and LithoLayers components then know the rock type ID of all the material in the 'block of rock' you have specified. This can be used to continuously know the value of specified rock properties at the topographic surface, even as the rock is eroded, uplifted, or new rock is deposited. \n",
"\n",
- "In this tutorial we will first make an example to help build intuition and then do two more complex examples. Most of the functionality of Lithology and LithoLayers is shown in this tutorial, but if you want to read the full component documentation for LithoLayers, it can be found [here](https://landlab.readthedocs.io/en/release/landlab.components.lithology.html). Links to both components documentation can be found at the bottom of the tutorial.\n",
+ "In this tutorial we will first make an example to help build intuition and then do two more complex examples. Most of the functionality of Lithology and LithoLayers is shown in this tutorial, but if you want to read the full component documentation for LithoLayers, it can be found [here](https://landlab.csdms.io/generated/api/landlab.components.lithology.litholayers.html). Links to both components documentation can be found at the bottom of the tutorial.\n",
"\n",
"First, we create a small RasterModelGrid with topography. "
]
@@ -144,7 +144,7 @@
"source": [
"`'K_sp'` is the property that we want to track through the layered rock, `0`, `1`, `2`, `3` are the rock type IDs, and `0.0003` and `0.0001` are the values for `'K_sp'` for the rock types `0` and `1`. \n",
"\n",
- "The rock type IDs are unique identifiers for each type of rock. A particular rock type may have many properties (e.g. `'K_sp'`, `'diffusivity'`, and more). You can either specify all the possible rock types and attributes when you instantiate the LithoLayers component, or you can add new ones with the [`lith.add_rock_type`](https://landlab.readthedocs.io/en/release/landlab.components.lithology.html#landlab.components.lithology.lithology.Lithology.add_rock_type) or [`lith.add_property`](https://landlab.readthedocs.io/en/release/landlab.components.lithology.html#landlab.components.lithology.lithology.Lithology.add_property) built in functions.\n",
+ "The rock type IDs are unique identifiers for each type of rock. A particular rock type may have many properties (e.g. `'K_sp'`, `'diffusivity'`, and more). You can either specify all the possible rock types and attributes when you instantiate the LithoLayers component, or you can add new ones with the [`lith.add_rock_type`](https://landlab.csdms.io/generated/api/landlab.components.lithology.lithology.html#landlab.components.lithology.lithology.Lithology.add_rock_type) or [`lith.add_property`](https://landlab.csdms.io/generated/api/landlab.components.lithology.lithology.html#landlab.components.lithology.lithology.Lithology.add_property) built in functions.\n",
"\n",
"Finally, we define our function. Here we will use a [lambda expression](https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions) to create a small anonymous function. In this case we define a function of `x` and `y` that returns the value `x + (2. * y)`. The LithoLayers component will check that this function is a function of two variables and that when passed two arrays of size number-of-nodes it returns an array of size number-of-nodes.\n",
"\n",
@@ -173,7 +173,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "LithoLayers will make sure that the model grid has at-node grid fields with the layer attribute names. In this case, this means that the model grid will now include a grid field called `'K_sp'` and a field called `'rock_type__id'`. We can plot these with the Landlab [imshow](http://landlab.readthedocs.io/en/release/landlab.plot.html#landlab.plot.imshow.imshow_grid) function. "
+ "LithoLayers will make sure that the model grid has at-node grid fields with the layer attribute names. In this case, this means that the model grid will now include a grid field called `'K_sp'` and a field called `'rock_type__id'`. We can plot these with the Landlab [imshow](https://landlab.csdms.io/generated/api/landlab.plot.imshow.html#landlab.plot.imshow.imshow_grid) function. "
]
},
{
@@ -585,7 +585,7 @@
"\n",
"[xarray](https://xarray.pydata.org/en/stable/) allows us to create a container for our data and label it with information like units, dimensions, short and long names, etc. xarray gives all the tools for dealing with N-dimentional data provided by python packages such as [numpy](http://www.numpy.org), the labeling and named indexing power of the [pandas](https://pandas.pydata.org) package, and the data-model of the [NetCDF file](https://www.unidata.ucar.edu/software/netcdf/).\n",
"\n",
- "This means that we can use xarray to make a \"self-referential\" dataset that contains all of the variables and attributes that describe what each part is and how it was made. In this application, we won't make a fully self-referential dataset, but if you are interested in this, check out the [NetCDF best practices](https://www.unidata.ucar.edu/software/netcdf/docs/BestPractices.html). \n",
+ "This means that we can use xarray to make a \"self-referential\" dataset that contains all of the variables and attributes that describe what each part is and how it was made. In this application, we won't make a fully self-referential dataset, but if you are interested in this, check out the [NetCDF best practices](https://docs.unidata.ucar.edu/nug/current/best_practices.html). \n",
"\n",
"Important for our application is that later on we will use the [HoloViews package](http://holoviews.org) for visualization. This package is a great tool for dealing with multidimentional annotated data and will do things like automatically create nice axis labels with units. However, in order for it to work, we must first annotate our data to include this information.\n",
"\n",
@@ -672,7 +672,7 @@
"source": [
"Next, we run the model. In each time step we first run the FlowAccumulator to direct flow and accumulatate drainage area. Then the FastscapeEroder erodes the topography based on the stream power equation using the erodability value in the field `'K_sp'`. We create an uplift field that uplifts only the model grid's core nodes. After uplifting these core nodes, we update LithoLayers. Importantly, we must tell the LithoLayers how it has been advected upward by uplift using the `dz_advection` keyword argument. \n",
"\n",
- "As we discussed in the introductory example, the built-in function [`lith.run_one_step`](https://landlab.readthedocs.io/en/release/landlab.components.litholayers.html#landlab.components.lithology.litholayers.LithoLayers.run_one_step) has an optional keyword argument `rock_id` to use when some material may be deposited. The LithoLayers component needs to know what type of rock exists everywhere and it will raise an error if material is deposited **and** no rock type is specified. However, here we are using the FastscapeEroder which is fully detachment limited, and thus we know that no material will be deposited at any time. Thus we can ignore this keyword argument. Later in the tutorial we will use the LinearDiffuser which can deposit sediment and we will need to set this keyword argument correctly. \n",
+ "As we discussed in the introductory example, the built-in function [`lith.run_one_step`](https://landlab.csdms.io/generated/api/landlab.components.lithology.litholayers.html#landlab.components.lithology.litholayers.LithoLayers.run_one_step) has an optional keyword argument `rock_id` to use when some material may be deposited. The LithoLayers component needs to know what type of rock exists everywhere and it will raise an error if material is deposited **and** no rock type is specified. However, here we are using the FastscapeEroder which is fully detachment limited, and thus we know that no material will be deposited at any time. Thus we can ignore this keyword argument. Later in the tutorial we will use the LinearDiffuser which can deposit sediment and we will need to set this keyword argument correctly. \n",
"\n",
"Within each timestep we save information about the model for plotting. "
]
@@ -769,7 +769,7 @@
"\n",
"Here we will explore making inverted topography by eroding Lithology with constant properties for half of the model evaluation time, and then filling Lithology in with resistant material only where the drainage area is large. This is meant as a simple example of filling in valleys with volcanic material. \n",
"\n",
- "All of the details of the options for creating a [Lithology](https://landlab.readthedocs.io/en/release/landlab.components.lithology.html) can be found here. \n",
+ "All of the details of the options for creating a [Lithology](https://landlab.csdms.io/generated/api/landlab.components.lithology.lithology.html) can be found here. \n",
"\n",
"In the next code block we make a new model and run it. There are a few important differences between this next example and the one we just worked through in Part 2. \n",
"\n",
@@ -997,9 +997,9 @@
"\n",
"Nice work getting to the end of the tutorial!\n",
"\n",
- "For more detailed information about the [Lithology](https://landlab.readthedocs.io/en/release/landlab.components.lithology.html) and [LithoLayers](https://landlab.readthedocs.io/en/release/landlab.components.litholayers.html) objects, check out their detailed documentation. \n",
+ "For more detailed information about the [Lithology](https://landlab.csdms.io/generated/api/landlab.components.lithology.lithology.html) and [LithoLayers](https://landlab.csdms.io/generated/api/landlab.components.lithology.litholayers.html#module-landlab.components.lithology.litholayers) objects, check out their detailed documentation. \n",
"\n",
- "### **Click [here](https://landlab.readthedocs.io/en/latest/user_guide/tutorials.html) for more Landlab tutorials**"
+ "### **Click [here](https://landlab.csdms.io/tutorials/) for more Landlab tutorials**"
]
}
],
diff --git a/docs/source/tutorials/making_components/component_design_tips.ipynb b/docs/source/tutorials/making_components/component_design_tips.ipynb
index 8ef60aa62c..1814908646 100644
--- a/docs/source/tutorials/making_components/component_design_tips.ipynb
+++ b/docs/source/tutorials/making_components/component_design_tips.ipynb
@@ -13,7 +13,7 @@
"source": [
"Thanks for your interest in developing a component in Landlab! \n",
"\n",
- "This ipython notebook provides some tips on designing and building Landlab components. It assumes you are familiar with the basics of building a component. If you haven't already, take a look at the tutorial on [How to Write a Landlab Component](making_components.ipynb), the User Guide section on [Developing Your Own Component](https://landlab.readthedocs.io/en/latest/development/contribution/index.html), and the [Example Pull Request Creating a Component](https://github.com/landlab/landlab/pull/678). We also recommend that you familiarize yourself with the [Style and Lint conventions](https://landlab.readthedocs.io/en/latest/development/practices/style_conventions.html)."
+ "This ipython notebook provides some tips on designing and building Landlab components. It assumes you are familiar with the basics of building a component. If you haven't already, take a look at the tutorial on [How to Write a Landlab Component](making_components.ipynb), the User Guide section on [Developing Your Own Component](https://landlab.csdms.io/development/contribution/), and the [Example Pull Request Creating a Component](https://github.com/landlab/landlab/pull/678). We also recommend that you familiarize yourself with the [Style and Lint conventions](https://landlab.csdms.io/development/practices/style_conventions.html)."
]
},
{
@@ -52,7 +52,7 @@
"* Provide the standard header information (such as `input_var_names`)\n",
"* Provide an `__init__` method. A Landlab grid object should be the first argument (after `self`). Any other necessary parameters should be given as keyword arguments with meaningful defaults. \n",
"* Provide a `run_one_step` method. \n",
- "* Include external and internal documentation. If the component is included in the Landlab package (as opposed to being a separate add-on), it needs to have an entry in the API Reference Manual at landlab.readthedocs.org. (In most cases, the text on the website is autogenerated from the docstrings in the component itself, but the documentation files must still be updated by hand to refer to the new component, as described below.) The component code should include a header docstring that briefly describes what it is, and lists its input parameters.\n",
+ "* Include external and internal documentation. If the component is included in the Landlab package (as opposed to being a separate add-on), it needs to have an entry in the API Reference Manual at landlab.csdms.io. (In most cases, the text on the website is autogenerated from the docstrings in the component itself, but the documentation files must still be updated by hand to refer to the new component, as described below.) The component code should include a header docstring that briefly describes what it is, and lists its input parameters.\n",
"\n",
"In addition to these basic ingredients, we highly recommend that Landlab components also include the following:\n",
"\n",
@@ -74,14 +74,14 @@
"source": [
"## Unit Testing\n",
"\n",
- "Testing is essential to writing robust scientific software (see, e.g., [The Turing Way guide to testing research code](https://the-turing-way.netlify.com/testing/testing.html)). A typical Landlab component includes two types of test: doctests and external tests.\n",
+ "Testing is essential to writing robust scientific software (see, e.g., [The Turing Way guide to testing research code](https://book.the-turing-way.org/reproducible-research/testing.html)). A typical Landlab component includes two types of test: doctests and external tests.\n",
"\n",
- "Doctests, in addition to testing a particular piece of code, should also give users an idea of how the code works---in other words, it should function both as a test, and as an example of how to use the functionality in question. Docstrings, including doctests, are scraped automatically to create content in the [Landlab API Reference Manual](https://landlab.readthedocs.io).\n",
+ "Doctests, in addition to testing a particular piece of code, should also give users an idea of how the code works---in other words, it should function both as a test, and as an example of how to use the functionality in question. Docstrings, including doctests, are scraped automatically to create content in the [Landlab API Reference Manual](https://landlab.csdms.io).\n",
"\n",
"External testing scripts normally live in a subdirectory called `tests` inside your component's main folder, in a file called `test_`(something)`.py`, with one or more functions whose names begin with `test_`. Using this naming convention is how the testing tool we use ([`pytest`](https://pytest.org/en/latest/)) is able to find and run your tests. \n",
"\n",
"### Useful tools for writing tests\n",
- "The `numpy.testing` module provides handy functions for testing, such as asserting that the values in a particular array match the values that you expect. [`pytest`](https://pytest.org/en/latest/) provides the ability to test whether a particular error is raised with the [`pytest.raises`](https://docs.pytest.org/en/latest/reference.html?highlight=assert#pytest-raises) function. Nonetheless, in many cases the core Python libraries will suffice for testing: a test fails if any assertion fails and/or an error or exception is raised, and you can both `assert` logical conditions in tests and `raise` various [standard Python](https://docs.python.org/3/library/exceptions.html) or [Landlab-specific](https://landlab.readthedocs.io/en/latest/landlab.field.html#landlab.field.FieldError) exceptions within components \"by hand\".\n",
+ "The `numpy.testing` module provides handy functions for testing, such as asserting that the values in a particular array match the values that you expect. [`pytest`](https://pytest.org/en/latest/) provides the ability to test whether a particular error is raised with the [`pytest.raises`](https://docs.pytest.org/en/latest/reference.html?highlight=assert#pytest-raises) function. Nonetheless, in many cases the core Python libraries will suffice for testing: a test fails if any assertion fails and/or an error or exception is raised, and you can both `assert` logical conditions in tests and `raise` various [standard Python](https://docs.python.org/3/library/exceptions.html) or [Landlab-specific](https://landlab.csdms.io/generated/api/landlab.field.errors.html#landlab.field.errors.FieldError) exceptions within components \"by hand\".\n",
"\n",
"If you use a common block of code (e.g., setting up a grid) in multiple test, we recommend looking into using a [`pytest.fixture`](https://docs.pytest.org/en/latest/reference.html?highlight=assert#pytest-fixture) to define it. \n",
"\n",
@@ -111,7 +111,7 @@
"source": [
"## Documentation\n",
"\n",
- "Each Landlab component ideally has three kinds of documentation: internal documentation using docstrings within the code, \"external\" documentation in the [Landlab API Reference Manual](https://landlab.readthedocs.io), and one or more tutorials in the notebooks folder. Internal and external documentation are essentially one and the same: the internal docstrings are read and formatted (\"scraped\") to produce the API Reference documentation for each component. To get a component's docstrings included in the API Reference, you simply need to create a short text file in Landlab's `docs` folder, and edit the `index.rst` file in the same folder to add a reference to your new file. The process is described in the User Guide section on [Developing Your Own Component](https://landlab.readthedocs.io/en/latest/development/index.html)."
+ "Each Landlab component ideally has three kinds of documentation: internal documentation using docstrings within the code, \"external\" documentation in the [Landlab API Reference Manual](https://landlab.csdms.io), and one or more tutorials in the notebooks folder. Internal and external documentation are essentially one and the same: the internal docstrings are read and formatted (\"scraped\") to produce the API Reference documentation for each component. To get a component's docstrings included in the API Reference, you simply need to create a short text file in Landlab's `docs` folder, and edit the `index.rst` file in the same folder to add a reference to your new file. The process is described in the User Guide section on [Developing Your Own Component](https://landlab.csdms.io/development/contribution/develop_a_component.html)."
]
},
{
@@ -186,7 +186,7 @@
"\n",
"Landlab field names should be reasonably descriptive, while not being overly long. For example, `hydraulic_conductivity` is a better field name than simply `K`. As of this writing, Landlab has not yet adopted a standard naming convention (such as the CSDMS Standard Names, or the CF Standard Names), but best practice is to follow the *de facto* Landlab standards for names that already exist in at least one component. Landlab has tended thus far to use names that are in the spirit of (and sometimes identical to) the CSDMS Standard Names, while keeping these names to a manageable length.\n",
"\n",
- "An (infrequently updated) list of the standard names currently used in Landlab can be found [here](https://landlab.readthedocs.io/en/latest/user_guide/field_definitions.html).\n",
+ "An (infrequently updated) list of the standard names currently used in Landlab can be found [here](https://landlab.csdms.io/user_guide/field_definitions.html).\n",
"\n",
"### Public and Private Variables\n",
"\n",
@@ -229,7 +229,7 @@
"Using a setter function allows you to make sure that the user isn't giving an inappropriate value of the parameter (as in the example of a negative elastic thickness above, which would not make any sense). In general, think long and hard about giving users the ability to set variables. An update of a variable at the \"wrong\" time can easily lead to unforeseen consequences if some parts of the component have assumed the old value previously. Careful [testing](#unit-testing) is probably in order in these cases.\n",
"\n",
"## Other references\n",
- "Many of the landlab developers have found this [resource on python anti-patterns](https://docs.quantifiedcode.com/python-anti-patterns/index.html) helpful. "
+ "Many of the landlab developers have found this [resource on python anti-patterns](https://docs.quantifiedcode.com/python-anti-patterns/) helpful. "
]
}
],
diff --git a/docs/source/tutorials/making_components/making_components.ipynb b/docs/source/tutorials/making_components/making_components.ipynb
index 013b9e64a6..1f2fb6f29e 100644
--- a/docs/source/tutorials/making_components/making_components.ipynb
+++ b/docs/source/tutorials/making_components/making_components.ipynb
@@ -99,19 +99,19 @@
"outputs": [],
"source": [
"\"\"\"\n",
- " Examples\n",
- " --------\n",
- " >>> from landlab import RasterModelGrid\n",
- " >>> rg = RasterModelGrid((4, 5), 10.0)\n",
- " >>> kw = KinwaveOverlandFlowModel(rg)\n",
- " >>> kw.vel_coef\n",
- " 100.0\n",
- " >>> rg.at_node['surface_water__depth']\n",
- " array([ 0., 0., 0., 0., 0.,\n",
- " 0., 0., 0., 0., 0.,\n",
- " 0., 0., 0., 0., 0.,\n",
- " 0., 0., 0., 0., 0.])\n",
- " \"\"\""
+ "Examples\n",
+ "--------\n",
+ ">>> from landlab import RasterModelGrid\n",
+ ">>> rg = RasterModelGrid((4, 5), 10.0)\n",
+ ">>> kw = KinwaveOverlandFlowModel(rg)\n",
+ ">>> kw.vel_coef\n",
+ "100.0\n",
+ ">>> rg.at_node['surface_water__depth']\n",
+ "array([ 0., 0., 0., 0., 0.,\n",
+ " 0., 0., 0., 0., 0.,\n",
+ " 0., 0., 0., 0., 0.,\n",
+ " 0., 0., 0., 0., 0.])\n",
+ "\"\"\""
]
},
{
diff --git a/docs/source/tutorials/mass_wasting_runout/A_PlanarSlope.asc b/docs/source/tutorials/mass_wasting_runout/A_PlanarSlope.asc
index c4488898e5..046f88f40e 100644
--- a/docs/source/tutorials/mass_wasting_runout/A_PlanarSlope.asc
+++ b/docs/source/tutorials/mass_wasting_runout/A_PlanarSlope.asc
@@ -1,55 +1,55 @@
-ncols 17
-nrows 50
-xllcorner 0.0
-yllcorner 0.0
-cellsize 10.0
-2.001899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 2.001899999999999977e+02
-1.941899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.941899999999999977e+02
-1.881899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.881899999999999977e+02
-1.821899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.821899999999999977e+02
-1.761899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.761899999999999977e+02
-1.701899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.701899999999999977e+02
-1.641899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.641899999999999977e+02
-1.581899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.581899999999999977e+02
-1.521899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.521899999999999977e+02
-1.461899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.461899999999999977e+02
-1.401899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.401899999999999977e+02
-1.341899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.341899999999999977e+02
-1.281899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.281899999999999977e+02
-1.221899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.221899999999999977e+02
-1.161899999999999977e+02 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 1.161899999999999977e+02
-1.101899999999999977e+02 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 1.101899999999999977e+02
-1.041899999999999977e+02 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 1.041899999999999977e+02
-9.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 9.818999999999999773e+01
-9.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 9.218999999999999773e+01
-8.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 8.618999999999999773e+01
-8.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 8.018999999999999773e+01
-7.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 7.418999999999999773e+01
-6.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 6.818999999999999773e+01
-6.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 6.218999999999999773e+01
-5.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 5.618999999999999773e+01
-5.018999999999999773e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 5.018999999999999773e+01
-4.418999999999999773e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 4.418999999999999773e+01
-3.818999999999999773e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 3.818999999999999773e+01
-3.218999999999999773e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 3.218999999999999773e+01
-2.619000000000000128e+01 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 2.619000000000000128e+01
-2.019000000000000128e+01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 2.019000000000000128e+01
-2.017999999999999972e+01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 2.017999999999999972e+01
-2.017000000000000171e+01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 2.017000000000000171e+01
-2.016000000000000014e+01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 2.016000000000000014e+01
-2.014999999999999858e+01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 2.014999999999999858e+01
-2.014000000000000057e+01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 2.014000000000000057e+01
-2.012999999999999901e+01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 2.012999999999999901e+01
-2.012000000000000099e+01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 2.012000000000000099e+01
-2.010999999999999943e+01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 2.010999999999999943e+01
-2.010000000000000142e+01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 2.010000000000000142e+01
-2.008999999999999986e+01 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 2.008999999999999986e+01
-2.007999999999999829e+01 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 2.007999999999999829e+01
-2.007000000000000028e+01 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 2.007000000000000028e+01
-2.005999999999999872e+01 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 2.005999999999999872e+01
-2.005000000000000071e+01 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 2.005000000000000071e+01
-2.003999999999999915e+01 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 2.003999999999999915e+01
-2.003000000000000114e+01 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.003000000000000114e+01
-2.001999999999999957e+01 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.001999999999999957e+01
-2.001000000000000156e+01 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 2.001000000000000156e+01
-2.000000000000000000e+01 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 2.000000000000000000e+01
+ncols 17
+nrows 50
+xllcorner 0.0
+yllcorner 0.0
+cellsize 10.0
+2.001899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 2.001899999999999977e+02
+1.941899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.941899999999999977e+02
+1.881899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.881899999999999977e+02
+1.821899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.821899999999999977e+02
+1.761899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.761899999999999977e+02
+1.701899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.701899999999999977e+02
+1.641899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.641899999999999977e+02
+1.581899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.581899999999999977e+02
+1.521899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.521899999999999977e+02
+1.461899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.461899999999999977e+02
+1.401899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.401899999999999977e+02
+1.341899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.341899999999999977e+02
+1.281899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.281899999999999977e+02
+1.221899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.221899999999999977e+02
+1.161899999999999977e+02 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 1.161899999999999977e+02
+1.101899999999999977e+02 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 1.101899999999999977e+02
+1.041899999999999977e+02 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 1.041899999999999977e+02
+9.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 9.818999999999999773e+01
+9.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 9.218999999999999773e+01
+8.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 8.618999999999999773e+01
+8.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 8.018999999999999773e+01
+7.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 7.418999999999999773e+01
+6.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 6.818999999999999773e+01
+6.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 6.218999999999999773e+01
+5.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 5.618999999999999773e+01
+5.018999999999999773e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 5.018999999999999773e+01
+4.418999999999999773e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 4.418999999999999773e+01
+3.818999999999999773e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 3.818999999999999773e+01
+3.218999999999999773e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 3.218999999999999773e+01
+2.619000000000000128e+01 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 2.619000000000000128e+01
+2.019000000000000128e+01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 2.019000000000000128e+01
+2.017999999999999972e+01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 2.017999999999999972e+01
+2.017000000000000171e+01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 2.017000000000000171e+01
+2.016000000000000014e+01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 2.016000000000000014e+01
+2.014999999999999858e+01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 2.014999999999999858e+01
+2.014000000000000057e+01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 2.014000000000000057e+01
+2.012999999999999901e+01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 2.012999999999999901e+01
+2.012000000000000099e+01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 2.012000000000000099e+01
+2.010999999999999943e+01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 2.010999999999999943e+01
+2.010000000000000142e+01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 2.010000000000000142e+01
+2.008999999999999986e+01 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 2.008999999999999986e+01
+2.007999999999999829e+01 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 2.007999999999999829e+01
+2.007000000000000028e+01 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 2.007000000000000028e+01
+2.005999999999999872e+01 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 2.005999999999999872e+01
+2.005000000000000071e+01 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 2.005000000000000071e+01
+2.003999999999999915e+01 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 2.003999999999999915e+01
+2.003000000000000114e+01 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.003000000000000114e+01
+2.001999999999999957e+01 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.001999999999999957e+01
+2.001000000000000156e+01 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 2.001000000000000156e+01
+2.000000000000000000e+01 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 2.000000000000000000e+01
diff --git a/docs/source/tutorials/mass_wasting_runout/B_PlanarSlopeWithConstriction.asc b/docs/source/tutorials/mass_wasting_runout/B_PlanarSlopeWithConstriction.asc
index 6b4807a111..b1379a1cb8 100644
--- a/docs/source/tutorials/mass_wasting_runout/B_PlanarSlopeWithConstriction.asc
+++ b/docs/source/tutorials/mass_wasting_runout/B_PlanarSlopeWithConstriction.asc
@@ -1,55 +1,55 @@
-ncols 17
-nrows 50
-xllcorner 0.0
-yllcorner 0.0
-cellsize 10.0
-2.001899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 2.001899999999999977e+02
-1.941899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.941899999999999977e+02
-1.881899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.881899999999999977e+02
-1.821899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.821899999999999977e+02
-1.761899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.761899999999999977e+02
-1.701899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.701899999999999977e+02
-1.641899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.641899999999999977e+02
-1.581899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.581899999999999977e+02
-1.521899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.521899999999999977e+02
-1.461899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.461899999999999977e+02
-1.401899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.401899999999999977e+02
-1.341899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.341899999999999977e+02
-1.281899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.281899999999999977e+02
-1.221899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.221899999999999977e+02
-1.161899999999999977e+02 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 1.161899999999999977e+02
-1.101899999999999977e+02 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 1.101899999999999977e+02
-1.041899999999999977e+02 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 1.041899999999999977e+02
-9.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 9.818999999999999773e+01
-9.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 9.218999999999999773e+01
-8.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 8.618999999999999773e+01
-1.101899999999999977e+02 9.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 9.018999999999999773e+01 1.101899999999999977e+02
-1.041899999999999977e+02 8.418999999999999773e+01 8.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 1.041899999999999977e+02
-6.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 6.818999999999999773e+01
-6.218999999999999773e+01 4.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 4.218999999999999773e+01 6.218999999999999773e+01
-5.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 5.618999999999999773e+01
-5.018999999999999773e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 5.018999999999999773e+01
-4.418999999999999773e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 5.418999999999999773e+01 5.418999999999999773e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 5.418999999999999773e+01 5.418999999999999773e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 4.418999999999999773e+01
-3.818999999999999773e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 3.818999999999999773e+01
-3.218999999999999773e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 3.218999999999999773e+01
-2.619000000000000128e+01 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 2.619000000000000128e+01
-2.019000000000000128e+01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 2.019000000000000128e+01
-2.017999999999999972e+01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 2.017999999999999972e+01
-2.017000000000000171e+01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 2.017000000000000171e+01
-2.016000000000000014e+01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 2.016000000000000014e+01
-2.014999999999999858e+01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 2.014999999999999858e+01
-2.014000000000000057e+01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 2.014000000000000057e+01
-2.012999999999999901e+01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 2.012999999999999901e+01
-2.012000000000000099e+01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 2.012000000000000099e+01
-2.010999999999999943e+01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 2.010999999999999943e+01
-2.010000000000000142e+01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 2.010000000000000142e+01
-2.008999999999999986e+01 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 2.008999999999999986e+01
-2.007999999999999829e+01 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 2.007999999999999829e+01
-2.007000000000000028e+01 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 2.007000000000000028e+01
-2.005999999999999872e+01 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 2.005999999999999872e+01
-2.005000000000000071e+01 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 2.005000000000000071e+01
-2.003999999999999915e+01 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 2.003999999999999915e+01
-2.003000000000000114e+01 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.003000000000000114e+01
-2.001999999999999957e+01 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.001999999999999957e+01
-2.001000000000000156e+01 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 2.001000000000000156e+01
-2.000000000000000000e+01 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 2.000000000000000000e+01
+ncols 17
+nrows 50
+xllcorner 0.0
+yllcorner 0.0
+cellsize 10.0
+2.001899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 1.801899999999999977e+02 2.001899999999999977e+02
+1.941899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.741899999999999977e+02 1.941899999999999977e+02
+1.881899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.681899999999999977e+02 1.881899999999999977e+02
+1.821899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.621899999999999977e+02 1.821899999999999977e+02
+1.761899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.561899999999999977e+02 1.761899999999999977e+02
+1.701899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.501899999999999977e+02 1.701899999999999977e+02
+1.641899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.441899999999999977e+02 1.641899999999999977e+02
+1.581899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.381899999999999977e+02 1.581899999999999977e+02
+1.521899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.321899999999999977e+02 1.521899999999999977e+02
+1.461899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.261899999999999977e+02 1.461899999999999977e+02
+1.401899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.201899999999999977e+02 1.401899999999999977e+02
+1.341899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.141899999999999977e+02 1.341899999999999977e+02
+1.281899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.081899999999999977e+02 1.281899999999999977e+02
+1.221899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.021899999999999977e+02 1.221899999999999977e+02
+1.161899999999999977e+02 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 9.618999999999999773e+01 1.161899999999999977e+02
+1.101899999999999977e+02 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 9.018999999999999773e+01 1.101899999999999977e+02
+1.041899999999999977e+02 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 1.041899999999999977e+02
+9.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 9.818999999999999773e+01
+9.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 9.218999999999999773e+01
+8.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 8.618999999999999773e+01
+1.101899999999999977e+02 9.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 9.018999999999999773e+01 1.101899999999999977e+02
+1.041899999999999977e+02 8.418999999999999773e+01 8.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 5.418999999999999773e+01 8.418999999999999773e+01 8.418999999999999773e+01 1.041899999999999977e+02
+6.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 4.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 7.818999999999999773e+01 6.818999999999999773e+01
+6.218999999999999773e+01 4.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 4.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 7.218999999999999773e+01 4.218999999999999773e+01 6.218999999999999773e+01
+5.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 6.618999999999999773e+01 3.618999999999999773e+01 3.618999999999999773e+01 5.618999999999999773e+01
+5.018999999999999773e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 6.018999999999999773e+01 6.018999999999999773e+01 6.018999999999999773e+01 3.019000000000000128e+01 3.019000000000000128e+01 3.019000000000000128e+01 5.018999999999999773e+01
+4.418999999999999773e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 5.418999999999999773e+01 5.418999999999999773e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 5.418999999999999773e+01 5.418999999999999773e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 2.419000000000000128e+01 4.418999999999999773e+01
+3.818999999999999773e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 1.819000000000000128e+01 3.818999999999999773e+01
+3.218999999999999773e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 1.218999999999999950e+01 3.218999999999999773e+01
+2.619000000000000128e+01 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 6.190000000000000391e+00 2.619000000000000128e+01
+2.019000000000000128e+01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 1.900000000000000022e-01 2.019000000000000128e+01
+2.017999999999999972e+01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 1.799999999999999933e-01 2.017999999999999972e+01
+2.017000000000000171e+01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 1.700000000000000122e-01 2.017000000000000171e+01
+2.016000000000000014e+01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 1.600000000000000033e-01 2.016000000000000014e+01
+2.014999999999999858e+01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 1.499999999999999944e-01 2.014999999999999858e+01
+2.014000000000000057e+01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 1.400000000000000133e-01 2.014000000000000057e+01
+2.012999999999999901e+01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 1.300000000000000044e-01 2.012999999999999901e+01
+2.012000000000000099e+01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 1.199999999999999956e-01 2.012000000000000099e+01
+2.010999999999999943e+01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 2.010999999999999943e+01
+2.010000000000000142e+01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 2.010000000000000142e+01
+2.008999999999999986e+01 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 2.008999999999999986e+01
+2.007999999999999829e+01 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 2.007999999999999829e+01
+2.007000000000000028e+01 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 2.007000000000000028e+01
+2.005999999999999872e+01 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 2.005999999999999872e+01
+2.005000000000000071e+01 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 2.005000000000000071e+01
+2.003999999999999915e+01 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 2.003999999999999915e+01
+2.003000000000000114e+01 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.003000000000000114e+01
+2.001999999999999957e+01 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.001999999999999957e+01
+2.001000000000000156e+01 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 2.001000000000000156e+01
+2.000000000000000000e+01 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 2.000000000000000000e+01
diff --git a/docs/source/tutorials/mass_wasting_runout/C_WideFlumeWithBench.asc b/docs/source/tutorials/mass_wasting_runout/C_WideFlumeWithBench.asc
index c274d71a53..3a5c79417a 100644
--- a/docs/source/tutorials/mass_wasting_runout/C_WideFlumeWithBench.asc
+++ b/docs/source/tutorials/mass_wasting_runout/C_WideFlumeWithBench.asc
@@ -1,55 +1,55 @@
-ncols 17
-nrows 50
-xllcorner 0.0
-yllcorner 0.0
-cellsize 10.0
-2.241500000000000341e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.241500000000000341e+02
-2.181500000000000341e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 2.181500000000000341e+02
-2.121500000000000341e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 2.121500000000000341e+02
-2.061500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 2.061500000000000057e+02
-2.001500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 2.001500000000000057e+02
-1.941500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.941500000000000057e+02
-1.881500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.881500000000000057e+02
-1.821500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.821500000000000057e+02
-1.761500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.761500000000000057e+02
-1.701500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.701500000000000057e+02
-1.641499999999999773e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.641499999999999773e+02
-1.581499999999999773e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.581499999999999773e+02
-1.521499999999999773e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.521499999999999773e+02
-1.461500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.461500000000000057e+02
-1.401500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.401500000000000057e+02
-1.341500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.341500000000000057e+02
-1.281500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.281500000000000057e+02
-1.221500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.221500000000000057e+02
-1.161500000000000057e+02 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 1.161500000000000057e+02
-1.101500000000000057e+02 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 1.101500000000000057e+02
-1.041500000000000057e+02 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 1.041500000000000057e+02
-1.041400000000000006e+02 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 1.041400000000000006e+02
-1.041299999999999955e+02 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 1.041299999999999955e+02
-1.041200000000000045e+02 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 1.041200000000000045e+02
-1.041099999999999994e+02 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 1.041099999999999994e+02
-9.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 9.810999999999999943e+01
-9.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 9.210999999999999943e+01
-8.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 8.610999999999999943e+01
-8.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 8.010999999999999943e+01
-7.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 7.410999999999999943e+01
-6.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 6.810999999999999943e+01
-6.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 6.210999999999999943e+01
-5.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 5.610999999999999943e+01
-5.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 5.010999999999999943e+01
-4.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 4.410999999999999943e+01
-3.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 3.810999999999999943e+01
-3.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 3.210999999999999943e+01
-2.610999999999999943e+01 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 2.610999999999999943e+01
-2.010999999999999943e+01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 2.010999999999999943e+01
-2.010000000000000142e+01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 2.010000000000000142e+01
-2.008999999999999986e+01 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 2.008999999999999986e+01
-2.007999999999999829e+01 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 2.007999999999999829e+01
-2.007000000000000028e+01 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 2.007000000000000028e+01
-2.005999999999999872e+01 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 2.005999999999999872e+01
-2.005000000000000071e+01 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 2.005000000000000071e+01
-2.003999999999999915e+01 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 2.003999999999999915e+01
-2.003000000000000114e+01 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.003000000000000114e+01
-2.001999999999999957e+01 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.001999999999999957e+01
-2.001000000000000156e+01 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 2.001000000000000156e+01
-2.000000000000000000e+01 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 2.000000000000000000e+01
+ncols 17
+nrows 50
+xllcorner 0.0
+yllcorner 0.0
+cellsize 10.0
+2.241500000000000341e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.041500000000000057e+02 2.241500000000000341e+02
+2.181500000000000341e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 1.981500000000000057e+02 2.181500000000000341e+02
+2.121500000000000341e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 1.921500000000000057e+02 2.121500000000000341e+02
+2.061500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 1.861500000000000057e+02 2.061500000000000057e+02
+2.001500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 1.801500000000000057e+02 2.001500000000000057e+02
+1.941500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.741500000000000057e+02 1.941500000000000057e+02
+1.881500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.681500000000000057e+02 1.881500000000000057e+02
+1.821500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.621500000000000057e+02 1.821500000000000057e+02
+1.761500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.561500000000000057e+02 1.761500000000000057e+02
+1.701500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.501500000000000057e+02 1.701500000000000057e+02
+1.641499999999999773e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.441500000000000057e+02 1.641499999999999773e+02
+1.581499999999999773e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.381500000000000057e+02 1.581499999999999773e+02
+1.521499999999999773e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.321500000000000057e+02 1.521499999999999773e+02
+1.461500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.261500000000000057e+02 1.461500000000000057e+02
+1.401500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.201500000000000057e+02 1.401500000000000057e+02
+1.341500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.141500000000000057e+02 1.341500000000000057e+02
+1.281500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.081500000000000057e+02 1.281500000000000057e+02
+1.221500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.021500000000000057e+02 1.221500000000000057e+02
+1.161500000000000057e+02 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 9.615000000000000568e+01 1.161500000000000057e+02
+1.101500000000000057e+02 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 9.015000000000000568e+01 1.101500000000000057e+02
+1.041500000000000057e+02 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 8.415000000000000568e+01 1.041500000000000057e+02
+1.041400000000000006e+02 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 8.414000000000000057e+01 1.041400000000000006e+02
+1.041299999999999955e+02 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 8.412999999999999545e+01 1.041299999999999955e+02
+1.041200000000000045e+02 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 8.412000000000000455e+01 1.041200000000000045e+02
+1.041099999999999994e+02 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 8.410999999999999943e+01 1.041099999999999994e+02
+9.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 7.810999999999999943e+01 9.810999999999999943e+01
+9.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 7.210999999999999943e+01 9.210999999999999943e+01
+8.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 6.610999999999999943e+01 8.610999999999999943e+01
+8.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 6.010999999999999943e+01 8.010999999999999943e+01
+7.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 5.410999999999999943e+01 7.410999999999999943e+01
+6.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 4.810999999999999943e+01 6.810999999999999943e+01
+6.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 4.210999999999999943e+01 6.210999999999999943e+01
+5.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 3.610999999999999943e+01 5.610999999999999943e+01
+5.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 3.010999999999999943e+01 5.010999999999999943e+01
+4.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 2.410999999999999943e+01 4.410999999999999943e+01
+3.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 1.810999999999999943e+01 3.810999999999999943e+01
+3.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 1.210999999999999943e+01 3.210999999999999943e+01
+2.610999999999999943e+01 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 6.110000000000000320e+00 2.610999999999999943e+01
+2.010999999999999943e+01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 1.100000000000000006e-01 2.010999999999999943e+01
+2.010000000000000142e+01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 1.000000000000000056e-01 2.010000000000000142e+01
+2.008999999999999986e+01 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 8.999999999999999667e-02 2.008999999999999986e+01
+2.007999999999999829e+01 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 8.000000000000000167e-02 2.007999999999999829e+01
+2.007000000000000028e+01 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 7.000000000000000666e-02 2.007000000000000028e+01
+2.005999999999999872e+01 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 5.999999999999999778e-02 2.005999999999999872e+01
+2.005000000000000071e+01 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 5.000000000000000278e-02 2.005000000000000071e+01
+2.003999999999999915e+01 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 4.000000000000000083e-02 2.003999999999999915e+01
+2.003000000000000114e+01 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.999999999999999889e-02 2.003000000000000114e+01
+2.001999999999999957e+01 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.000000000000000042e-02 2.001999999999999957e+01
+2.001000000000000156e+01 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 1.000000000000000021e-02 2.001000000000000156e+01
+2.000000000000000000e+01 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 2.000000000000000000e+01
diff --git a/docs/source/tutorials/mass_wasting_runout/D_ConvergentConcave.asc b/docs/source/tutorials/mass_wasting_runout/D_ConvergentConcave.asc
index a7fe1b9bd8..0dd7bc5335 100644
--- a/docs/source/tutorials/mass_wasting_runout/D_ConvergentConcave.asc
+++ b/docs/source/tutorials/mass_wasting_runout/D_ConvergentConcave.asc
@@ -1,55 +1,55 @@
-ncols 15
-nrows 50
-xllcorner 0.0
-yllcorner 0.0
-cellsize 10.0
-1.335678521165119719e+02 1.205678521165119861e+02 1.095678521165119861e+02 1.005678521165119861e+02 9.356785211651198608e+01 8.856785211651198608e+01 8.556785211651198608e+01 8.456785211651198608e+01 8.556785211651198608e+01 8.856785211651198608e+01 9.356785211651198608e+01 1.005678521165119861e+02 1.095678521165119861e+02 1.205678521165119861e+02 1.335678521165119719e+02
-1.298173575747255200e+02 1.168173575747255200e+02 1.058173575747255200e+02 9.681735757472551995e+01 8.981735757472551995e+01 8.481735757472551995e+01 8.181735757472551995e+01 8.081735757472551995e+01 8.181735757472551995e+01 8.481735757472551995e+01 8.981735757472551995e+01 9.681735757472551995e+01 1.058173575747255200e+02 1.168173575747255200e+02 1.298173575747255200e+02
-1.261594657192227231e+02 1.131594657192227231e+02 1.021594657192227231e+02 9.315946571922272312e+01 8.615946571922272312e+01 8.115946571922272312e+01 7.815946571922272312e+01 7.715946571922272312e+01 7.815946571922272312e+01 8.115946571922272312e+01 8.615946571922272312e+01 9.315946571922272312e+01 1.021594657192227231e+02 1.131594657192227231e+02 1.261594657192227231e+02
-1.225937874263653100e+02 1.095937874263653100e+02 9.859378742636531001e+01 8.959378742636531001e+01 8.259378742636531001e+01 7.759378742636531001e+01 7.459378742636531001e+01 7.359378742636531001e+01 7.459378742636531001e+01 7.759378742636531001e+01 8.259378742636531001e+01 8.959378742636531001e+01 9.859378742636531001e+01 1.095937874263653100e+02 1.225937874263653100e+02
-1.191199268908159752e+02 1.061199268908159752e+02 9.511992689081597518e+01 8.611992689081597518e+01 7.911992689081597518e+01 7.411992689081597518e+01 7.111992689081597518e+01 7.011992689081597518e+01 7.111992689081597518e+01 7.411992689081597518e+01 7.911992689081597518e+01 8.611992689081597518e+01 9.511992689081597518e+01 1.061199268908159752e+02 1.191199268908159752e+02
-1.157374813616942220e+02 1.027374813616942220e+02 9.173748136169422196e+01 8.273748136169422196e+01 7.573748136169422196e+01 7.073748136169422196e+01 6.773748136169422196e+01 6.673748136169422196e+01 6.773748136169422196e+01 7.073748136169422196e+01 7.573748136169422196e+01 8.273748136169422196e+01 9.173748136169422196e+01 1.027374813616942220e+02 1.157374813616942220e+02
-1.124460408621596343e+02 9.944604086215963434e+01 8.844604086215963434e+01 7.944604086215963434e+01 7.244604086215963434e+01 6.744604086215963434e+01 6.444604086215963434e+01 6.344604086215964145e+01 6.444604086215963434e+01 6.744604086215963434e+01 7.244604086215963434e+01 7.944604086215963434e+01 8.844604086215963434e+01 9.944604086215963434e+01 1.124460408621596343e+02
-1.092451878909776610e+02 9.624518789097766103e+01 8.524518789097766103e+01 7.624518789097766103e+01 6.924518789097766103e+01 6.424518789097766103e+01 6.124518789097766103e+01 6.024518789097766103e+01 6.124518789097766103e+01 6.424518789097766103e+01 6.924518789097766103e+01 7.624518789097766103e+01 8.524518789097766103e+01 9.624518789097766103e+01 1.092451878909776610e+02
-1.061344971044590153e+02 9.313449710445901530e+01 8.213449710445901530e+01 7.313449710445901530e+01 6.613449710445901530e+01 6.113449710445901530e+01 5.813449710445901530e+01 5.713449710445901530e+01 5.813449710445901530e+01 6.113449710445901530e+01 6.613449710445901530e+01 7.313449710445901530e+01 8.213449710445901530e+01 9.313449710445901530e+01 1.061344971044590153e+02
-1.031135349769793663e+02 9.011353497697936632e+01 7.911353497697936632e+01 7.011353497697936632e+01 6.311353497697936632e+01 5.811353497697936632e+01 5.511353497697936632e+01 5.411353497697936632e+01 5.511353497697936632e+01 5.811353497697936632e+01 6.311353497697936632e+01 7.011353497697936632e+01 7.911353497697936632e+01 9.011353497697936632e+01 1.031135349769793663e+02
-1.001818594380724932e+02 8.718185943807249316e+01 7.618185943807249316e+01 6.718185943807249316e+01 6.018185943807249316e+01 5.518185943807249316e+01 5.218185943807249316e+01 5.118185943807249316e+01 5.218185943807249316e+01 5.518185943807249316e+01 6.018185943807249316e+01 6.718185943807249316e+01 7.618185943807249316e+01 8.718185943807249316e+01 1.001818594380724932e+02
-9.733901948384726666e+01 8.433901948384726666e+01 7.333901948384726666e+01 6.433901948384726666e+01 5.733901948384725955e+01 5.233901948384725955e+01 4.933901948384725955e+01 4.833901948384725955e+01 4.933901948384725955e+01 5.233901948384725955e+01 5.733901948384725955e+01 6.433901948384726666e+01 7.333901948384726666e+01 8.433901948384726666e+01 9.733901948384726666e+01
-9.458455476019886987e+01 8.158455476019886987e+01 7.058455476019886987e+01 6.158455476019886987e+01 5.458455476019886987e+01 4.958455476019886987e+01 4.658455476019886987e+01 4.558455476019886987e+01 4.658455476019886987e+01 4.958455476019886987e+01 5.458455476019886987e+01 6.158455476019886987e+01 7.058455476019886987e+01 8.158455476019886987e+01 9.458455476019886987e+01
-9.191799511496095931e+01 7.891799511496095931e+01 6.791799511496095931e+01 5.891799511496095931e+01 5.191799511496095931e+01 4.691799511496095931e+01 4.391799511496095931e+01 4.291799511496095931e+01 4.391799511496095931e+01 4.691799511496095931e+01 5.191799511496095931e+01 5.891799511496095931e+01 6.791799511496095931e+01 7.891799511496095931e+01 9.191799511496095931e+01
-8.933886011577118325e+01 7.633886011577118325e+01 6.533886011577118325e+01 5.633886011577119035e+01 4.933886011577119035e+01 4.433886011577119035e+01 4.133886011577119035e+01 4.033886011577119035e+01 4.133886011577119035e+01 4.433886011577119035e+01 4.933886011577119035e+01 5.633886011577119035e+01 6.533886011577118325e+01 7.633886011577118325e+01 8.933886011577118325e+01
-8.684665852998699620e+01 7.384665852998699620e+01 6.284665852998700331e+01 5.384665852998700331e+01 4.684665852998700331e+01 4.184665852998700331e+01 3.884665852998700331e+01 3.784665852998700331e+01 3.884665852998700331e+01 4.184665852998700331e+01 4.684665852998700331e+01 5.384665852998700331e+01 6.284665852998700331e+01 7.384665852998699620e+01 8.684665852998699620e+01
-8.444088776247913586e+01 7.144088776247913586e+01 6.044088776247913586e+01 5.144088776247913586e+01 4.444088776247913586e+01 3.944088776247913586e+01 3.644088776247913586e+01 3.544088776247913586e+01 3.644088776247913586e+01 3.944088776247913586e+01 4.444088776247913586e+01 5.144088776247913586e+01 6.044088776247913586e+01 7.144088776247913586e+01 8.444088776247913586e+01
-8.212103324653428160e+01 6.912103324653428160e+01 5.812103324653428160e+01 4.912103324653428160e+01 4.212103324653428160e+01 3.712103324653428160e+01 3.412103324653428160e+01 3.312103324653428160e+01 3.412103324653428160e+01 3.712103324653428160e+01 4.212103324653428160e+01 4.912103324653428160e+01 5.812103324653428160e+01 6.912103324653428160e+01 8.212103324653428160e+01
-7.988656778239459300e+01 6.688656778239459300e+01 5.588656778239459300e+01 4.688656778239459300e+01 3.988656778239459300e+01 3.488656778239459300e+01 3.188656778239458944e+01 3.088656778239458944e+01 3.188656778239458944e+01 3.488656778239459300e+01 3.988656778239459300e+01 4.688656778239459300e+01 5.588656778239459300e+01 6.688656778239459300e+01 7.988656778239459300e+01
-7.773695081712966726e+01 6.473695081712966726e+01 5.373695081712967436e+01 4.473695081712967436e+01 3.773695081712967436e+01 3.273695081712967436e+01 2.973695081712967436e+01 2.873695081712967436e+01 2.973695081712967436e+01 3.273695081712967436e+01 3.773695081712967436e+01 4.473695081712967436e+01 5.373695081712967436e+01 6.473695081712966726e+01 7.773695081712966726e+01
-7.567162765854615714e+01 6.267162765854615714e+01 5.167162765854615714e+01 4.267162765854615714e+01 3.567162765854615714e+01 3.067162765854616069e+01 2.767162765854616069e+01 2.667162765854616069e+01 2.767162765854616069e+01 3.067162765854616069e+01 3.567162765854615714e+01 4.267162765854615714e+01 5.167162765854615714e+01 6.267162765854615714e+01 7.567162765854615714e+01
-7.369002861465497745e+01 6.069002861465497034e+01 4.969002861465497034e+01 4.069002861465497034e+01 3.369002861465497034e+01 2.869002861465497034e+01 2.569002861465497034e+01 2.469002861465497034e+01 2.569002861465497034e+01 2.869002861465497034e+01 3.369002861465497034e+01 4.069002861465497034e+01 4.969002861465497034e+01 6.069002861465497034e+01 7.369002861465497745e+01
-7.179156804879076503e+01 5.879156804879076503e+01 4.779156804879076503e+01 3.879156804879076503e+01 3.179156804879076148e+01 2.679156804879076148e+01 2.379156804879076148e+01 2.279156804879076148e+01 2.379156804879076148e+01 2.679156804879076148e+01 3.179156804879076148e+01 3.879156804879076503e+01 4.779156804879076503e+01 5.879156804879076503e+01 7.179156804879076503e+01
-6.997564333875216391e+01 5.697564333875216391e+01 4.597564333875216391e+01 3.697564333875216391e+01 2.997564333875216747e+01 2.497564333875216747e+01 2.197564333875216747e+01 2.097564333875216747e+01 2.197564333875216747e+01 2.497564333875216747e+01 2.997564333875216747e+01 3.697564333875216391e+01 4.597564333875216391e+01 5.697564333875216391e+01 6.997564333875216391e+01
-6.824163372622820134e+01 5.524163372622819423e+01 4.424163372622819423e+01 3.524163372622819423e+01 2.824163372622819423e+01 2.324163372622819423e+01 2.024163372622819423e+01 1.924163372622819423e+01 2.024163372622819423e+01 2.324163372622819423e+01 2.824163372622819423e+01 3.524163372622819423e+01 4.424163372622819423e+01 5.524163372622819423e+01 6.824163372622820134e+01
-6.658889904019540040e+01 5.358889904019540040e+01 4.258889904019540040e+01 3.358889904019540040e+01 2.658889904019539685e+01 2.158889904019539685e+01 1.858889904019539685e+01 1.758889904019539685e+01 1.858889904019539685e+01 2.158889904019539685e+01 2.658889904019539685e+01 3.358889904019540040e+01 4.258889904019540040e+01 5.358889904019540040e+01 6.658889904019540040e+01
-6.501677827477938365e+01 5.201677827477938365e+01 4.101677827477938365e+01 3.201677827477938365e+01 2.501677827477938365e+01 2.001677827477938365e+01 1.701677827477938365e+01 1.601677827477938365e+01 1.701677827477938365e+01 2.001677827477938365e+01 2.501677827477938365e+01 3.201677827477938365e+01 4.101677827477938365e+01 5.201677827477938365e+01 6.501677827477938365e+01
-6.352458799809687662e+01 5.052458799809687662e+01 3.952458799809687662e+01 3.052458799809687306e+01 2.352458799809687306e+01 1.852458799809687306e+01 1.552458799809687306e+01 1.452458799809687306e+01 1.552458799809687306e+01 1.852458799809687306e+01 2.352458799809687306e+01 3.052458799809687306e+01 3.952458799809687662e+01 5.052458799809687662e+01 6.352458799809687662e+01
-6.211162056359285799e+01 4.911162056359285799e+01 3.811162056359285799e+01 2.911162056359285799e+01 2.211162056359285799e+01 1.711162056359285799e+01 1.411162056359285977e+01 1.311162056359285977e+01 1.411162056359285977e+01 1.711162056359285799e+01 2.211162056359285799e+01 2.911162056359285799e+01 3.811162056359285799e+01 4.911162056359285799e+01 6.211162056359285799e+01
-6.077714208903847748e+01 4.777714208903847748e+01 3.677714208903847748e+01 2.777714208903847748e+01 2.077714208903847748e+01 1.577714208903847748e+01 1.277714208903847748e+01 1.177714208903847748e+01 1.277714208903847748e+01 1.577714208903847748e+01 2.077714208903847748e+01 2.777714208903847748e+01 3.677714208903847748e+01 4.777714208903847748e+01 6.077714208903847748e+01
-5.952039016021139162e+01 4.652039016021139162e+01 3.552039016021139162e+01 2.652039016021139162e+01 1.952039016021139162e+01 1.452039016021138984e+01 1.152039016021138984e+01 1.052039016021138984e+01 1.152039016021138984e+01 1.452039016021138984e+01 1.952039016021139162e+01 2.652039016021139162e+01 3.552039016021139162e+01 4.652039016021139162e+01 5.952039016021139162e+01
-5.834057120571738864e+01 4.534057120571738864e+01 3.434057120571738864e+01 2.534057120571738864e+01 1.834057120571738864e+01 1.334057120571739041e+01 1.034057120571739041e+01 9.340571205717390413e+00 1.034057120571739041e+01 1.334057120571739041e+01 1.834057120571738864e+01 2.534057120571738864e+01 3.434057120571738864e+01 4.534057120571738864e+01 5.834057120571738864e+01
-5.723685747553906111e+01 4.423685747553906111e+01 3.323685747553906111e+01 2.423685747553906111e+01 1.723685747553906111e+01 1.223685747553906111e+01 9.236857475539061113e+00 8.236857475539061113e+00 9.236857475539061113e+00 1.223685747553906111e+01 1.723685747553906111e+01 2.423685747553906111e+01 3.323685747553906111e+01 4.423685747553906111e+01 5.723685747553906111e+01
-5.620838353743001647e+01 4.320838353743001647e+01 3.220838353743001647e+01 2.320838353743001647e+01 1.620838353743001647e+01 1.120838353743001825e+01 8.208383537430018251e+00 7.208383537430018251e+00 8.208383537430018251e+00 1.120838353743001825e+01 1.620838353743001647e+01 2.320838353743001647e+01 3.220838353743001647e+01 4.320838353743001647e+01 5.620838353743001647e+01
-5.525424218031631085e+01 4.225424218031631085e+01 3.125424218031631085e+01 2.225424218031631085e+01 1.525424218031631263e+01 1.025424218031631263e+01 7.254242180316312627e+00 6.254242180316312627e+00 7.254242180316312627e+00 1.025424218031631263e+01 1.525424218031631263e+01 2.225424218031631085e+01 3.125424218031631085e+01 4.225424218031631085e+01 5.525424218031631085e+01
-5.437347957957132394e+01 4.137347957957132394e+01 3.037347957957132749e+01 2.137347957957132749e+01 1.437347957957132749e+01 9.373479579571327491e+00 6.373479579571327491e+00 5.373479579571327491e+00 6.373479579571327491e+00 9.373479579571327491e+00 1.437347957957132749e+01 2.137347957957132749e+01 3.037347957957132749e+01 4.137347957957132394e+01 5.437347957957132394e+01
-5.356508953101232606e+01 4.056508953101232606e+01 2.956508953101232251e+01 2.056508953101232251e+01 1.356508953101232251e+01 8.565089531012322510e+00 5.565089531012323398e+00 4.565089531012323398e+00 5.565089531012323398e+00 8.565089531012322510e+00 1.356508953101232251e+01 2.056508953101232251e+01 2.956508953101232251e+01 4.056508953101232606e+01 5.356508953101232606e+01
-5.282800649180018837e+01 3.982800649180018837e+01 2.882800649180018837e+01 1.982800649180018837e+01 1.282800649180019015e+01 7.828006491800190148e+00 4.828006491800190148e+00 3.828006491800189703e+00 4.828006491800190148e+00 7.828006491800190148e+00 1.282800649180019015e+01 1.982800649180018837e+01 2.882800649180018837e+01 3.982800649180018837e+01 5.282800649180018837e+01
-5.216109706584683892e+01 3.916109706584683892e+01 2.816109706584683892e+01 1.916109706584683892e+01 1.216109706584683892e+01 7.161097065846838916e+00 4.161097065846838916e+00 3.161097065846838916e+00 4.161097065846838916e+00 7.161097065846838916e+00 1.216109706584683892e+01 1.916109706584683892e+01 2.816109706584683892e+01 3.916109706584683892e+01 5.216109706584683892e+01
-5.156314941990773093e+01 3.856314941990773093e+01 2.756314941990773448e+01 1.856314941990773448e+01 1.156314941990773448e+01 6.563149419907734483e+00 3.563149419907734483e+00 2.563149419907734483e+00 3.563149419907734483e+00 6.563149419907734483e+00 1.156314941990773448e+01 1.856314941990773448e+01 2.756314941990773448e+01 3.856314941990773093e+01 5.156314941990773093e+01
-5.103285988116120819e+01 3.803285988116120819e+01 2.703285988116120819e+01 1.803285988116120819e+01 1.103285988116120819e+01 6.032859881161208193e+00 3.032859881161208193e+00 2.032859881161208193e+00 3.032859881161208193e+00 6.032859881161208193e+00 1.103285988116120819e+01 1.803285988116120819e+01 2.703285988116120819e+01 3.803285988116120819e+01 5.103285988116120819e+01
-5.056881558724105474e+01 3.756881558724105474e+01 2.656881558724105119e+01 1.756881558724105119e+01 1.056881558724105297e+01 5.568815587241052967e+00 2.568815587241052523e+00 1.568815587241052523e+00 2.568815587241052523e+00 5.568815587241052967e+00 1.056881558724105297e+01 1.756881558724105119e+01 2.656881558724105119e+01 3.756881558724105474e+01 5.056881558724105474e+01
-5.016947141871401072e+01 3.716947141871401072e+01 2.616947141871401072e+01 1.716947141871401072e+01 1.016947141871401072e+01 5.169471418714009836e+00 2.169471418714009836e+00 1.169471418714009836e+00 2.169471418714009836e+00 5.169471418714009836e+00 1.016947141871401072e+01 1.716947141871401072e+01 2.616947141871401072e+01 3.716947141871401072e+01 5.016947141871401072e+01
-4.983311830193446923e+01 3.683311830193446923e+01 2.583311830193446923e+01 1.683311830193446923e+01 9.833118301934469230e+00 4.833118301934469230e+00 1.833118301934468786e+00 8.331183019344687857e-01 1.833118301934468786e+00 4.833118301934469230e+00 9.833118301934469230e+00 1.683311830193446923e+01 2.583311830193446923e+01 3.683311830193446923e+01 4.983311830193446923e+01
-4.955783779282820234e+01 3.655783779282820234e+01 2.555783779282820234e+01 1.655783779282820234e+01 9.557837792828202339e+00 4.557837792828203227e+00 1.557837792828203005e+00 5.578377928282030052e-01 1.557837792828203005e+00 4.557837792828203227e+00 9.557837792828202339e+00 1.655783779282820234e+01 2.555783779282820234e+01 3.655783779282820234e+01 4.955783779282820234e+01
-4.934143332329510656e+01 3.634143332329510656e+01 2.534143332329511011e+01 1.634143332329511011e+01 9.341433323295110114e+00 4.341433323295109226e+00 1.341433323295109670e+00 3.414333232951095587e-01 1.341433323295109670e+00 4.341433323295109226e+00 9.341433323295110114e+00 1.634143332329511011e+01 2.534143332329511011e+01 3.634143332329510656e+01 4.934143332329510656e+01
-4.918131790176033746e+01 3.618131790176033746e+01 2.518131790176034102e+01 1.618131790176034102e+01 9.181317901760341016e+00 4.181317901760341016e+00 1.181317901760340572e+00 1.813179017603405996e-01 1.181317901760340572e+00 4.181317901760341016e+00 9.181317901760341016e+00 1.618131790176034102e+01 2.518131790176034102e+01 3.618131790176033746e+01 4.918131790176033746e+01
-4.907430874298065504e+01 3.607430874298065504e+01 2.507430874298065504e+01 1.607430874298065504e+01 9.074308742980656817e+00 4.074308742980655929e+00 1.074308742980656373e+00 7.430874298065631711e-02 1.074308742980656373e+00 4.074308742980655929e+00 9.074308742980656817e+00 1.607430874298065504e+01 2.507430874298065504e+01 3.607430874298065504e+01 4.907430874298065504e+01
-4.901617237951490580e+01 3.601617237951490580e+01 2.501617237951490935e+01 1.601617237951490935e+01 9.016172379514909352e+00 4.016172379514909352e+00 1.016172379514909352e+00 1.617237951490931719e-02 1.016172379514909352e+00 4.016172379514909352e+00 9.016172379514909352e+00 1.601617237951490935e+01 2.501617237951490935e+01 3.601617237951490580e+01 4.901617237951490580e+01
-4.900000000000000000e+01 3.600000000000000000e+01 2.500000000000000000e+01 1.600000000000000000e+01 9.000000000000000000e+00 4.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 4.000000000000000000e+00 9.000000000000000000e+00 1.600000000000000000e+01 2.500000000000000000e+01 3.600000000000000000e+01 4.900000000000000000e+01
+ncols 15
+nrows 50
+xllcorner 0.0
+yllcorner 0.0
+cellsize 10.0
+1.335678521165119719e+02 1.205678521165119861e+02 1.095678521165119861e+02 1.005678521165119861e+02 9.356785211651198608e+01 8.856785211651198608e+01 8.556785211651198608e+01 8.456785211651198608e+01 8.556785211651198608e+01 8.856785211651198608e+01 9.356785211651198608e+01 1.005678521165119861e+02 1.095678521165119861e+02 1.205678521165119861e+02 1.335678521165119719e+02
+1.298173575747255200e+02 1.168173575747255200e+02 1.058173575747255200e+02 9.681735757472551995e+01 8.981735757472551995e+01 8.481735757472551995e+01 8.181735757472551995e+01 8.081735757472551995e+01 8.181735757472551995e+01 8.481735757472551995e+01 8.981735757472551995e+01 9.681735757472551995e+01 1.058173575747255200e+02 1.168173575747255200e+02 1.298173575747255200e+02
+1.261594657192227231e+02 1.131594657192227231e+02 1.021594657192227231e+02 9.315946571922272312e+01 8.615946571922272312e+01 8.115946571922272312e+01 7.815946571922272312e+01 7.715946571922272312e+01 7.815946571922272312e+01 8.115946571922272312e+01 8.615946571922272312e+01 9.315946571922272312e+01 1.021594657192227231e+02 1.131594657192227231e+02 1.261594657192227231e+02
+1.225937874263653100e+02 1.095937874263653100e+02 9.859378742636531001e+01 8.959378742636531001e+01 8.259378742636531001e+01 7.759378742636531001e+01 7.459378742636531001e+01 7.359378742636531001e+01 7.459378742636531001e+01 7.759378742636531001e+01 8.259378742636531001e+01 8.959378742636531001e+01 9.859378742636531001e+01 1.095937874263653100e+02 1.225937874263653100e+02
+1.191199268908159752e+02 1.061199268908159752e+02 9.511992689081597518e+01 8.611992689081597518e+01 7.911992689081597518e+01 7.411992689081597518e+01 7.111992689081597518e+01 7.011992689081597518e+01 7.111992689081597518e+01 7.411992689081597518e+01 7.911992689081597518e+01 8.611992689081597518e+01 9.511992689081597518e+01 1.061199268908159752e+02 1.191199268908159752e+02
+1.157374813616942220e+02 1.027374813616942220e+02 9.173748136169422196e+01 8.273748136169422196e+01 7.573748136169422196e+01 7.073748136169422196e+01 6.773748136169422196e+01 6.673748136169422196e+01 6.773748136169422196e+01 7.073748136169422196e+01 7.573748136169422196e+01 8.273748136169422196e+01 9.173748136169422196e+01 1.027374813616942220e+02 1.157374813616942220e+02
+1.124460408621596343e+02 9.944604086215963434e+01 8.844604086215963434e+01 7.944604086215963434e+01 7.244604086215963434e+01 6.744604086215963434e+01 6.444604086215963434e+01 6.344604086215964145e+01 6.444604086215963434e+01 6.744604086215963434e+01 7.244604086215963434e+01 7.944604086215963434e+01 8.844604086215963434e+01 9.944604086215963434e+01 1.124460408621596343e+02
+1.092451878909776610e+02 9.624518789097766103e+01 8.524518789097766103e+01 7.624518789097766103e+01 6.924518789097766103e+01 6.424518789097766103e+01 6.124518789097766103e+01 6.024518789097766103e+01 6.124518789097766103e+01 6.424518789097766103e+01 6.924518789097766103e+01 7.624518789097766103e+01 8.524518789097766103e+01 9.624518789097766103e+01 1.092451878909776610e+02
+1.061344971044590153e+02 9.313449710445901530e+01 8.213449710445901530e+01 7.313449710445901530e+01 6.613449710445901530e+01 6.113449710445901530e+01 5.813449710445901530e+01 5.713449710445901530e+01 5.813449710445901530e+01 6.113449710445901530e+01 6.613449710445901530e+01 7.313449710445901530e+01 8.213449710445901530e+01 9.313449710445901530e+01 1.061344971044590153e+02
+1.031135349769793663e+02 9.011353497697936632e+01 7.911353497697936632e+01 7.011353497697936632e+01 6.311353497697936632e+01 5.811353497697936632e+01 5.511353497697936632e+01 5.411353497697936632e+01 5.511353497697936632e+01 5.811353497697936632e+01 6.311353497697936632e+01 7.011353497697936632e+01 7.911353497697936632e+01 9.011353497697936632e+01 1.031135349769793663e+02
+1.001818594380724932e+02 8.718185943807249316e+01 7.618185943807249316e+01 6.718185943807249316e+01 6.018185943807249316e+01 5.518185943807249316e+01 5.218185943807249316e+01 5.118185943807249316e+01 5.218185943807249316e+01 5.518185943807249316e+01 6.018185943807249316e+01 6.718185943807249316e+01 7.618185943807249316e+01 8.718185943807249316e+01 1.001818594380724932e+02
+9.733901948384726666e+01 8.433901948384726666e+01 7.333901948384726666e+01 6.433901948384726666e+01 5.733901948384725955e+01 5.233901948384725955e+01 4.933901948384725955e+01 4.833901948384725955e+01 4.933901948384725955e+01 5.233901948384725955e+01 5.733901948384725955e+01 6.433901948384726666e+01 7.333901948384726666e+01 8.433901948384726666e+01 9.733901948384726666e+01
+9.458455476019886987e+01 8.158455476019886987e+01 7.058455476019886987e+01 6.158455476019886987e+01 5.458455476019886987e+01 4.958455476019886987e+01 4.658455476019886987e+01 4.558455476019886987e+01 4.658455476019886987e+01 4.958455476019886987e+01 5.458455476019886987e+01 6.158455476019886987e+01 7.058455476019886987e+01 8.158455476019886987e+01 9.458455476019886987e+01
+9.191799511496095931e+01 7.891799511496095931e+01 6.791799511496095931e+01 5.891799511496095931e+01 5.191799511496095931e+01 4.691799511496095931e+01 4.391799511496095931e+01 4.291799511496095931e+01 4.391799511496095931e+01 4.691799511496095931e+01 5.191799511496095931e+01 5.891799511496095931e+01 6.791799511496095931e+01 7.891799511496095931e+01 9.191799511496095931e+01
+8.933886011577118325e+01 7.633886011577118325e+01 6.533886011577118325e+01 5.633886011577119035e+01 4.933886011577119035e+01 4.433886011577119035e+01 4.133886011577119035e+01 4.033886011577119035e+01 4.133886011577119035e+01 4.433886011577119035e+01 4.933886011577119035e+01 5.633886011577119035e+01 6.533886011577118325e+01 7.633886011577118325e+01 8.933886011577118325e+01
+8.684665852998699620e+01 7.384665852998699620e+01 6.284665852998700331e+01 5.384665852998700331e+01 4.684665852998700331e+01 4.184665852998700331e+01 3.884665852998700331e+01 3.784665852998700331e+01 3.884665852998700331e+01 4.184665852998700331e+01 4.684665852998700331e+01 5.384665852998700331e+01 6.284665852998700331e+01 7.384665852998699620e+01 8.684665852998699620e+01
+8.444088776247913586e+01 7.144088776247913586e+01 6.044088776247913586e+01 5.144088776247913586e+01 4.444088776247913586e+01 3.944088776247913586e+01 3.644088776247913586e+01 3.544088776247913586e+01 3.644088776247913586e+01 3.944088776247913586e+01 4.444088776247913586e+01 5.144088776247913586e+01 6.044088776247913586e+01 7.144088776247913586e+01 8.444088776247913586e+01
+8.212103324653428160e+01 6.912103324653428160e+01 5.812103324653428160e+01 4.912103324653428160e+01 4.212103324653428160e+01 3.712103324653428160e+01 3.412103324653428160e+01 3.312103324653428160e+01 3.412103324653428160e+01 3.712103324653428160e+01 4.212103324653428160e+01 4.912103324653428160e+01 5.812103324653428160e+01 6.912103324653428160e+01 8.212103324653428160e+01
+7.988656778239459300e+01 6.688656778239459300e+01 5.588656778239459300e+01 4.688656778239459300e+01 3.988656778239459300e+01 3.488656778239459300e+01 3.188656778239458944e+01 3.088656778239458944e+01 3.188656778239458944e+01 3.488656778239459300e+01 3.988656778239459300e+01 4.688656778239459300e+01 5.588656778239459300e+01 6.688656778239459300e+01 7.988656778239459300e+01
+7.773695081712966726e+01 6.473695081712966726e+01 5.373695081712967436e+01 4.473695081712967436e+01 3.773695081712967436e+01 3.273695081712967436e+01 2.973695081712967436e+01 2.873695081712967436e+01 2.973695081712967436e+01 3.273695081712967436e+01 3.773695081712967436e+01 4.473695081712967436e+01 5.373695081712967436e+01 6.473695081712966726e+01 7.773695081712966726e+01
+7.567162765854615714e+01 6.267162765854615714e+01 5.167162765854615714e+01 4.267162765854615714e+01 3.567162765854615714e+01 3.067162765854616069e+01 2.767162765854616069e+01 2.667162765854616069e+01 2.767162765854616069e+01 3.067162765854616069e+01 3.567162765854615714e+01 4.267162765854615714e+01 5.167162765854615714e+01 6.267162765854615714e+01 7.567162765854615714e+01
+7.369002861465497745e+01 6.069002861465497034e+01 4.969002861465497034e+01 4.069002861465497034e+01 3.369002861465497034e+01 2.869002861465497034e+01 2.569002861465497034e+01 2.469002861465497034e+01 2.569002861465497034e+01 2.869002861465497034e+01 3.369002861465497034e+01 4.069002861465497034e+01 4.969002861465497034e+01 6.069002861465497034e+01 7.369002861465497745e+01
+7.179156804879076503e+01 5.879156804879076503e+01 4.779156804879076503e+01 3.879156804879076503e+01 3.179156804879076148e+01 2.679156804879076148e+01 2.379156804879076148e+01 2.279156804879076148e+01 2.379156804879076148e+01 2.679156804879076148e+01 3.179156804879076148e+01 3.879156804879076503e+01 4.779156804879076503e+01 5.879156804879076503e+01 7.179156804879076503e+01
+6.997564333875216391e+01 5.697564333875216391e+01 4.597564333875216391e+01 3.697564333875216391e+01 2.997564333875216747e+01 2.497564333875216747e+01 2.197564333875216747e+01 2.097564333875216747e+01 2.197564333875216747e+01 2.497564333875216747e+01 2.997564333875216747e+01 3.697564333875216391e+01 4.597564333875216391e+01 5.697564333875216391e+01 6.997564333875216391e+01
+6.824163372622820134e+01 5.524163372622819423e+01 4.424163372622819423e+01 3.524163372622819423e+01 2.824163372622819423e+01 2.324163372622819423e+01 2.024163372622819423e+01 1.924163372622819423e+01 2.024163372622819423e+01 2.324163372622819423e+01 2.824163372622819423e+01 3.524163372622819423e+01 4.424163372622819423e+01 5.524163372622819423e+01 6.824163372622820134e+01
+6.658889904019540040e+01 5.358889904019540040e+01 4.258889904019540040e+01 3.358889904019540040e+01 2.658889904019539685e+01 2.158889904019539685e+01 1.858889904019539685e+01 1.758889904019539685e+01 1.858889904019539685e+01 2.158889904019539685e+01 2.658889904019539685e+01 3.358889904019540040e+01 4.258889904019540040e+01 5.358889904019540040e+01 6.658889904019540040e+01
+6.501677827477938365e+01 5.201677827477938365e+01 4.101677827477938365e+01 3.201677827477938365e+01 2.501677827477938365e+01 2.001677827477938365e+01 1.701677827477938365e+01 1.601677827477938365e+01 1.701677827477938365e+01 2.001677827477938365e+01 2.501677827477938365e+01 3.201677827477938365e+01 4.101677827477938365e+01 5.201677827477938365e+01 6.501677827477938365e+01
+6.352458799809687662e+01 5.052458799809687662e+01 3.952458799809687662e+01 3.052458799809687306e+01 2.352458799809687306e+01 1.852458799809687306e+01 1.552458799809687306e+01 1.452458799809687306e+01 1.552458799809687306e+01 1.852458799809687306e+01 2.352458799809687306e+01 3.052458799809687306e+01 3.952458799809687662e+01 5.052458799809687662e+01 6.352458799809687662e+01
+6.211162056359285799e+01 4.911162056359285799e+01 3.811162056359285799e+01 2.911162056359285799e+01 2.211162056359285799e+01 1.711162056359285799e+01 1.411162056359285977e+01 1.311162056359285977e+01 1.411162056359285977e+01 1.711162056359285799e+01 2.211162056359285799e+01 2.911162056359285799e+01 3.811162056359285799e+01 4.911162056359285799e+01 6.211162056359285799e+01
+6.077714208903847748e+01 4.777714208903847748e+01 3.677714208903847748e+01 2.777714208903847748e+01 2.077714208903847748e+01 1.577714208903847748e+01 1.277714208903847748e+01 1.177714208903847748e+01 1.277714208903847748e+01 1.577714208903847748e+01 2.077714208903847748e+01 2.777714208903847748e+01 3.677714208903847748e+01 4.777714208903847748e+01 6.077714208903847748e+01
+5.952039016021139162e+01 4.652039016021139162e+01 3.552039016021139162e+01 2.652039016021139162e+01 1.952039016021139162e+01 1.452039016021138984e+01 1.152039016021138984e+01 1.052039016021138984e+01 1.152039016021138984e+01 1.452039016021138984e+01 1.952039016021139162e+01 2.652039016021139162e+01 3.552039016021139162e+01 4.652039016021139162e+01 5.952039016021139162e+01
+5.834057120571738864e+01 4.534057120571738864e+01 3.434057120571738864e+01 2.534057120571738864e+01 1.834057120571738864e+01 1.334057120571739041e+01 1.034057120571739041e+01 9.340571205717390413e+00 1.034057120571739041e+01 1.334057120571739041e+01 1.834057120571738864e+01 2.534057120571738864e+01 3.434057120571738864e+01 4.534057120571738864e+01 5.834057120571738864e+01
+5.723685747553906111e+01 4.423685747553906111e+01 3.323685747553906111e+01 2.423685747553906111e+01 1.723685747553906111e+01 1.223685747553906111e+01 9.236857475539061113e+00 8.236857475539061113e+00 9.236857475539061113e+00 1.223685747553906111e+01 1.723685747553906111e+01 2.423685747553906111e+01 3.323685747553906111e+01 4.423685747553906111e+01 5.723685747553906111e+01
+5.620838353743001647e+01 4.320838353743001647e+01 3.220838353743001647e+01 2.320838353743001647e+01 1.620838353743001647e+01 1.120838353743001825e+01 8.208383537430018251e+00 7.208383537430018251e+00 8.208383537430018251e+00 1.120838353743001825e+01 1.620838353743001647e+01 2.320838353743001647e+01 3.220838353743001647e+01 4.320838353743001647e+01 5.620838353743001647e+01
+5.525424218031631085e+01 4.225424218031631085e+01 3.125424218031631085e+01 2.225424218031631085e+01 1.525424218031631263e+01 1.025424218031631263e+01 7.254242180316312627e+00 6.254242180316312627e+00 7.254242180316312627e+00 1.025424218031631263e+01 1.525424218031631263e+01 2.225424218031631085e+01 3.125424218031631085e+01 4.225424218031631085e+01 5.525424218031631085e+01
+5.437347957957132394e+01 4.137347957957132394e+01 3.037347957957132749e+01 2.137347957957132749e+01 1.437347957957132749e+01 9.373479579571327491e+00 6.373479579571327491e+00 5.373479579571327491e+00 6.373479579571327491e+00 9.373479579571327491e+00 1.437347957957132749e+01 2.137347957957132749e+01 3.037347957957132749e+01 4.137347957957132394e+01 5.437347957957132394e+01
+5.356508953101232606e+01 4.056508953101232606e+01 2.956508953101232251e+01 2.056508953101232251e+01 1.356508953101232251e+01 8.565089531012322510e+00 5.565089531012323398e+00 4.565089531012323398e+00 5.565089531012323398e+00 8.565089531012322510e+00 1.356508953101232251e+01 2.056508953101232251e+01 2.956508953101232251e+01 4.056508953101232606e+01 5.356508953101232606e+01
+5.282800649180018837e+01 3.982800649180018837e+01 2.882800649180018837e+01 1.982800649180018837e+01 1.282800649180019015e+01 7.828006491800190148e+00 4.828006491800190148e+00 3.828006491800189703e+00 4.828006491800190148e+00 7.828006491800190148e+00 1.282800649180019015e+01 1.982800649180018837e+01 2.882800649180018837e+01 3.982800649180018837e+01 5.282800649180018837e+01
+5.216109706584683892e+01 3.916109706584683892e+01 2.816109706584683892e+01 1.916109706584683892e+01 1.216109706584683892e+01 7.161097065846838916e+00 4.161097065846838916e+00 3.161097065846838916e+00 4.161097065846838916e+00 7.161097065846838916e+00 1.216109706584683892e+01 1.916109706584683892e+01 2.816109706584683892e+01 3.916109706584683892e+01 5.216109706584683892e+01
+5.156314941990773093e+01 3.856314941990773093e+01 2.756314941990773448e+01 1.856314941990773448e+01 1.156314941990773448e+01 6.563149419907734483e+00 3.563149419907734483e+00 2.563149419907734483e+00 3.563149419907734483e+00 6.563149419907734483e+00 1.156314941990773448e+01 1.856314941990773448e+01 2.756314941990773448e+01 3.856314941990773093e+01 5.156314941990773093e+01
+5.103285988116120819e+01 3.803285988116120819e+01 2.703285988116120819e+01 1.803285988116120819e+01 1.103285988116120819e+01 6.032859881161208193e+00 3.032859881161208193e+00 2.032859881161208193e+00 3.032859881161208193e+00 6.032859881161208193e+00 1.103285988116120819e+01 1.803285988116120819e+01 2.703285988116120819e+01 3.803285988116120819e+01 5.103285988116120819e+01
+5.056881558724105474e+01 3.756881558724105474e+01 2.656881558724105119e+01 1.756881558724105119e+01 1.056881558724105297e+01 5.568815587241052967e+00 2.568815587241052523e+00 1.568815587241052523e+00 2.568815587241052523e+00 5.568815587241052967e+00 1.056881558724105297e+01 1.756881558724105119e+01 2.656881558724105119e+01 3.756881558724105474e+01 5.056881558724105474e+01
+5.016947141871401072e+01 3.716947141871401072e+01 2.616947141871401072e+01 1.716947141871401072e+01 1.016947141871401072e+01 5.169471418714009836e+00 2.169471418714009836e+00 1.169471418714009836e+00 2.169471418714009836e+00 5.169471418714009836e+00 1.016947141871401072e+01 1.716947141871401072e+01 2.616947141871401072e+01 3.716947141871401072e+01 5.016947141871401072e+01
+4.983311830193446923e+01 3.683311830193446923e+01 2.583311830193446923e+01 1.683311830193446923e+01 9.833118301934469230e+00 4.833118301934469230e+00 1.833118301934468786e+00 8.331183019344687857e-01 1.833118301934468786e+00 4.833118301934469230e+00 9.833118301934469230e+00 1.683311830193446923e+01 2.583311830193446923e+01 3.683311830193446923e+01 4.983311830193446923e+01
+4.955783779282820234e+01 3.655783779282820234e+01 2.555783779282820234e+01 1.655783779282820234e+01 9.557837792828202339e+00 4.557837792828203227e+00 1.557837792828203005e+00 5.578377928282030052e-01 1.557837792828203005e+00 4.557837792828203227e+00 9.557837792828202339e+00 1.655783779282820234e+01 2.555783779282820234e+01 3.655783779282820234e+01 4.955783779282820234e+01
+4.934143332329510656e+01 3.634143332329510656e+01 2.534143332329511011e+01 1.634143332329511011e+01 9.341433323295110114e+00 4.341433323295109226e+00 1.341433323295109670e+00 3.414333232951095587e-01 1.341433323295109670e+00 4.341433323295109226e+00 9.341433323295110114e+00 1.634143332329511011e+01 2.534143332329511011e+01 3.634143332329510656e+01 4.934143332329510656e+01
+4.918131790176033746e+01 3.618131790176033746e+01 2.518131790176034102e+01 1.618131790176034102e+01 9.181317901760341016e+00 4.181317901760341016e+00 1.181317901760340572e+00 1.813179017603405996e-01 1.181317901760340572e+00 4.181317901760341016e+00 9.181317901760341016e+00 1.618131790176034102e+01 2.518131790176034102e+01 3.618131790176033746e+01 4.918131790176033746e+01
+4.907430874298065504e+01 3.607430874298065504e+01 2.507430874298065504e+01 1.607430874298065504e+01 9.074308742980656817e+00 4.074308742980655929e+00 1.074308742980656373e+00 7.430874298065631711e-02 1.074308742980656373e+00 4.074308742980655929e+00 9.074308742980656817e+00 1.607430874298065504e+01 2.507430874298065504e+01 3.607430874298065504e+01 4.907430874298065504e+01
+4.901617237951490580e+01 3.601617237951490580e+01 2.501617237951490935e+01 1.601617237951490935e+01 9.016172379514909352e+00 4.016172379514909352e+00 1.016172379514909352e+00 1.617237951490931719e-02 1.016172379514909352e+00 4.016172379514909352e+00 9.016172379514909352e+00 1.601617237951490935e+01 2.501617237951490935e+01 3.601617237951490580e+01 4.901617237951490580e+01
+4.900000000000000000e+01 3.600000000000000000e+01 2.500000000000000000e+01 1.600000000000000000e+01 9.000000000000000000e+00 4.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 4.000000000000000000e+00 9.000000000000000000e+00 1.600000000000000000e+01 2.500000000000000000e+01 3.600000000000000000e+01 4.900000000000000000e+01
diff --git a/docs/source/tutorials/mass_wasting_runout/E_VariableConvergenceConcave.asc b/docs/source/tutorials/mass_wasting_runout/E_VariableConvergenceConcave.asc
index 5f35e39d3a..dda2bc0331 100644
--- a/docs/source/tutorials/mass_wasting_runout/E_VariableConvergenceConcave.asc
+++ b/docs/source/tutorials/mass_wasting_runout/E_VariableConvergenceConcave.asc
@@ -1,55 +1,55 @@
-ncols 15
-nrows 50
-xllcorner 0.0
-yllcorner 0.0
-cellsize 10.0
-1.335678521165119719e+02 1.205678521165119861e+02 1.095678521165119861e+02 1.005678521165119861e+02 9.356785211651198608e+01 8.856785211651198608e+01 8.556785211651198608e+01 8.456785211651198608e+01 8.556785211651198608e+01 8.856785211651198608e+01 9.356785211651198608e+01 1.005678521165119861e+02 1.095678521165119861e+02 1.205678521165119861e+02 1.335678521165119719e+02
-1.288173575747255200e+02 1.160826636971744961e+02 1.053071534930928692e+02 9.649082696248062518e+01 8.963368410533776398e+01 8.473572492166429981e+01 8.179694941146021847e+01 8.081735757472551995e+01 8.179694941146021847e+01 8.473572492166429981e+01 8.963368410533776398e+01 9.649082696248062518e+01 1.053071534930928692e+02 1.160826636971744961e+02 1.288173575747255200e+02
-1.241594657192227231e+02 1.116900779641206896e+02 1.011390575559574216e+02 9.250640449473293359e+01 8.579211878044721118e+01 8.099620041310026863e+01 7.811864939269210595e+01 7.715946571922272312e+01 7.811864939269210595e+01 8.099620041310026863e+01 8.579211878044721118e+01 9.250640449473293359e+01 1.011390575559574216e+02 1.116900779641206896e+02 1.241594657192227231e+02
-1.195937874263653100e+02 1.073897057937122383e+02 9.706317518146735779e+01 8.861419558963061149e+01 8.204276701820204210e+01 7.734888946718163538e+01 7.453256293656939135e+01 7.359378742636531001e+01 7.453256293656939135e+01 7.734888946718163538e+01 8.204276701820204210e+01 8.861419558963061149e+01 9.706317518146735779e+01 1.073897057937122383e+02 1.195937874263653100e+02
-1.151199268908159752e+02 1.031811513806118938e+02 9.307911056428537222e+01 8.481380444183638190e+01 7.838523301326495130e+01 7.379339627857108042e+01 7.103829423775475504e+01 7.011992689081597518e+01 7.103829423775475504e+01 7.379339627857108042e+01 7.838523301326495130e+01 8.481380444183638190e+01 9.307911056428537222e+01 1.031811513806118938e+02 1.151199268908159752e+02
-1.107374813616942220e+02 9.906401197393913094e+01 8.918646095353095404e+01 8.110482830046973390e+01 7.481911401475544210e+01 7.032931809638809284e+01 6.763544054536768613e+01 6.673748136169422196e+01 6.763544054536768613e+01 7.032931809638809284e+01 7.481911401475544210e+01 8.110482830046973390e+01 8.918646095353095404e+01 9.906401197393913094e+01 1.107374813616942220e+02
-1.064460408621596343e+02 9.503787759685351944e+01 8.538481637236372990e+01 7.748685718869025152e+01 7.134400004583311272e+01 6.695624494379229930e+01 6.432359188256781124e+01 6.344604086215964145e+01 6.432359188256781124e+01 6.695624494379229930e+01 7.134400004583311272e+01 7.748685718869025152e+01 8.538481637236372990e+01 9.503787759685351944e+01 1.064460408621596343e+02
-1.022451878909776610e+02 9.110233074812052223e+01 8.167375931954909163e+01 7.395947360526338343e+01 6.795947360526336922e+01 6.367375931954909163e+01 6.110233074812051512e+01 6.024518789097766103e+01 6.110233074812051512e+01 6.367375931954909163e+01 6.795947360526336922e+01 7.395947360526338343e+01 8.167375931954909163e+01 9.110233074812052223e+01 1.022451878909776610e+02
-9.813449710445902952e+01 8.725694608405085262e+01 7.805286445139779516e+01 7.052225220649982873e+01 6.466510934935698174e+01 6.048143587996921866e+01 5.797123179833656792e+01 5.713449710445901530e+01 5.797123179833656792e+01 6.048143587996921866e+01 6.466510934935698174e+01 7.052225220649982873e+01 7.805286445139779516e+01 8.725694608405085262e+01 9.813449710445902952e+01
-9.411353497697936632e+01 8.350129007902017975e+01 7.452169824228549544e+01 6.717475946677528498e+01 6.146047375248956968e+01 5.737884109942834243e+01 5.492986150759161035e+01 5.411353497697936632e+01 5.492986150759161035e+01 5.737884109942834243e+01 6.146047375248956968e+01 6.717475946677528498e+01 7.452169824228549544e+01 8.350129007902017975e+01 9.411353497697936632e+01
-9.018185943807249316e+01 7.983492066256229691e+01 7.107981862174595733e+01 6.391655331562351705e+01 5.834512474419494055e+01 5.436553290746024913e+01 5.197777780541942860e+01 5.118185943807249316e+01 5.197777780541942860e+01 5.436553290746024913e+01 5.834512474419494055e+01 6.391655331562351705e+01 7.107981862174595733e+01 7.983492066256229691e+01 9.018185943807249316e+01
-8.633901948384726666e+01 7.625738683078603231e+01 6.772677458588808008e+01 6.074718274915338156e+01 5.531861132058195096e+01 5.144106030017378828e+01 4.911452968792889351e+01 4.833901948384725955e+01 4.911452968792889351e+01 5.144106030017378828e+01 5.531861132058195096e+01 6.074718274915338156e+01 6.772677458588808008e+01 7.625738683078603231e+01 8.633901948384726666e+01
-8.258455476019886987e+01 7.276822822958662584e+01 6.446210578060703256e+01 5.766618741326009001e+01 5.238047312754580531e+01 4.860496292346417846e+01 4.633965680101519524e+01 4.558455476019886987e+01 4.633965680101519524e+01 4.860496292346417846e+01 5.238047312754580531e+01 5.766618741326009001e+01 6.446210578060703256e+01 7.276822822958662584e+01 8.258455476019886987e+01
-7.891799511496095931e+01 6.936697470679769140e+01 6.128534205373647126e+01 5.467309715577728468e+01 4.953024001292014589e+01 4.585677062516504066e+01 4.365268899251198320e+01 4.291799511496095931e+01 4.365268899251198320e+01 4.585677062516504066e+01 4.953024001292014589e+01 5.467309715577728468e+01 6.128534205373647126e+01 6.936697470679769140e+01 7.891799511496095931e+01
-7.533886011577118325e+01 6.605314583005690565e+01 5.819600297291404445e+01 5.176743154434262095e+01 4.676743154434262095e+01 4.319600297291404445e+01 4.105314583005690565e+01 4.033886011577119035e+01 4.105314583005690565e+01 4.319600297291404445e+01 4.676743154434262095e+01 5.176743154434262095e+01 5.819600297291404445e+01 6.605314583005690565e+01 7.533886011577118325e+01
-7.184665852998699620e+01 6.282625036672169472e+01 5.519359730549720666e+01 4.894869934631353203e+01 4.409155648917067793e+01 4.062216873406863726e+01 3.854053608100741002e+01 3.784665852998700331e+01 3.854053608100741002e+01 4.062216873406863726e+01 4.409155648917067793e+01 4.894869934631353203e+01 5.519359730549720666e+01 6.282625036672169472e+01 7.184665852998699620e+01
-6.844088776247913586e+01 5.968578572166281049e+01 5.227762245635668847e+01 4.621639796656076982e+01 4.150211225227505452e+01 3.813476531349954257e+01 3.611435715023424109e+01 3.544088776247913586e+01 3.611435715023424109e+01 3.813476531349954257e+01 4.150211225227505452e+01 4.621639796656076982e+01 5.227762245635668847e+01 5.968578572166281049e+01 6.844088776247913586e+01
-6.512103324653428160e+01 5.663123732816693234e+01 4.944756385877917637e+01 4.357001283837101369e+01 3.899858426694244429e+01 3.573327814449346818e+01 3.377409447102407825e+01 3.312103324653428160e+01 3.377409447102407825e+01 3.573327814449346818e+01 3.899858426694244429e+01 4.357001283837101369e+01 4.944756385877917637e+01 5.663123732816693234e+01 6.512103324653428160e+01
-6.188656778239459300e+01 5.366207798647621985e+01 4.670289431300683702e+01 4.100901676198643031e+01 3.658044533341499971e+01 3.341718002729254522e+01 3.151922084361908105e+01 3.088656778239458944e+01 3.151922084361908105e+01 3.341718002729254522e+01 3.658044533341499971e+01 4.100901676198643031e+01 4.670289431300683702e+01 5.366207798647621985e+01 6.188656778239459300e+01
-5.873695081712968147e+01 5.077776714366028443e+01 4.404307326610926765e+01 3.853286918447660980e+01 3.424715489876232510e+01 3.118593040896641000e+01 2.934919571508885738e+01 2.873695081712967436e+01 2.934919571508885738e+01 3.118593040896641000e+01 3.424715489876232510e+01 3.853286918447660980e+01 4.404307326610926765e+01 5.077776714366028443e+01 5.873695081712968147e+01
-5.567162765854615714e+01 4.797775010752575042e+01 4.146754602589309968e+01 3.614101541364820491e+01 3.199815827079105901e+01 2.903897459732166908e+01 2.726346439324003867e+01 2.667162765854616069e+01 2.726346439324003867e+01 2.903897459732166908e+01 3.199815827079105901e+01 3.614101541364820491e+01 4.146754602589309968e+01 4.797775010752575042e+01 5.567162765854615714e+01
-5.269002861465497034e+01 4.526145718608354684e+01 3.897574290036925504e+01 3.383288575751211624e+01 2.983288575751211269e+01 2.697574290036925504e+01 2.526145718608354329e+01 2.469002861465497034e+01 2.526145718608354329e+01 2.697574290036925504e+01 2.983288575751211269e+01 3.383288575751211624e+01 3.897574290036925504e+01 4.526145718608354684e+01 5.269002861465497034e+01
-4.979156804879075793e+01 4.262830274266831054e+01 3.656707825287239189e+01 3.160789457940300551e+01 2.775075172226014786e+01 2.499564968144382249e+01 2.334258845695402584e+01 2.279156804879076148e+01 2.334258845695402584e+01 2.499564968144382249e+01 2.775075172226014786e+01 3.160789457940300551e+01 3.656707825287239189e+01 4.262830274266831054e+01 4.979156804879075793e+01
-4.697564333875216391e+01 4.007768415507869975e+01 3.424094946120114713e+01 2.946543925711951317e+01 2.575115354283380142e+01 2.309809231834400478e+01 2.150625558365012679e+01 2.097564333875216747e+01 2.150625558365012679e+01 2.309809231834400478e+01 2.575115354283380142e+01 2.946543925711951317e+01 3.424094946120114713e+01 4.007768415507869975e+01 4.697564333875216391e+01
-4.424163372622820134e+01 3.760898066500370618e+01 3.199673576704451960e+01 2.740489903235064162e+01 2.383347046092207222e+01 2.128245005275880786e+01 1.975183780786084853e+01 1.924163372622819423e+01 1.975183780786084853e+01 2.128245005275880786e+01 2.383347046092207222e+01 2.740489903235064162e+01 3.199673576704451960e+01 3.760898066500370618e+01 4.424163372622820134e+01
-4.158889904019540040e+01 3.522155210141988846e+01 2.983379699937906793e+01 2.542563373407294591e+01 2.199706230550151886e+01 1.954808271366478323e+01 1.807869495856274256e+01 1.758889904019539685e+01 1.807869495856274256e+01 1.954808271366478323e+01 2.199706230550151886e+01 2.542563373407294591e+01 2.983379699937906793e+01 3.522155210141988846e+01 4.158889904019540040e+01
-3.901677827477938365e+01 3.291473745845284782e+01 2.775147215233040399e+01 2.352698235641203439e+01 2.024126807069774969e+01 1.789432929518754634e+01 1.648616602988142432e+01 1.601677827477938365e+01 1.648616602988142432e+01 1.789432929518754634e+01 2.024126807069774969e+01 2.352698235641203439e+01 2.775147215233040399e+01 3.291473745845284782e+01 3.901677827477938365e+01
-3.652458799809687662e+01 3.068785330421932400e+01 2.574907779401524266e+01 2.170826146748462904e+01 1.856540432462748669e+01 1.632050636544381206e+01 1.497356758993360693e+01 1.452458799809687306e+01 1.497356758993360693e+01 1.632050636544381206e+01 1.856540432462748669e+01 2.170826146748462904e+01 2.574907779401524266e+01 3.068785330421932400e+01 3.652458799809687662e+01
-3.411162056359285799e+01 2.854019199216428859e+01 2.382590627787857329e+01 1.996876342073571919e+01 1.696876342073571564e+01 1.482590627787857329e+01 1.354019199216428859e+01 1.311162056359285977e+01 1.354019199216428859e+01 1.482590627787857329e+01 1.696876342073571564e+01 1.996876342073571919e+01 2.382590627787857329e+01 2.854019199216428859e+01 3.411162056359285799e+01
-3.177714208903848103e+01 2.647101964005888775e+01 2.198122372169154204e+01 1.830775433393643681e+01 1.545061147679357916e+01 1.340979515026296731e+01 1.218530535434459949e+01 1.177714208903847748e+01 1.218530535434459949e+01 1.340979515026296731e+01 1.545061147679357916e+01 1.830775433393643681e+01 2.198122372169154204e+01 2.647101964005888775e+01 3.177714208903848103e+01
-2.952039016021139162e+01 2.447957383368077799e+01 2.021426771123179833e+01 1.672447179286444907e+01 1.401018607857873732e+01 1.207141056837465598e+01 1.090814526225220682e+01 1.052039016021138984e+01 1.090814526225220682e+01 1.207141056837465598e+01 1.401018607857873732e+01 1.672447179286444907e+01 2.021426771123179833e+01 2.447957383368077799e+01 2.952039016021139162e+01
-2.734057120571738864e+01 2.256506100163575823e+01 1.852424467510514461e+01 1.521812222612555487e+01 1.264669365469698192e+01 1.080995896081943108e+01 9.707918144492900581e+00 9.340571205717390413e+00 9.707918144492900581e+00 1.080995896081943108e+01 1.264669365469698192e+01 1.521812222612555487e+01 1.852424467510514461e+01 2.256506100163575823e+01 2.734057120571738864e+01
-2.523685747553906111e+01 2.072665339390641037e+01 1.691032686329416279e+01 1.378787788370232548e+01 1.135930645513089843e+01 9.624612577579878092e+00 8.583796251049264470e+00 8.236857475539061113e+00 8.583796251049264470e+00 9.624612577579878092e+00 1.135930645513089843e+01 1.378787788370232548e+01 1.691032686329416279e+01 2.072665339390641037e+01 2.523685747553906111e+01
-2.320838353743001647e+01 1.896348557824634184e+01 1.537164884355246564e+01 1.243287333334838607e+01 1.014715904763409959e+01 8.514505986409609761e+00 7.534914149674916573e+00 7.208383537430018251e+00 7.534914149674916573e+00 8.514505986409609761e+00 1.014715904763409959e+01 1.243287333334838607e+01 1.537164884355246564e+01 1.896348557824634184e+01 2.320838353743001647e+01
-2.125424218031631440e+01 1.727465034358161944e+01 1.390730340480610927e+01 1.115220136398978212e+01 9.009344221132639774e+00 7.478731976234680445e+00 6.560364629295904138e+00 6.254242180316312627e+00 6.560364629295904138e+00 7.478731976234680445e+00 9.009344221132639774e+00 1.115220136398978212e+01 1.390730340480610927e+01 1.727465034358161944e+01 2.125424218031631440e+01
-1.937347957957132749e+01 1.565919386528561397e+01 1.251633672242846984e+01 9.944908150999898666e+00 7.944908150999898666e+00 6.516336722428469841e+00 5.659193865285613079e+00 5.373479579571327491e+00 5.659193865285613079e+00 6.516336722428469841e+00 7.944908150999898666e+00 9.944908150999898666e+00 1.251633672242846984e+01 1.565919386528561397e+01 1.937347957957132749e+01
-1.756508953101232251e+01 1.411610993917559043e+01 1.119774259223681412e+01 8.809987490195997140e+00 6.952844633053139489e+00 5.626314020808242056e+00 4.830395653461303063e+00 4.565089531012323398e+00 4.830395653461303063e+00 5.626314020808242056e+00 6.952844633053139489e+00 8.809987490195997140e+00 1.119774259223681412e+01 1.411610993917559043e+01 1.756508953101232251e+01
-1.582800649180019015e+01 1.264433302241243418e+01 9.950455471392025686e+00 7.746373838738964679e+00 6.032088124453251154e+00 4.807598328534883336e+00 4.072904450983863001e+00 3.828006491800189703e+00 4.072904450983863001e+00 4.807598328534883336e+00 6.032088124453251154e+00 7.746373838738964679e+00 9.950455471392025686e+00 1.264433302241243418e+01 1.582800649180019015e+01
-1.416109706584683892e+01 1.124272971890806438e+01 8.773341963806021937e+00 6.752933800540716902e+00 5.181505229112145727e+00 4.059056249520308413e+00 3.385586861765206290e+00 3.161097065846838916e+00 3.385586861765206290e+00 4.059056249520308413e+00 5.181505229112145727e+00 6.752933800540716902e+00 8.773341963806021937e+00 1.124272971890806438e+01 1.416109706584683892e+01
-1.256314941990773626e+01 9.910088195417939616e+00 7.665190236234265875e+00 5.828455542356714147e+00 4.399884113785285322e+00 3.379475950519979399e+00 2.767231052560795490e+00 2.563149419907734483e+00 2.767231052560795490e+00 3.379475950519979399e+00 4.399884113785285322e+00 5.828455542356714147e+00 7.665190236234265875e+00 9.910088195417939616e+00 1.256314941990773626e+01
-1.103285988116120819e+01 8.645104779120391214e+00 6.624696615855086179e+00 4.971635391365289536e+00 3.685921105651003948e+00 2.767553758712228529e+00 2.216533350548963277e+00 2.032859881161208193e+00 2.216533350548963277e+00 2.767553758712228529e+00 3.685921105651003948e+00 4.971635391365289536e+00 6.624696615855086179e+00 8.645104779120391214e+00 1.103285988116120819e+01
-9.568815587241051190e+00 7.446366607649215652e+00 5.650448240302276659e+00 4.181060485200235988e+00 3.038203342343093194e+00 2.221876811730848278e+00 1.732080893363501461e+00 1.568815587241052523e+00 1.732080893363501461e+00 2.221876811730848278e+00 3.038203342343093194e+00 4.181060485200235988e+00 5.650448240302276659e+00 7.446366607649215652e+00 9.568815587241051190e+00
-8.169471418714010724e+00 6.312328561571153074e+00 4.740899990142581899e+00 3.455185704428295423e+00 2.455185704428295423e+00 1.740899990142581233e+00 1.312328561571152630e+00 1.169471418714009836e+00 1.312328561571152630e+00 1.740899990142581233e+00 2.455185704428295423e+00 3.455185704428295423e+00 4.740899990142581899e+00 6.312328561571153074e+00 8.169471418714010724e+00
-6.833118301934469230e+00 5.241281567240591244e+00 3.894342791730386999e+00 2.792301975403856495e+00 1.935159118260999289e+00 1.322914220301815824e+00 9.555672815263055453e-01 8.331183019344687857e-01 9.555672815263055453e-01 1.322914220301815824e+00 1.935159118260999289e+00 2.792301975403856495e+00 3.894342791730386999e+00 5.241281567240591244e+00 6.833118301934469230e+00
-5.557837792828204115e+00 4.231307180583305794e+00 3.108858200991468479e+00 2.190490854052693059e+00 1.476205139766978647e+00 9.660010581343254632e-01 6.598786091547336197e-01 5.578377928282030052e-01 6.598786091547336197e-01 9.660010581343254632e-01 1.476205139766978647e+00 2.190490854052693059e+00 3.108858200991468479e+00 4.231307180583305794e+00 5.557837792828204115e+00
-4.341433323295109226e+00 3.280208833499191012e+00 2.382249649825721516e+00 1.647555772274701180e+00 1.076127200846130005e+00 6.679639355400075473e-01 4.230659763563340281e-01 3.414333232951095587e-01 4.230659763563340281e-01 6.679639355400075473e-01 1.076127200846130005e+00 1.647555772274701180e+00 2.382249649825721516e+00 3.280208833499191012e+00 4.341433323295109226e+00
-3.181317901760340572e+00 2.385399534413401579e+00 1.711930146658299678e+00 1.160909738495034427e+00 7.323383099236058236e-01 4.262158609440140911e-01 2.425423915562589516e-01 1.813179017603405996e-01 2.425423915562589516e-01 4.262158609440140911e-01 7.323383099236058236e-01 1.160909738495034427e+00 1.711930146658299678e+00 2.385399534413401579e+00 3.181317901760340572e+00
-2.074308742980655929e+00 1.543696498082697044e+00 1.094716906245962296e+00 7.273699674704521279e-01 4.416556817561664849e-01 2.375740491031052837e-01 1.151250695112685518e-01 7.430874298065631711e-02 1.151250695112685518e-01 2.375740491031052837e-01 4.416556817561664849e-01 7.273699674704521279e-01 1.094716906245962296e+00 1.543696498082697044e+00 2.074308742980655929e+00
-1.016172379514909130e+00 7.508662570659296875e-01 5.263764611475623134e-01 3.427029917598072295e-01 1.998458489026644080e-01 9.780503257613379353e-02 3.658054278021544148e-02 1.617237951490931719e-02 3.658054278021544148e-02 9.780503257613379353e-02 1.998458489026644080e-01 3.427029917598072295e-01 5.263764611475623134e-01 7.508662570659296875e-01 1.016172379514909130e+00
-0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00
+ncols 15
+nrows 50
+xllcorner 0.0
+yllcorner 0.0
+cellsize 10.0
+1.335678521165119719e+02 1.205678521165119861e+02 1.095678521165119861e+02 1.005678521165119861e+02 9.356785211651198608e+01 8.856785211651198608e+01 8.556785211651198608e+01 8.456785211651198608e+01 8.556785211651198608e+01 8.856785211651198608e+01 9.356785211651198608e+01 1.005678521165119861e+02 1.095678521165119861e+02 1.205678521165119861e+02 1.335678521165119719e+02
+1.288173575747255200e+02 1.160826636971744961e+02 1.053071534930928692e+02 9.649082696248062518e+01 8.963368410533776398e+01 8.473572492166429981e+01 8.179694941146021847e+01 8.081735757472551995e+01 8.179694941146021847e+01 8.473572492166429981e+01 8.963368410533776398e+01 9.649082696248062518e+01 1.053071534930928692e+02 1.160826636971744961e+02 1.288173575747255200e+02
+1.241594657192227231e+02 1.116900779641206896e+02 1.011390575559574216e+02 9.250640449473293359e+01 8.579211878044721118e+01 8.099620041310026863e+01 7.811864939269210595e+01 7.715946571922272312e+01 7.811864939269210595e+01 8.099620041310026863e+01 8.579211878044721118e+01 9.250640449473293359e+01 1.011390575559574216e+02 1.116900779641206896e+02 1.241594657192227231e+02
+1.195937874263653100e+02 1.073897057937122383e+02 9.706317518146735779e+01 8.861419558963061149e+01 8.204276701820204210e+01 7.734888946718163538e+01 7.453256293656939135e+01 7.359378742636531001e+01 7.453256293656939135e+01 7.734888946718163538e+01 8.204276701820204210e+01 8.861419558963061149e+01 9.706317518146735779e+01 1.073897057937122383e+02 1.195937874263653100e+02
+1.151199268908159752e+02 1.031811513806118938e+02 9.307911056428537222e+01 8.481380444183638190e+01 7.838523301326495130e+01 7.379339627857108042e+01 7.103829423775475504e+01 7.011992689081597518e+01 7.103829423775475504e+01 7.379339627857108042e+01 7.838523301326495130e+01 8.481380444183638190e+01 9.307911056428537222e+01 1.031811513806118938e+02 1.151199268908159752e+02
+1.107374813616942220e+02 9.906401197393913094e+01 8.918646095353095404e+01 8.110482830046973390e+01 7.481911401475544210e+01 7.032931809638809284e+01 6.763544054536768613e+01 6.673748136169422196e+01 6.763544054536768613e+01 7.032931809638809284e+01 7.481911401475544210e+01 8.110482830046973390e+01 8.918646095353095404e+01 9.906401197393913094e+01 1.107374813616942220e+02
+1.064460408621596343e+02 9.503787759685351944e+01 8.538481637236372990e+01 7.748685718869025152e+01 7.134400004583311272e+01 6.695624494379229930e+01 6.432359188256781124e+01 6.344604086215964145e+01 6.432359188256781124e+01 6.695624494379229930e+01 7.134400004583311272e+01 7.748685718869025152e+01 8.538481637236372990e+01 9.503787759685351944e+01 1.064460408621596343e+02
+1.022451878909776610e+02 9.110233074812052223e+01 8.167375931954909163e+01 7.395947360526338343e+01 6.795947360526336922e+01 6.367375931954909163e+01 6.110233074812051512e+01 6.024518789097766103e+01 6.110233074812051512e+01 6.367375931954909163e+01 6.795947360526336922e+01 7.395947360526338343e+01 8.167375931954909163e+01 9.110233074812052223e+01 1.022451878909776610e+02
+9.813449710445902952e+01 8.725694608405085262e+01 7.805286445139779516e+01 7.052225220649982873e+01 6.466510934935698174e+01 6.048143587996921866e+01 5.797123179833656792e+01 5.713449710445901530e+01 5.797123179833656792e+01 6.048143587996921866e+01 6.466510934935698174e+01 7.052225220649982873e+01 7.805286445139779516e+01 8.725694608405085262e+01 9.813449710445902952e+01
+9.411353497697936632e+01 8.350129007902017975e+01 7.452169824228549544e+01 6.717475946677528498e+01 6.146047375248956968e+01 5.737884109942834243e+01 5.492986150759161035e+01 5.411353497697936632e+01 5.492986150759161035e+01 5.737884109942834243e+01 6.146047375248956968e+01 6.717475946677528498e+01 7.452169824228549544e+01 8.350129007902017975e+01 9.411353497697936632e+01
+9.018185943807249316e+01 7.983492066256229691e+01 7.107981862174595733e+01 6.391655331562351705e+01 5.834512474419494055e+01 5.436553290746024913e+01 5.197777780541942860e+01 5.118185943807249316e+01 5.197777780541942860e+01 5.436553290746024913e+01 5.834512474419494055e+01 6.391655331562351705e+01 7.107981862174595733e+01 7.983492066256229691e+01 9.018185943807249316e+01
+8.633901948384726666e+01 7.625738683078603231e+01 6.772677458588808008e+01 6.074718274915338156e+01 5.531861132058195096e+01 5.144106030017378828e+01 4.911452968792889351e+01 4.833901948384725955e+01 4.911452968792889351e+01 5.144106030017378828e+01 5.531861132058195096e+01 6.074718274915338156e+01 6.772677458588808008e+01 7.625738683078603231e+01 8.633901948384726666e+01
+8.258455476019886987e+01 7.276822822958662584e+01 6.446210578060703256e+01 5.766618741326009001e+01 5.238047312754580531e+01 4.860496292346417846e+01 4.633965680101519524e+01 4.558455476019886987e+01 4.633965680101519524e+01 4.860496292346417846e+01 5.238047312754580531e+01 5.766618741326009001e+01 6.446210578060703256e+01 7.276822822958662584e+01 8.258455476019886987e+01
+7.891799511496095931e+01 6.936697470679769140e+01 6.128534205373647126e+01 5.467309715577728468e+01 4.953024001292014589e+01 4.585677062516504066e+01 4.365268899251198320e+01 4.291799511496095931e+01 4.365268899251198320e+01 4.585677062516504066e+01 4.953024001292014589e+01 5.467309715577728468e+01 6.128534205373647126e+01 6.936697470679769140e+01 7.891799511496095931e+01
+7.533886011577118325e+01 6.605314583005690565e+01 5.819600297291404445e+01 5.176743154434262095e+01 4.676743154434262095e+01 4.319600297291404445e+01 4.105314583005690565e+01 4.033886011577119035e+01 4.105314583005690565e+01 4.319600297291404445e+01 4.676743154434262095e+01 5.176743154434262095e+01 5.819600297291404445e+01 6.605314583005690565e+01 7.533886011577118325e+01
+7.184665852998699620e+01 6.282625036672169472e+01 5.519359730549720666e+01 4.894869934631353203e+01 4.409155648917067793e+01 4.062216873406863726e+01 3.854053608100741002e+01 3.784665852998700331e+01 3.854053608100741002e+01 4.062216873406863726e+01 4.409155648917067793e+01 4.894869934631353203e+01 5.519359730549720666e+01 6.282625036672169472e+01 7.184665852998699620e+01
+6.844088776247913586e+01 5.968578572166281049e+01 5.227762245635668847e+01 4.621639796656076982e+01 4.150211225227505452e+01 3.813476531349954257e+01 3.611435715023424109e+01 3.544088776247913586e+01 3.611435715023424109e+01 3.813476531349954257e+01 4.150211225227505452e+01 4.621639796656076982e+01 5.227762245635668847e+01 5.968578572166281049e+01 6.844088776247913586e+01
+6.512103324653428160e+01 5.663123732816693234e+01 4.944756385877917637e+01 4.357001283837101369e+01 3.899858426694244429e+01 3.573327814449346818e+01 3.377409447102407825e+01 3.312103324653428160e+01 3.377409447102407825e+01 3.573327814449346818e+01 3.899858426694244429e+01 4.357001283837101369e+01 4.944756385877917637e+01 5.663123732816693234e+01 6.512103324653428160e+01
+6.188656778239459300e+01 5.366207798647621985e+01 4.670289431300683702e+01 4.100901676198643031e+01 3.658044533341499971e+01 3.341718002729254522e+01 3.151922084361908105e+01 3.088656778239458944e+01 3.151922084361908105e+01 3.341718002729254522e+01 3.658044533341499971e+01 4.100901676198643031e+01 4.670289431300683702e+01 5.366207798647621985e+01 6.188656778239459300e+01
+5.873695081712968147e+01 5.077776714366028443e+01 4.404307326610926765e+01 3.853286918447660980e+01 3.424715489876232510e+01 3.118593040896641000e+01 2.934919571508885738e+01 2.873695081712967436e+01 2.934919571508885738e+01 3.118593040896641000e+01 3.424715489876232510e+01 3.853286918447660980e+01 4.404307326610926765e+01 5.077776714366028443e+01 5.873695081712968147e+01
+5.567162765854615714e+01 4.797775010752575042e+01 4.146754602589309968e+01 3.614101541364820491e+01 3.199815827079105901e+01 2.903897459732166908e+01 2.726346439324003867e+01 2.667162765854616069e+01 2.726346439324003867e+01 2.903897459732166908e+01 3.199815827079105901e+01 3.614101541364820491e+01 4.146754602589309968e+01 4.797775010752575042e+01 5.567162765854615714e+01
+5.269002861465497034e+01 4.526145718608354684e+01 3.897574290036925504e+01 3.383288575751211624e+01 2.983288575751211269e+01 2.697574290036925504e+01 2.526145718608354329e+01 2.469002861465497034e+01 2.526145718608354329e+01 2.697574290036925504e+01 2.983288575751211269e+01 3.383288575751211624e+01 3.897574290036925504e+01 4.526145718608354684e+01 5.269002861465497034e+01
+4.979156804879075793e+01 4.262830274266831054e+01 3.656707825287239189e+01 3.160789457940300551e+01 2.775075172226014786e+01 2.499564968144382249e+01 2.334258845695402584e+01 2.279156804879076148e+01 2.334258845695402584e+01 2.499564968144382249e+01 2.775075172226014786e+01 3.160789457940300551e+01 3.656707825287239189e+01 4.262830274266831054e+01 4.979156804879075793e+01
+4.697564333875216391e+01 4.007768415507869975e+01 3.424094946120114713e+01 2.946543925711951317e+01 2.575115354283380142e+01 2.309809231834400478e+01 2.150625558365012679e+01 2.097564333875216747e+01 2.150625558365012679e+01 2.309809231834400478e+01 2.575115354283380142e+01 2.946543925711951317e+01 3.424094946120114713e+01 4.007768415507869975e+01 4.697564333875216391e+01
+4.424163372622820134e+01 3.760898066500370618e+01 3.199673576704451960e+01 2.740489903235064162e+01 2.383347046092207222e+01 2.128245005275880786e+01 1.975183780786084853e+01 1.924163372622819423e+01 1.975183780786084853e+01 2.128245005275880786e+01 2.383347046092207222e+01 2.740489903235064162e+01 3.199673576704451960e+01 3.760898066500370618e+01 4.424163372622820134e+01
+4.158889904019540040e+01 3.522155210141988846e+01 2.983379699937906793e+01 2.542563373407294591e+01 2.199706230550151886e+01 1.954808271366478323e+01 1.807869495856274256e+01 1.758889904019539685e+01 1.807869495856274256e+01 1.954808271366478323e+01 2.199706230550151886e+01 2.542563373407294591e+01 2.983379699937906793e+01 3.522155210141988846e+01 4.158889904019540040e+01
+3.901677827477938365e+01 3.291473745845284782e+01 2.775147215233040399e+01 2.352698235641203439e+01 2.024126807069774969e+01 1.789432929518754634e+01 1.648616602988142432e+01 1.601677827477938365e+01 1.648616602988142432e+01 1.789432929518754634e+01 2.024126807069774969e+01 2.352698235641203439e+01 2.775147215233040399e+01 3.291473745845284782e+01 3.901677827477938365e+01
+3.652458799809687662e+01 3.068785330421932400e+01 2.574907779401524266e+01 2.170826146748462904e+01 1.856540432462748669e+01 1.632050636544381206e+01 1.497356758993360693e+01 1.452458799809687306e+01 1.497356758993360693e+01 1.632050636544381206e+01 1.856540432462748669e+01 2.170826146748462904e+01 2.574907779401524266e+01 3.068785330421932400e+01 3.652458799809687662e+01
+3.411162056359285799e+01 2.854019199216428859e+01 2.382590627787857329e+01 1.996876342073571919e+01 1.696876342073571564e+01 1.482590627787857329e+01 1.354019199216428859e+01 1.311162056359285977e+01 1.354019199216428859e+01 1.482590627787857329e+01 1.696876342073571564e+01 1.996876342073571919e+01 2.382590627787857329e+01 2.854019199216428859e+01 3.411162056359285799e+01
+3.177714208903848103e+01 2.647101964005888775e+01 2.198122372169154204e+01 1.830775433393643681e+01 1.545061147679357916e+01 1.340979515026296731e+01 1.218530535434459949e+01 1.177714208903847748e+01 1.218530535434459949e+01 1.340979515026296731e+01 1.545061147679357916e+01 1.830775433393643681e+01 2.198122372169154204e+01 2.647101964005888775e+01 3.177714208903848103e+01
+2.952039016021139162e+01 2.447957383368077799e+01 2.021426771123179833e+01 1.672447179286444907e+01 1.401018607857873732e+01 1.207141056837465598e+01 1.090814526225220682e+01 1.052039016021138984e+01 1.090814526225220682e+01 1.207141056837465598e+01 1.401018607857873732e+01 1.672447179286444907e+01 2.021426771123179833e+01 2.447957383368077799e+01 2.952039016021139162e+01
+2.734057120571738864e+01 2.256506100163575823e+01 1.852424467510514461e+01 1.521812222612555487e+01 1.264669365469698192e+01 1.080995896081943108e+01 9.707918144492900581e+00 9.340571205717390413e+00 9.707918144492900581e+00 1.080995896081943108e+01 1.264669365469698192e+01 1.521812222612555487e+01 1.852424467510514461e+01 2.256506100163575823e+01 2.734057120571738864e+01
+2.523685747553906111e+01 2.072665339390641037e+01 1.691032686329416279e+01 1.378787788370232548e+01 1.135930645513089843e+01 9.624612577579878092e+00 8.583796251049264470e+00 8.236857475539061113e+00 8.583796251049264470e+00 9.624612577579878092e+00 1.135930645513089843e+01 1.378787788370232548e+01 1.691032686329416279e+01 2.072665339390641037e+01 2.523685747553906111e+01
+2.320838353743001647e+01 1.896348557824634184e+01 1.537164884355246564e+01 1.243287333334838607e+01 1.014715904763409959e+01 8.514505986409609761e+00 7.534914149674916573e+00 7.208383537430018251e+00 7.534914149674916573e+00 8.514505986409609761e+00 1.014715904763409959e+01 1.243287333334838607e+01 1.537164884355246564e+01 1.896348557824634184e+01 2.320838353743001647e+01
+2.125424218031631440e+01 1.727465034358161944e+01 1.390730340480610927e+01 1.115220136398978212e+01 9.009344221132639774e+00 7.478731976234680445e+00 6.560364629295904138e+00 6.254242180316312627e+00 6.560364629295904138e+00 7.478731976234680445e+00 9.009344221132639774e+00 1.115220136398978212e+01 1.390730340480610927e+01 1.727465034358161944e+01 2.125424218031631440e+01
+1.937347957957132749e+01 1.565919386528561397e+01 1.251633672242846984e+01 9.944908150999898666e+00 7.944908150999898666e+00 6.516336722428469841e+00 5.659193865285613079e+00 5.373479579571327491e+00 5.659193865285613079e+00 6.516336722428469841e+00 7.944908150999898666e+00 9.944908150999898666e+00 1.251633672242846984e+01 1.565919386528561397e+01 1.937347957957132749e+01
+1.756508953101232251e+01 1.411610993917559043e+01 1.119774259223681412e+01 8.809987490195997140e+00 6.952844633053139489e+00 5.626314020808242056e+00 4.830395653461303063e+00 4.565089531012323398e+00 4.830395653461303063e+00 5.626314020808242056e+00 6.952844633053139489e+00 8.809987490195997140e+00 1.119774259223681412e+01 1.411610993917559043e+01 1.756508953101232251e+01
+1.582800649180019015e+01 1.264433302241243418e+01 9.950455471392025686e+00 7.746373838738964679e+00 6.032088124453251154e+00 4.807598328534883336e+00 4.072904450983863001e+00 3.828006491800189703e+00 4.072904450983863001e+00 4.807598328534883336e+00 6.032088124453251154e+00 7.746373838738964679e+00 9.950455471392025686e+00 1.264433302241243418e+01 1.582800649180019015e+01
+1.416109706584683892e+01 1.124272971890806438e+01 8.773341963806021937e+00 6.752933800540716902e+00 5.181505229112145727e+00 4.059056249520308413e+00 3.385586861765206290e+00 3.161097065846838916e+00 3.385586861765206290e+00 4.059056249520308413e+00 5.181505229112145727e+00 6.752933800540716902e+00 8.773341963806021937e+00 1.124272971890806438e+01 1.416109706584683892e+01
+1.256314941990773626e+01 9.910088195417939616e+00 7.665190236234265875e+00 5.828455542356714147e+00 4.399884113785285322e+00 3.379475950519979399e+00 2.767231052560795490e+00 2.563149419907734483e+00 2.767231052560795490e+00 3.379475950519979399e+00 4.399884113785285322e+00 5.828455542356714147e+00 7.665190236234265875e+00 9.910088195417939616e+00 1.256314941990773626e+01
+1.103285988116120819e+01 8.645104779120391214e+00 6.624696615855086179e+00 4.971635391365289536e+00 3.685921105651003948e+00 2.767553758712228529e+00 2.216533350548963277e+00 2.032859881161208193e+00 2.216533350548963277e+00 2.767553758712228529e+00 3.685921105651003948e+00 4.971635391365289536e+00 6.624696615855086179e+00 8.645104779120391214e+00 1.103285988116120819e+01
+9.568815587241051190e+00 7.446366607649215652e+00 5.650448240302276659e+00 4.181060485200235988e+00 3.038203342343093194e+00 2.221876811730848278e+00 1.732080893363501461e+00 1.568815587241052523e+00 1.732080893363501461e+00 2.221876811730848278e+00 3.038203342343093194e+00 4.181060485200235988e+00 5.650448240302276659e+00 7.446366607649215652e+00 9.568815587241051190e+00
+8.169471418714010724e+00 6.312328561571153074e+00 4.740899990142581899e+00 3.455185704428295423e+00 2.455185704428295423e+00 1.740899990142581233e+00 1.312328561571152630e+00 1.169471418714009836e+00 1.312328561571152630e+00 1.740899990142581233e+00 2.455185704428295423e+00 3.455185704428295423e+00 4.740899990142581899e+00 6.312328561571153074e+00 8.169471418714010724e+00
+6.833118301934469230e+00 5.241281567240591244e+00 3.894342791730386999e+00 2.792301975403856495e+00 1.935159118260999289e+00 1.322914220301815824e+00 9.555672815263055453e-01 8.331183019344687857e-01 9.555672815263055453e-01 1.322914220301815824e+00 1.935159118260999289e+00 2.792301975403856495e+00 3.894342791730386999e+00 5.241281567240591244e+00 6.833118301934469230e+00
+5.557837792828204115e+00 4.231307180583305794e+00 3.108858200991468479e+00 2.190490854052693059e+00 1.476205139766978647e+00 9.660010581343254632e-01 6.598786091547336197e-01 5.578377928282030052e-01 6.598786091547336197e-01 9.660010581343254632e-01 1.476205139766978647e+00 2.190490854052693059e+00 3.108858200991468479e+00 4.231307180583305794e+00 5.557837792828204115e+00
+4.341433323295109226e+00 3.280208833499191012e+00 2.382249649825721516e+00 1.647555772274701180e+00 1.076127200846130005e+00 6.679639355400075473e-01 4.230659763563340281e-01 3.414333232951095587e-01 4.230659763563340281e-01 6.679639355400075473e-01 1.076127200846130005e+00 1.647555772274701180e+00 2.382249649825721516e+00 3.280208833499191012e+00 4.341433323295109226e+00
+3.181317901760340572e+00 2.385399534413401579e+00 1.711930146658299678e+00 1.160909738495034427e+00 7.323383099236058236e-01 4.262158609440140911e-01 2.425423915562589516e-01 1.813179017603405996e-01 2.425423915562589516e-01 4.262158609440140911e-01 7.323383099236058236e-01 1.160909738495034427e+00 1.711930146658299678e+00 2.385399534413401579e+00 3.181317901760340572e+00
+2.074308742980655929e+00 1.543696498082697044e+00 1.094716906245962296e+00 7.273699674704521279e-01 4.416556817561664849e-01 2.375740491031052837e-01 1.151250695112685518e-01 7.430874298065631711e-02 1.151250695112685518e-01 2.375740491031052837e-01 4.416556817561664849e-01 7.273699674704521279e-01 1.094716906245962296e+00 1.543696498082697044e+00 2.074308742980655929e+00
+1.016172379514909130e+00 7.508662570659296875e-01 5.263764611475623134e-01 3.427029917598072295e-01 1.998458489026644080e-01 9.780503257613379353e-02 3.658054278021544148e-02 1.617237951490931719e-02 3.658054278021544148e-02 9.780503257613379353e-02 1.998458489026644080e-01 3.427029917598072295e-01 5.263764611475623134e-01 7.508662570659296875e-01 1.016172379514909130e+00
+0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00
diff --git a/docs/source/tutorials/mass_wasting_runout/F_VaryConvergenceConvex.asc b/docs/source/tutorials/mass_wasting_runout/F_VaryConvergenceConvex.asc
index 0e5c3b22b5..7269d1941b 100644
--- a/docs/source/tutorials/mass_wasting_runout/F_VaryConvergenceConvex.asc
+++ b/docs/source/tutorials/mass_wasting_runout/F_VaryConvergenceConvex.asc
@@ -1,55 +1,55 @@
-ncols 15
-nrows 50
-xllcorner 0.0
-yllcorner 0.0
-cellsize 10.0
-1.409607808342839235e+02 1.279607808342839093e+02 1.169607808342839093e+02 1.079607808342839093e+02 1.009607808342839093e+02 9.596078083428390926e+01 9.296078083428390926e+01 9.196078083428390926e+01 9.296078083428390926e+01 9.596078083428390926e+01 1.009607808342839093e+02 1.079607808342839093e+02 1.169607808342839093e+02 1.279607808342839093e+02 1.409607808342839235e+02
-1.388300900165792768e+02 1.260953961390282672e+02 1.153198859349466403e+02 1.065035594043343963e+02 9.964641654719153507e+01 9.474845736351807091e+01 9.180968185331398956e+01 9.083009001657929105e+01 9.180968185331398956e+01 9.474845736351807091e+01 9.964641654719153507e+01 1.065035594043343963e+02 1.153198859349466403e+02 1.260953961390282672e+02 1.388300900165792768e+02
-1.366899365810845097e+02 1.242205488259824904e+02 1.136695284178192225e+02 1.050368753565947344e+02 9.832258964230901199e+01 9.352667127496206945e+01 9.064912025455390676e+01 8.968993658108452394e+01 9.064912025455390676e+01 9.352667127496206945e+01 9.832258964230901199e+01 1.050368753565947344e+02 1.136695284178192225e+02 1.242205488259824904e+02 1.366899365810845097e+02
-1.345400374172721740e+02 1.223359557846191024e+02 1.120094251723742218e+02 1.035604455805374755e+02 9.698901700910890611e+01 9.229513945808849940e+01 8.947881292747625537e+01 8.854003741727217403e+01 8.947881292747625537e+01 9.229513945808849940e+01 9.698901700910890611e+01 1.035604455805374755e+02 1.120094251723742218e+02 1.223359557846191024e+02 1.345400374172721740e+02
-1.323800945760021079e+02 1.204413190657980124e+02 1.103392782494714766e+02 1.020739721270225004e+02 9.564540069845106984e+01 9.105356396375719896e+01 8.829846192294087359e+01 8.738009457600209373e+01 8.829846192294087359e+01 9.105356396375719896e+01 9.564540069845106984e+01 1.020739721270225004e+02 1.103392782494714766e+02 1.204413190657980124e+02 1.323800945760021079e+02
-1.302097941430593551e+02 1.185363247553042640e+02 1.086587737348961014e+02 1.005771410818348812e+02 9.429142679612058942e+01 8.980163087775324016e+01 8.710775332673283344e+01 8.620979414305936928e+01 8.710775332673283344e+01 8.980163087775324016e+01 9.429142679612058942e+01 1.005771410818348812e+02 1.086587737348961014e+02 1.185363247553042640e+02 1.302097941430593551e+02
-1.280288049994908874e+02 1.166206417341847725e+02 1.069675805096949830e+02 9.906962132602151883e+01 9.292676418316436582e+01 8.853900908112355239e+01 8.590635601989906434e+01 8.502880499949090165e+01 8.590635601989906434e+01 8.853900908112355239e+01 9.292676418316436582e+01 9.906962132602151883e+01 1.069675805096949830e+02 1.166206417341847725e+02 1.280288049994908874e+02
-1.258367774544524877e+02 1.146939203115953489e+02 1.052653488830239183e+02 9.755106316873821015e+01 9.155106316873819594e+01 8.726534888302391835e+01 8.469392031159534895e+01 8.383677745445248775e+01 8.469392031159534895e+01 8.726534888302391835e+01 9.155106316873819594e+01 9.755106316873821015e+01 1.052653488830239183e+02 1.146939203115953489e+02 1.258367774544524877e+02
-1.236333417340885603e+02 1.127557907136803976e+02 1.035517090810273402e+02 9.602109683612937374e+01 9.016395397898652675e+01 8.598028050959877078e+01 8.347007642796610583e+01 8.263334173408856032e+01 8.347007642796610583e+01 8.598028050959877078e+01 9.016395397898652675e+01 9.602109683612937374e+01 1.035517090810273402e+02 1.127557907136803976e+02 1.236333417340885603e+02
-1.214181063073808673e+02 1.108058614094216807e+02 1.018262695726869964e+02 9.447933079717678595e+01 8.876504508289107775e+01 8.468341242982984340e+01 8.223443283799311132e+01 8.141810630738086729e+01 8.223443283799311132e+01 8.468341242982984340e+01 8.876504508289107775e+01 9.447933079717678595e+01 1.018262695726869964e+02 1.108058614094216807e+02 1.214181063073808673e+02
-1.191906560268354127e+02 1.088437172513252165e+02 1.000886152105088769e+02 9.292534990438643661e+01 8.735392133295786721e+01 8.337432949622316869e+01 8.098657439418235526e+01 8.019065602683541272e+01 8.098657439418235526e+01 8.337432949622316869e+01 8.735392133295786721e+01 9.292534990438643661e+01 1.000886152105088769e+02 1.088437172513252165e+02 1.191906560268354127e+02
-1.169505500582237545e+02 1.068689174051625344e+02 9.833830516026456792e+01 9.135871332352988361e+01 8.593014189495845301e+01 8.205259087455029032e+01 7.972606026230538134e+01 7.895055005822375449e+01 7.972606026230538134e+01 8.205259087455029032e+01 8.593014189495845301e+01 9.135871332352988361e+01 9.833830516026456792e+01 1.068689174051625344e+02 1.169505500582237545e+02
-1.146973195692267922e+02 1.048809930386145481e+02 9.657487058963495485e+01 8.977895222228801231e+01 8.449323793657373471e+01 8.071772773249209365e+01 7.845242161004311754e+01 7.769731956922679217e+01 7.845242161004311754e+01 8.071772773249209365e+01 8.449323793657373471e+01 8.977895222228801231e+01 9.657487058963495485e+01 1.048809930386145481e+02 1.146973195692267922e+02
-1.124304651415819620e+02 1.028794447334186941e+02 9.479781208035747397e+01 8.818556718239828740e+01 8.304271003954114860e+01 7.936924065178604337e+01 7.716515901913298592e+01 7.643046514158196203e+01 7.716515901913298592e+01 7.936924065178604337e+01 8.304271003954114860e+01 8.818556718239828740e+01 9.479781208035747397e+01 1.028794447334186941e+02 1.124304651415819620e+02
-1.101494538650013482e+02 1.008637395792870564e+02 9.300659672214420937e+01 8.657802529357277876e+01 8.157802529357277876e+01 7.800659672214420937e+01 7.586373957928705636e+01 7.514945386500134816e+01 7.586373957928705636e+01 7.800659672214420937e+01 8.157802529357277876e+01 8.657802529357277876e+01 9.300659672214420937e+01 1.008637395792870564e+02 1.101494538650013482e+02
-1.078537160634485588e+02 9.883330790018325729e+01 9.120065483895876923e+01 8.495575687977509460e+01 8.009861402263223340e+01 7.662922626753018562e+01 7.454759361446896548e+01 7.385371606344855877e+01 7.454759361446896548e+01 7.662922626753018562e+01 8.009861402263223340e+01 8.495575687977509460e+01 9.120065483895876923e+01 9.883330790018325729e+01 1.078537160634485588e+02
-1.055426415949973205e+02 9.678753955418099508e+01 8.937937628887488017e+01 8.331815179907894731e+01 7.860386608479323911e+01 7.523651914601772717e+01 7.321611098275242568e+01 7.254264159499732045e+01 7.321611098275242568e+01 7.523651914601772717e+01 7.860386608479323911e+01 8.331815179907894731e+01 8.937937628887488017e+01 9.678753955418099508e+01 1.055426415949973205e+02
-1.032155756550177870e+02 9.472577973665043771e+01 8.754210626726268174e+01 8.166455524685451905e+01 7.709312667542594966e+01 7.382782055297697354e+01 7.186863687950757651e+01 7.121557565501778697e+01 7.186863687950757651e+01 7.382782055297697354e+01 7.709312667542594966e+01 8.166455524685451905e+01 8.754210626726268174e+01 9.472577973665043771e+01 1.032155756550177870e+02
-1.008718139982837272e+02 9.264732420236535404e+01 8.568814052889597122e+01 7.999426297787556450e+01 7.556569154930413390e+01 7.240242624318167941e+01 7.050446705950821524e+01 6.987181399828372719e+01 7.050446705950821524e+01 7.240242624318167941e+01 7.556569154930413390e+01 7.999426297787556450e+01 8.568814052889597122e+01 9.264732420236535404e+01 1.008718139982837272e+02
-9.851059747803871858e+01 9.055141380456933575e+01 8.381671992701831186e+01 7.830651584538566112e+01 7.402080155967136932e+01 7.095957706987545066e+01 6.912284237599790515e+01 6.851059747803871858e+01 6.912284237599790515e+01 7.095957706987545066e+01 7.402080155967136932e+01 7.830651584538566112e+01 8.381671992701831186e+01 9.055141380456933575e+01 9.851059747803871858e+01
-9.613110577813931457e+01 8.843722822711890785e+01 8.192702414548625711e+01 7.660049353324134813e+01 7.245763639038420934e+01 6.949845271691482651e+01 6.772294251283318545e+01 6.713110577813931457e+01 6.772294251283318545e+01 6.949845271691482651e+01 7.245763639038420934e+01 7.660049353324134813e+01 8.192702414548625711e+01 8.843722822711890785e+01 9.613110577813931457e+01
-9.373245018683405760e+01 8.630387875826262700e+01 8.001816447254834941e+01 7.487530732969119640e+01 7.087530732969119640e+01 6.801816447254834941e+01 6.630387875826262700e+01 6.573245018683405760e+01 6.630387875826262700e+01 6.801816447254834941e+01 7.087530732969119640e+01 7.487530732969119640e+01 8.001816447254834941e+01 8.630387875826262700e+01 9.373245018683405760e+01
-9.131366522583319068e+01 8.415039991971073619e+01 7.808917542991481753e+01 7.312999175644543470e+01 6.927284889930257350e+01 6.651774685848624813e+01 6.486468563399645859e+01 6.431366522583319068e+01 6.486468563399645859e+01 6.651774685848624813e+01 6.927284889930257350e+01 7.312999175644543470e+01 7.808917542991481753e+01 8.415039991971073619e+01 9.131366522583319068e+01
-8.887369890376861292e+01 8.197573972009514875e+01 7.613900502621758903e+01 7.136349482213596218e+01 6.764920910785023977e+01 6.499614788336045024e+01 6.340431114866657225e+01 6.287369890376861292e+01 6.340431114866657225e+01 6.499614788336045024e+01 6.764920910785023977e+01 7.136349482213596218e+01 7.613900502621758903e+01 8.197573972009514875e+01 8.887369890376861292e+01
-8.641140130578952494e+01 7.977874824456503688e+01 7.416650334660585031e+01 6.957466661191196522e+01 6.600323804048339582e+01 6.345221763232012790e+01 6.192160538742216858e+01 6.141140130578951783e+01 6.192160538742216858e+01 6.345221763232012790e+01 6.600323804048339582e+01 6.957466661191196522e+01 7.416650334660585031e+01 7.977874824456503688e+01 8.641140130578952494e+01
-8.392551115654522675e+01 7.755816421776971481e+01 7.217040911572890138e+01 6.776224585042277226e+01 6.433367442185135587e+01 6.188469483001461668e+01 6.041530707491257601e+01 5.992551115654522675e+01 6.041530707491257601e+01 6.188469483001461668e+01 6.433367442185135587e+01 6.776224585042277226e+01 7.217040911572890138e+01 7.755816421776971481e+01 8.392551115654522675e+01
-8.141463989610934959e+01 7.531259907978281376e+01 7.014933377366035927e+01 6.592484397774200033e+01 6.263912969202770853e+01 6.029219091651750517e+01 5.888402765121138316e+01 5.841463989610934249e+01 5.888402765121138316e+01 6.029219091651750517e+01 6.263912969202770853e+01 6.592484397774200033e+01 7.014933377366035927e+01 7.531259907978281376e+01 8.141463989610934959e+01
-7.887725267893478076e+01 7.304051798505723525e+01 6.810174247485315391e+01 6.406092614832253673e+01 6.091806900546539083e+01 5.867317104628171620e+01 5.732623227077151284e+01 5.687725267893478076e+01 5.732623227077151284e+01 5.867317104628171620e+01 6.091806900546539083e+01 6.406092614832253673e+01 6.810174247485315391e+01 7.304051798505723525e+01 7.887725267893478076e+01
-7.631164553242834359e+01 7.074021696099977419e+01 6.602593124671406599e+01 6.216878838957120479e+01 5.916878838957119768e+01 5.702593124671405889e+01 5.574021696099977419e+01 5.531164553242834359e+01 5.574021696099977419e+01 5.702593124671405889e+01 5.916878838957119768e+01 6.216878838957120479e+01 6.602593124671406599e+01 7.074021696099977419e+01 7.631164553242834359e+01
-7.371591767636877535e+01 6.840979522738918206e+01 6.391999930902183280e+01 6.024652992126672757e+01 5.738938706412387347e+01 5.534857073759325630e+01 5.412408094167489025e+01 5.371591767636876824e+01 5.412408094167489025e+01 5.534857073759325630e+01 5.738938706412387347e+01 6.024652992126672757e+01 6.391999930902183280e+01 6.840979522738918206e+01 7.371591767636877535e+01
-7.108793768084882458e+01 6.604712135431820741e+01 6.178181523186922419e+01 5.829201931350188204e+01 5.557773359921616674e+01 5.363895808901208540e+01 5.247569278288963091e+01 5.208793768084881748e+01 5.247569278288963091e+01 5.363895808901208540e+01 5.557773359921616674e+01 5.829201931350188204e+01 6.178181523186922419e+01 6.604712135431820741e+01 7.108793768084882458e+01
-6.842530168918466416e+01 6.364979148510303020e+01 5.960897515857242013e+01 5.630285270959282684e+01 5.373142413816425744e+01 5.189468944428670483e+01 5.079264862796017610e+01 5.042530168918466416e+01 5.079264862796017610e+01 5.189468944428670483e+01 5.373142413816425744e+01 5.630285270959282684e+01 5.960897515857242013e+01 6.364979148510303020e+01 6.842530168918466416e+01
-6.572528129284776810e+01 6.121507721121511736e+01 5.739875068060287333e+01 5.427630170101103602e+01 5.184773027243960541e+01 5.011303639488858153e+01 4.907222006835797146e+01 4.872528129284776810e+01 4.907222006835797146e+01 5.011303639488858153e+01 5.184773027243960541e+01 5.427630170101103602e+01 5.739875068060287333e+01 6.121507721121511736e+01 6.572528129284776810e+01
-6.298475772352075808e+01 5.873985976433708345e+01 5.514802302964320546e+01 5.220924751943912412e+01 4.992353323372483942e+01 4.829088017250035136e+01 4.731128833576565285e+01 4.698475772352075808e+01 4.731128833576565285e+01 4.829088017250035136e+01 4.992353323372483942e+01 5.220924751943912412e+01 5.514802302964320546e+01 5.873985976433708345e+01 6.298475772352075808e+01
-6.020013767202479471e+01 5.622054583529010330e+01 5.285319889651459135e+01 5.009809685569826598e+01 4.795523971284112008e+01 4.642462746794316075e+01 4.550626012100438800e+01 4.520013767202479471e+01 4.550626012100438800e+01 4.642462746794316075e+01 4.795523971284112008e+01 5.009809685569826598e+01 5.285319889651459135e+01 5.622054583529010330e+01 6.020013767202479471e+01
-5.736724400800637369e+01 5.365295829372065839e+01 5.051010115086351959e+01 4.793867257943494309e+01 4.593867257943494309e+01 4.451010115086351959e+01 4.365295829372065839e+01 4.336724400800637369e+01 4.365295829372065839e+01 4.451010115086351959e+01 4.593867257943494309e+01 4.793867257943494309e+01 5.051010115086351959e+01 5.365295829372065839e+01 5.736724400800637369e+01
-5.448117154153786856e+01 5.103219194970113648e+01 4.811382460276235662e+01 4.572606950072154319e+01 4.386892664357868199e+01 4.254239603133378722e+01 4.174647766398684468e+01 4.148117154153786856e+01 4.174647766398684468e+01 4.254239603133378722e+01 4.386892664357868199e+01 4.572606950072154319e+01 4.811382460276235662e+01 5.103219194970113648e+01 5.448117154153786856e+01
-5.153609301408538101e+01 4.835241954469762504e+01 4.565854199367721833e+01 4.345446036102415377e+01 4.174017464673843847e+01 4.051568485082007243e+01 3.978099097326905564e+01 3.953609301408538101e+01 3.978099097326905564e+01 4.051568485082007243e+01 4.174017464673843847e+01 4.345446036102415377e+01 4.565854199367721833e+01 4.835241954469762504e+01 5.153609301408538101e+01
-4.852499242644162081e+01 4.560662507950284805e+01 4.313723732440080738e+01 4.111682916113549879e+01 3.954540058970692940e+01 3.842295161011509208e+01 3.774948222235998685e+01 3.752499242644162081e+01 3.774948222235998685e+01 3.842295161011509208e+01 3.954540058970692940e+01 4.111682916113549879e+01 4.313723732440080738e+01 4.560662507950284805e+01 4.852499242644162081e+01
-4.543928915419706982e+01 4.278622792970727318e+01 4.054132997052359855e+01 3.870459527664604593e+01 3.727602384807462244e+01 3.625561568480931385e+01 3.564337078685013438e+01 3.543928915419706982e+01 3.564337078685013438e+01 3.625561568480931385e+01 3.727602384807462244e+01 3.870459527664604593e+01 4.054132997052359855e+01 4.278622792970727318e+01 4.543928915419706982e+01
-4.226829224099447657e+01 3.988053713895366315e+01 3.786012897568835456e+01 3.620706775119855791e+01 3.492135346548427322e+01 3.400298611854550046e+01 3.345196571038223254e+01 3.326829224099447657e+01 3.345196571038223254e+01 3.400298611854550046e+01 3.492135346548427322e+01 3.620706775119855791e+01 3.786012897568835456e+01 3.988053713895366315e+01 4.226829224099447657e+01
-3.899837975096674114e+01 3.687593077137490383e+01 3.508001240402796839e+01 3.361062464892592772e+01 3.246776750606878181e+01 3.165144097545653779e+01 3.116164505708918853e+01 3.099837975096674114e+01 3.116164505708918853e+01 3.165144097545653779e+01 3.246776750606878181e+01 3.361062464892592772e+01 3.508001240402796839e+01 3.687593077137490383e+01 3.899837975096674114e+01
-3.561171076849140604e+01 3.375456791134854484e+01 3.218313933991997544e+01 3.089742505420568719e+01 2.989742505420568719e+01 2.918313933991997544e+01 2.875456791134854484e+01 2.861171076849140249e+01 2.875456791134854484e+01 2.918313933991997544e+01 2.989742505420568719e+01 3.089742505420568719e+01 3.218313933991997544e+01 3.375456791134854484e+01 3.561171076849140604e+01
-3.208409374656930879e+01 3.049225701187543081e+01 2.914531823636522745e+01 2.804327742003869517e+01 2.718613456289583752e+01 2.657388966493665450e+01 2.620654272616114611e+01 2.608409374656930879e+01 2.620654272616114611e+01 2.657388966493665450e+01 2.718613456289583752e+01 2.804327742003869517e+01 2.914531823636522745e+01 3.049225701187543081e+01 3.208409374656930879e+01
-2.838121119556553040e+01 2.705468058332063208e+01 2.593223160372879477e+01 2.501386425679002201e+01 2.429957854250430671e+01 2.378937446087165242e+01 2.348325201189206268e+01 2.338121119556553040e+01 2.348325201189206268e+01 2.378937446087165242e+01 2.429957854250430671e+01 2.501386425679002201e+01 2.593223160372879477e+01 2.705468058332063208e+01 2.838121119556553040e+01
-2.445130365127145566e+01 2.339007916147553701e+01 2.249211997780206929e+01 2.175742610025104895e+01 2.118599752882247600e+01 2.077783426351635399e+01 2.053293630433267936e+01 2.045130365127145566e+01 2.053293630433267936e+01 2.077783426351635399e+01 2.118599752882247600e+01 2.175742610025104895e+01 2.249211997780206929e+01 2.339007916147553701e+01 2.445130365127145566e+01
-2.020908402196999276e+01 1.941316565462305377e+01 1.873969626686795209e+01 1.818867585870468773e+01 1.776010443013325713e+01 1.745398198115366739e+01 1.727030851176591142e+01 1.720908402196999276e+01 1.727030851176591142e+01 1.745398198115366739e+01 1.776010443013325713e+01 1.818867585870468773e+01 1.873969626686795209e+01 1.941316565462305377e+01 2.020908402196999276e+01
-1.549282847673563346e+01 1.496221623183767413e+01 1.451323664000094027e+01 1.414588970122543010e+01 1.386017541551114363e+01 1.365609378285808262e+01 1.353364480326624530e+01 1.349282847673563346e+01 1.353364480326624530e+01 1.365609378285808262e+01 1.386017541551114363e+01 1.414588970122543010e+01 1.451323664000094027e+01 1.496221623183767413e+01 1.549282847673563346e+01
-9.901946956877223371e+00 9.636640834428243707e+00 9.412151038509875889e+00 9.228477569122121693e+00 9.085620426264977567e+00 8.983579609938447064e+00 8.922355120142530183e+00 8.901946956877223371e+00 8.922355120142530183e+00 8.983579609938447064e+00 9.085620426264977567e+00 9.228477569122121693e+00 9.412151038509875889e+00 9.636640834428243707e+00 9.901946956877223371e+00
-0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00
+ncols 15
+nrows 50
+xllcorner 0.0
+yllcorner 0.0
+cellsize 10.0
+1.409607808342839235e+02 1.279607808342839093e+02 1.169607808342839093e+02 1.079607808342839093e+02 1.009607808342839093e+02 9.596078083428390926e+01 9.296078083428390926e+01 9.196078083428390926e+01 9.296078083428390926e+01 9.596078083428390926e+01 1.009607808342839093e+02 1.079607808342839093e+02 1.169607808342839093e+02 1.279607808342839093e+02 1.409607808342839235e+02
+1.388300900165792768e+02 1.260953961390282672e+02 1.153198859349466403e+02 1.065035594043343963e+02 9.964641654719153507e+01 9.474845736351807091e+01 9.180968185331398956e+01 9.083009001657929105e+01 9.180968185331398956e+01 9.474845736351807091e+01 9.964641654719153507e+01 1.065035594043343963e+02 1.153198859349466403e+02 1.260953961390282672e+02 1.388300900165792768e+02
+1.366899365810845097e+02 1.242205488259824904e+02 1.136695284178192225e+02 1.050368753565947344e+02 9.832258964230901199e+01 9.352667127496206945e+01 9.064912025455390676e+01 8.968993658108452394e+01 9.064912025455390676e+01 9.352667127496206945e+01 9.832258964230901199e+01 1.050368753565947344e+02 1.136695284178192225e+02 1.242205488259824904e+02 1.366899365810845097e+02
+1.345400374172721740e+02 1.223359557846191024e+02 1.120094251723742218e+02 1.035604455805374755e+02 9.698901700910890611e+01 9.229513945808849940e+01 8.947881292747625537e+01 8.854003741727217403e+01 8.947881292747625537e+01 9.229513945808849940e+01 9.698901700910890611e+01 1.035604455805374755e+02 1.120094251723742218e+02 1.223359557846191024e+02 1.345400374172721740e+02
+1.323800945760021079e+02 1.204413190657980124e+02 1.103392782494714766e+02 1.020739721270225004e+02 9.564540069845106984e+01 9.105356396375719896e+01 8.829846192294087359e+01 8.738009457600209373e+01 8.829846192294087359e+01 9.105356396375719896e+01 9.564540069845106984e+01 1.020739721270225004e+02 1.103392782494714766e+02 1.204413190657980124e+02 1.323800945760021079e+02
+1.302097941430593551e+02 1.185363247553042640e+02 1.086587737348961014e+02 1.005771410818348812e+02 9.429142679612058942e+01 8.980163087775324016e+01 8.710775332673283344e+01 8.620979414305936928e+01 8.710775332673283344e+01 8.980163087775324016e+01 9.429142679612058942e+01 1.005771410818348812e+02 1.086587737348961014e+02 1.185363247553042640e+02 1.302097941430593551e+02
+1.280288049994908874e+02 1.166206417341847725e+02 1.069675805096949830e+02 9.906962132602151883e+01 9.292676418316436582e+01 8.853900908112355239e+01 8.590635601989906434e+01 8.502880499949090165e+01 8.590635601989906434e+01 8.853900908112355239e+01 9.292676418316436582e+01 9.906962132602151883e+01 1.069675805096949830e+02 1.166206417341847725e+02 1.280288049994908874e+02
+1.258367774544524877e+02 1.146939203115953489e+02 1.052653488830239183e+02 9.755106316873821015e+01 9.155106316873819594e+01 8.726534888302391835e+01 8.469392031159534895e+01 8.383677745445248775e+01 8.469392031159534895e+01 8.726534888302391835e+01 9.155106316873819594e+01 9.755106316873821015e+01 1.052653488830239183e+02 1.146939203115953489e+02 1.258367774544524877e+02
+1.236333417340885603e+02 1.127557907136803976e+02 1.035517090810273402e+02 9.602109683612937374e+01 9.016395397898652675e+01 8.598028050959877078e+01 8.347007642796610583e+01 8.263334173408856032e+01 8.347007642796610583e+01 8.598028050959877078e+01 9.016395397898652675e+01 9.602109683612937374e+01 1.035517090810273402e+02 1.127557907136803976e+02 1.236333417340885603e+02
+1.214181063073808673e+02 1.108058614094216807e+02 1.018262695726869964e+02 9.447933079717678595e+01 8.876504508289107775e+01 8.468341242982984340e+01 8.223443283799311132e+01 8.141810630738086729e+01 8.223443283799311132e+01 8.468341242982984340e+01 8.876504508289107775e+01 9.447933079717678595e+01 1.018262695726869964e+02 1.108058614094216807e+02 1.214181063073808673e+02
+1.191906560268354127e+02 1.088437172513252165e+02 1.000886152105088769e+02 9.292534990438643661e+01 8.735392133295786721e+01 8.337432949622316869e+01 8.098657439418235526e+01 8.019065602683541272e+01 8.098657439418235526e+01 8.337432949622316869e+01 8.735392133295786721e+01 9.292534990438643661e+01 1.000886152105088769e+02 1.088437172513252165e+02 1.191906560268354127e+02
+1.169505500582237545e+02 1.068689174051625344e+02 9.833830516026456792e+01 9.135871332352988361e+01 8.593014189495845301e+01 8.205259087455029032e+01 7.972606026230538134e+01 7.895055005822375449e+01 7.972606026230538134e+01 8.205259087455029032e+01 8.593014189495845301e+01 9.135871332352988361e+01 9.833830516026456792e+01 1.068689174051625344e+02 1.169505500582237545e+02
+1.146973195692267922e+02 1.048809930386145481e+02 9.657487058963495485e+01 8.977895222228801231e+01 8.449323793657373471e+01 8.071772773249209365e+01 7.845242161004311754e+01 7.769731956922679217e+01 7.845242161004311754e+01 8.071772773249209365e+01 8.449323793657373471e+01 8.977895222228801231e+01 9.657487058963495485e+01 1.048809930386145481e+02 1.146973195692267922e+02
+1.124304651415819620e+02 1.028794447334186941e+02 9.479781208035747397e+01 8.818556718239828740e+01 8.304271003954114860e+01 7.936924065178604337e+01 7.716515901913298592e+01 7.643046514158196203e+01 7.716515901913298592e+01 7.936924065178604337e+01 8.304271003954114860e+01 8.818556718239828740e+01 9.479781208035747397e+01 1.028794447334186941e+02 1.124304651415819620e+02
+1.101494538650013482e+02 1.008637395792870564e+02 9.300659672214420937e+01 8.657802529357277876e+01 8.157802529357277876e+01 7.800659672214420937e+01 7.586373957928705636e+01 7.514945386500134816e+01 7.586373957928705636e+01 7.800659672214420937e+01 8.157802529357277876e+01 8.657802529357277876e+01 9.300659672214420937e+01 1.008637395792870564e+02 1.101494538650013482e+02
+1.078537160634485588e+02 9.883330790018325729e+01 9.120065483895876923e+01 8.495575687977509460e+01 8.009861402263223340e+01 7.662922626753018562e+01 7.454759361446896548e+01 7.385371606344855877e+01 7.454759361446896548e+01 7.662922626753018562e+01 8.009861402263223340e+01 8.495575687977509460e+01 9.120065483895876923e+01 9.883330790018325729e+01 1.078537160634485588e+02
+1.055426415949973205e+02 9.678753955418099508e+01 8.937937628887488017e+01 8.331815179907894731e+01 7.860386608479323911e+01 7.523651914601772717e+01 7.321611098275242568e+01 7.254264159499732045e+01 7.321611098275242568e+01 7.523651914601772717e+01 7.860386608479323911e+01 8.331815179907894731e+01 8.937937628887488017e+01 9.678753955418099508e+01 1.055426415949973205e+02
+1.032155756550177870e+02 9.472577973665043771e+01 8.754210626726268174e+01 8.166455524685451905e+01 7.709312667542594966e+01 7.382782055297697354e+01 7.186863687950757651e+01 7.121557565501778697e+01 7.186863687950757651e+01 7.382782055297697354e+01 7.709312667542594966e+01 8.166455524685451905e+01 8.754210626726268174e+01 9.472577973665043771e+01 1.032155756550177870e+02
+1.008718139982837272e+02 9.264732420236535404e+01 8.568814052889597122e+01 7.999426297787556450e+01 7.556569154930413390e+01 7.240242624318167941e+01 7.050446705950821524e+01 6.987181399828372719e+01 7.050446705950821524e+01 7.240242624318167941e+01 7.556569154930413390e+01 7.999426297787556450e+01 8.568814052889597122e+01 9.264732420236535404e+01 1.008718139982837272e+02
+9.851059747803871858e+01 9.055141380456933575e+01 8.381671992701831186e+01 7.830651584538566112e+01 7.402080155967136932e+01 7.095957706987545066e+01 6.912284237599790515e+01 6.851059747803871858e+01 6.912284237599790515e+01 7.095957706987545066e+01 7.402080155967136932e+01 7.830651584538566112e+01 8.381671992701831186e+01 9.055141380456933575e+01 9.851059747803871858e+01
+9.613110577813931457e+01 8.843722822711890785e+01 8.192702414548625711e+01 7.660049353324134813e+01 7.245763639038420934e+01 6.949845271691482651e+01 6.772294251283318545e+01 6.713110577813931457e+01 6.772294251283318545e+01 6.949845271691482651e+01 7.245763639038420934e+01 7.660049353324134813e+01 8.192702414548625711e+01 8.843722822711890785e+01 9.613110577813931457e+01
+9.373245018683405760e+01 8.630387875826262700e+01 8.001816447254834941e+01 7.487530732969119640e+01 7.087530732969119640e+01 6.801816447254834941e+01 6.630387875826262700e+01 6.573245018683405760e+01 6.630387875826262700e+01 6.801816447254834941e+01 7.087530732969119640e+01 7.487530732969119640e+01 8.001816447254834941e+01 8.630387875826262700e+01 9.373245018683405760e+01
+9.131366522583319068e+01 8.415039991971073619e+01 7.808917542991481753e+01 7.312999175644543470e+01 6.927284889930257350e+01 6.651774685848624813e+01 6.486468563399645859e+01 6.431366522583319068e+01 6.486468563399645859e+01 6.651774685848624813e+01 6.927284889930257350e+01 7.312999175644543470e+01 7.808917542991481753e+01 8.415039991971073619e+01 9.131366522583319068e+01
+8.887369890376861292e+01 8.197573972009514875e+01 7.613900502621758903e+01 7.136349482213596218e+01 6.764920910785023977e+01 6.499614788336045024e+01 6.340431114866657225e+01 6.287369890376861292e+01 6.340431114866657225e+01 6.499614788336045024e+01 6.764920910785023977e+01 7.136349482213596218e+01 7.613900502621758903e+01 8.197573972009514875e+01 8.887369890376861292e+01
+8.641140130578952494e+01 7.977874824456503688e+01 7.416650334660585031e+01 6.957466661191196522e+01 6.600323804048339582e+01 6.345221763232012790e+01 6.192160538742216858e+01 6.141140130578951783e+01 6.192160538742216858e+01 6.345221763232012790e+01 6.600323804048339582e+01 6.957466661191196522e+01 7.416650334660585031e+01 7.977874824456503688e+01 8.641140130578952494e+01
+8.392551115654522675e+01 7.755816421776971481e+01 7.217040911572890138e+01 6.776224585042277226e+01 6.433367442185135587e+01 6.188469483001461668e+01 6.041530707491257601e+01 5.992551115654522675e+01 6.041530707491257601e+01 6.188469483001461668e+01 6.433367442185135587e+01 6.776224585042277226e+01 7.217040911572890138e+01 7.755816421776971481e+01 8.392551115654522675e+01
+8.141463989610934959e+01 7.531259907978281376e+01 7.014933377366035927e+01 6.592484397774200033e+01 6.263912969202770853e+01 6.029219091651750517e+01 5.888402765121138316e+01 5.841463989610934249e+01 5.888402765121138316e+01 6.029219091651750517e+01 6.263912969202770853e+01 6.592484397774200033e+01 7.014933377366035927e+01 7.531259907978281376e+01 8.141463989610934959e+01
+7.887725267893478076e+01 7.304051798505723525e+01 6.810174247485315391e+01 6.406092614832253673e+01 6.091806900546539083e+01 5.867317104628171620e+01 5.732623227077151284e+01 5.687725267893478076e+01 5.732623227077151284e+01 5.867317104628171620e+01 6.091806900546539083e+01 6.406092614832253673e+01 6.810174247485315391e+01 7.304051798505723525e+01 7.887725267893478076e+01
+7.631164553242834359e+01 7.074021696099977419e+01 6.602593124671406599e+01 6.216878838957120479e+01 5.916878838957119768e+01 5.702593124671405889e+01 5.574021696099977419e+01 5.531164553242834359e+01 5.574021696099977419e+01 5.702593124671405889e+01 5.916878838957119768e+01 6.216878838957120479e+01 6.602593124671406599e+01 7.074021696099977419e+01 7.631164553242834359e+01
+7.371591767636877535e+01 6.840979522738918206e+01 6.391999930902183280e+01 6.024652992126672757e+01 5.738938706412387347e+01 5.534857073759325630e+01 5.412408094167489025e+01 5.371591767636876824e+01 5.412408094167489025e+01 5.534857073759325630e+01 5.738938706412387347e+01 6.024652992126672757e+01 6.391999930902183280e+01 6.840979522738918206e+01 7.371591767636877535e+01
+7.108793768084882458e+01 6.604712135431820741e+01 6.178181523186922419e+01 5.829201931350188204e+01 5.557773359921616674e+01 5.363895808901208540e+01 5.247569278288963091e+01 5.208793768084881748e+01 5.247569278288963091e+01 5.363895808901208540e+01 5.557773359921616674e+01 5.829201931350188204e+01 6.178181523186922419e+01 6.604712135431820741e+01 7.108793768084882458e+01
+6.842530168918466416e+01 6.364979148510303020e+01 5.960897515857242013e+01 5.630285270959282684e+01 5.373142413816425744e+01 5.189468944428670483e+01 5.079264862796017610e+01 5.042530168918466416e+01 5.079264862796017610e+01 5.189468944428670483e+01 5.373142413816425744e+01 5.630285270959282684e+01 5.960897515857242013e+01 6.364979148510303020e+01 6.842530168918466416e+01
+6.572528129284776810e+01 6.121507721121511736e+01 5.739875068060287333e+01 5.427630170101103602e+01 5.184773027243960541e+01 5.011303639488858153e+01 4.907222006835797146e+01 4.872528129284776810e+01 4.907222006835797146e+01 5.011303639488858153e+01 5.184773027243960541e+01 5.427630170101103602e+01 5.739875068060287333e+01 6.121507721121511736e+01 6.572528129284776810e+01
+6.298475772352075808e+01 5.873985976433708345e+01 5.514802302964320546e+01 5.220924751943912412e+01 4.992353323372483942e+01 4.829088017250035136e+01 4.731128833576565285e+01 4.698475772352075808e+01 4.731128833576565285e+01 4.829088017250035136e+01 4.992353323372483942e+01 5.220924751943912412e+01 5.514802302964320546e+01 5.873985976433708345e+01 6.298475772352075808e+01
+6.020013767202479471e+01 5.622054583529010330e+01 5.285319889651459135e+01 5.009809685569826598e+01 4.795523971284112008e+01 4.642462746794316075e+01 4.550626012100438800e+01 4.520013767202479471e+01 4.550626012100438800e+01 4.642462746794316075e+01 4.795523971284112008e+01 5.009809685569826598e+01 5.285319889651459135e+01 5.622054583529010330e+01 6.020013767202479471e+01
+5.736724400800637369e+01 5.365295829372065839e+01 5.051010115086351959e+01 4.793867257943494309e+01 4.593867257943494309e+01 4.451010115086351959e+01 4.365295829372065839e+01 4.336724400800637369e+01 4.365295829372065839e+01 4.451010115086351959e+01 4.593867257943494309e+01 4.793867257943494309e+01 5.051010115086351959e+01 5.365295829372065839e+01 5.736724400800637369e+01
+5.448117154153786856e+01 5.103219194970113648e+01 4.811382460276235662e+01 4.572606950072154319e+01 4.386892664357868199e+01 4.254239603133378722e+01 4.174647766398684468e+01 4.148117154153786856e+01 4.174647766398684468e+01 4.254239603133378722e+01 4.386892664357868199e+01 4.572606950072154319e+01 4.811382460276235662e+01 5.103219194970113648e+01 5.448117154153786856e+01
+5.153609301408538101e+01 4.835241954469762504e+01 4.565854199367721833e+01 4.345446036102415377e+01 4.174017464673843847e+01 4.051568485082007243e+01 3.978099097326905564e+01 3.953609301408538101e+01 3.978099097326905564e+01 4.051568485082007243e+01 4.174017464673843847e+01 4.345446036102415377e+01 4.565854199367721833e+01 4.835241954469762504e+01 5.153609301408538101e+01
+4.852499242644162081e+01 4.560662507950284805e+01 4.313723732440080738e+01 4.111682916113549879e+01 3.954540058970692940e+01 3.842295161011509208e+01 3.774948222235998685e+01 3.752499242644162081e+01 3.774948222235998685e+01 3.842295161011509208e+01 3.954540058970692940e+01 4.111682916113549879e+01 4.313723732440080738e+01 4.560662507950284805e+01 4.852499242644162081e+01
+4.543928915419706982e+01 4.278622792970727318e+01 4.054132997052359855e+01 3.870459527664604593e+01 3.727602384807462244e+01 3.625561568480931385e+01 3.564337078685013438e+01 3.543928915419706982e+01 3.564337078685013438e+01 3.625561568480931385e+01 3.727602384807462244e+01 3.870459527664604593e+01 4.054132997052359855e+01 4.278622792970727318e+01 4.543928915419706982e+01
+4.226829224099447657e+01 3.988053713895366315e+01 3.786012897568835456e+01 3.620706775119855791e+01 3.492135346548427322e+01 3.400298611854550046e+01 3.345196571038223254e+01 3.326829224099447657e+01 3.345196571038223254e+01 3.400298611854550046e+01 3.492135346548427322e+01 3.620706775119855791e+01 3.786012897568835456e+01 3.988053713895366315e+01 4.226829224099447657e+01
+3.899837975096674114e+01 3.687593077137490383e+01 3.508001240402796839e+01 3.361062464892592772e+01 3.246776750606878181e+01 3.165144097545653779e+01 3.116164505708918853e+01 3.099837975096674114e+01 3.116164505708918853e+01 3.165144097545653779e+01 3.246776750606878181e+01 3.361062464892592772e+01 3.508001240402796839e+01 3.687593077137490383e+01 3.899837975096674114e+01
+3.561171076849140604e+01 3.375456791134854484e+01 3.218313933991997544e+01 3.089742505420568719e+01 2.989742505420568719e+01 2.918313933991997544e+01 2.875456791134854484e+01 2.861171076849140249e+01 2.875456791134854484e+01 2.918313933991997544e+01 2.989742505420568719e+01 3.089742505420568719e+01 3.218313933991997544e+01 3.375456791134854484e+01 3.561171076849140604e+01
+3.208409374656930879e+01 3.049225701187543081e+01 2.914531823636522745e+01 2.804327742003869517e+01 2.718613456289583752e+01 2.657388966493665450e+01 2.620654272616114611e+01 2.608409374656930879e+01 2.620654272616114611e+01 2.657388966493665450e+01 2.718613456289583752e+01 2.804327742003869517e+01 2.914531823636522745e+01 3.049225701187543081e+01 3.208409374656930879e+01
+2.838121119556553040e+01 2.705468058332063208e+01 2.593223160372879477e+01 2.501386425679002201e+01 2.429957854250430671e+01 2.378937446087165242e+01 2.348325201189206268e+01 2.338121119556553040e+01 2.348325201189206268e+01 2.378937446087165242e+01 2.429957854250430671e+01 2.501386425679002201e+01 2.593223160372879477e+01 2.705468058332063208e+01 2.838121119556553040e+01
+2.445130365127145566e+01 2.339007916147553701e+01 2.249211997780206929e+01 2.175742610025104895e+01 2.118599752882247600e+01 2.077783426351635399e+01 2.053293630433267936e+01 2.045130365127145566e+01 2.053293630433267936e+01 2.077783426351635399e+01 2.118599752882247600e+01 2.175742610025104895e+01 2.249211997780206929e+01 2.339007916147553701e+01 2.445130365127145566e+01
+2.020908402196999276e+01 1.941316565462305377e+01 1.873969626686795209e+01 1.818867585870468773e+01 1.776010443013325713e+01 1.745398198115366739e+01 1.727030851176591142e+01 1.720908402196999276e+01 1.727030851176591142e+01 1.745398198115366739e+01 1.776010443013325713e+01 1.818867585870468773e+01 1.873969626686795209e+01 1.941316565462305377e+01 2.020908402196999276e+01
+1.549282847673563346e+01 1.496221623183767413e+01 1.451323664000094027e+01 1.414588970122543010e+01 1.386017541551114363e+01 1.365609378285808262e+01 1.353364480326624530e+01 1.349282847673563346e+01 1.353364480326624530e+01 1.365609378285808262e+01 1.386017541551114363e+01 1.414588970122543010e+01 1.451323664000094027e+01 1.496221623183767413e+01 1.549282847673563346e+01
+9.901946956877223371e+00 9.636640834428243707e+00 9.412151038509875889e+00 9.228477569122121693e+00 9.085620426264977567e+00 8.983579609938447064e+00 8.922355120142530183e+00 8.901946956877223371e+00 8.922355120142530183e+00 8.983579609938447064e+00 9.085620426264977567e+00 9.228477569122121693e+00 9.412151038509875889e+00 9.636640834428243707e+00 9.901946956877223371e+00
+0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00
diff --git a/docs/source/tutorials/mass_wasting_runout/landslide_runout_animation.ipynb b/docs/source/tutorials/mass_wasting_runout/landslide_runout_animation.ipynb
index 36cdd41f10..dc0beeb315 100644
--- a/docs/source/tutorials/mass_wasting_runout/landslide_runout_animation.ipynb
+++ b/docs/source/tutorials/mass_wasting_runout/landslide_runout_animation.ipynb
@@ -485,6 +485,8 @@
"outputs": [],
"source": [
"# update function\n",
+ "\n",
+ "\n",
"def update_plot(frame_number, MWR, plot):\n",
" mg.at_node[\"dem_dif_m\"] = (\n",
" MWR.saver.runout_evo_maps[0][frame_number]\n",
diff --git a/docs/source/tutorials/network_sediment_transporter/hugo_site.asc b/docs/source/tutorials/network_sediment_transporter/hugo_site.asc
index 8d37cafd42..61c8e89340 100644
--- a/docs/source/tutorials/network_sediment_transporter/hugo_site.asc
+++ b/docs/source/tutorials/network_sediment_transporter/hugo_site.asc
@@ -1,61 +1,61 @@
-ncols 76
-nrows 55
-xllcorner 0
-yllcorner 0
-cellsize 10
-NODATA_value -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1708 -9999 1707 1708 -9999 1708 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1709 1708 1708 1708 1707 1708 1708 1707 1707 1707 1706 1705 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1708 1708 1707 1707 1707 1708 1707 1707 1706 1706 1705 1705 1707 1706 1705 1706 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1706 1707 1707 1707 1707 1707 1707 1707 1706 1706 1705 1705 1705 1705 1705 1706 1707 1706 1705 1705 1705 1705 1707 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1705 1705 1706 1706 1707 1706 1706 1707 1706 1706 1705 1704 1704 1703 1704 1704 1703 1704 1705 1704 1704 1705 1706 1705 1706 1704 1704 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1704 1704 1704 1704 1705 1704 1705 1705 1705 1706 1704 1704 1704 1703 1702 1702 1701 1702 1702 1704 1704 1705 1704 1704 1704 1705 1705 1703 1705 1704 1704 1704 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1704 1703 1702 1702 1703 1702 1703 1704 1703 1704 1704 1703 1702 1701 1700 1699 1699 1698 1700 1701 1702 1703 1703 1704 1704 1704 1704 1704 1705 1703 1702 1702 1702 1703 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1702 1702 1701 1700 1701 1701 1701 1702 1702 1702 1703 1702 1701 1699 1698 1696 1697 1695 1696 1699 1700 1699 1700 1700 1702 1702 1702 1702 1703 1702 1701 1701 1701 1701 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1700 1699 1698 1698 1698 1699 1698 1700 1699 1699 1699 1700 1699 1697 1696 1693 1693 1693 1694 1696 1698 1698 1698 1698 1699 1699 1700 1701 1700 1700 1699 1698 1699 1699 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1699 1698 1697 1696 1696 1695 1695 1696 1697 1697 1697 1697 1696 1696 1695 1693 1691 1689 1689 1691 1692 1695 1696 1695 1695 1695 1696 1697 1698 1698 1697 1695 1695 1696 1698 1698 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1702 1700 1698 1695 1694 1693 1692 1692 1693 1693 1693 1694 1693 1694 1693 1692 1692 1690 1688 1686 1686 1688 1691 1692 1693 1691 1692 1692 1694 1694 1695 1694 1693 1692 1692 1693 1695 1696 1697 1698 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1701 1699 1696 1694 1692 1690 1689 1689 1689 1690 1690 1690 1690 1690 1690 1690 1689 1688 1685 1684 1683 1686 1688 1689 1689 1689 1689 1689 1690 1691 1692 1692 1691 1690 1690 1691 1692 1694 1696 1696 1697 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1698 1696 1694 1691 1688 1687 1686 1686 1687 1687 1686 1687 1687 1687 1686 1686 1685 1683 1681 1681 1683 1685 1686 1686 1686 1686 1686 1687 1688 1689 1689 1688 1687 1686 1688 1689 1691 1694 1695 1695 1696 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1699 1696 1694 1691 1688 1685 1684 1684 1684 1684 1683 1683 1684 1683 1683 1683 1682 1681 1679 1678 1681 1683 1683 1683 1683 1682 1683 1684 1686 1687 1686 1685 1684 1684 1685 1687 1689 1691 1693 1693 1695 1694 1694 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1704 1703 1702 1700 1696 1695 1692 1689 1686 1684 1682 1682 1682 1681 1681 1681 1680 1680 1680 1680 1679 1677 1677 1679 1680 1680 1681 1680 1679 1680 1681 1683 1684 1684 1683 1681 1681 1682 1685 1687 1689 1691 1693 1694 1691 1693 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1702 1700 1698 1696 1692 1690 1688 1685 1685 1684 1681 1680 1680 1679 1678 1678 1678 1677 1677 1676 1675 1677 1677 1677 1678 1678 1677 1677 1679 1681 1682 1682 1681 1679 1678 1680 1683 1686 1688 1689 1690 1692 1691 1691 1692 1692 1692 1692 1691 1690 1692 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1706 1705 1705 1703 1701 1699 1696 1694 1692 1691 1690 1688 1687 1685 1683 1682 1681 1680 1678 1679 1676 1676 1676 1675 1675 1675 1675 1675 1675 1674 1676 1677 1678 1679 1679 1679 1677 1676 1678 1681 1684 1686 1688 1688 1689 1691 1691 1691 1690 1691 1689 1690 1690 1690 1689 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1705 1704 1702 1700 1698 1696 1695 1694 1692 1691 1691 1688 1687 1686 1685 1684 1682 1682 1680 1678 1677 1675 1675 1674 1674 1673 1673 1673 1674 1675 1675 1676 1676 1677 1676 1675 1677 1680 1683 1684 1687 1686 1687 1688 1687 1688 1687 1688 1687 1687 1687 1687 1686 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1706 1705 1705 1703 1701 1700 1699 1697 1696 1695 1694 1693 1691 1690 1688 1688 1687 1685 1685 1683 1682 1680 1678 1678 1677 1675 1673 1672 1671 1672 1673 1673 1673 1674 1675 1673 1673 1676 1679 1680 1682 1683 1684 1683 1684 1684 1683 1684 1684 1684 1683 1684 1683 1682 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1704 1703 1702 1700 1700 1699 1698 1697 1696 1694 1693 1692 1691 1689 1689 1688 1687 1684 1683 1681 1681 1679 1677 1677 1674 1673 1670 1670 1670 1670 1671 1672 1671 1672 1674 1678 1678 1680 1680 1680 1679 1680 1680 1680 1680 1680 1681 1680 1680 1679 1679 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1706 1706 1705 1703 1703 1703 1702 1701 1699 1698 1696 1696 1695 1695 1694 1692 1691 1689 1688 1685 1685 1683 1682 1680 1679 1678 1676 1675 1673 1671 1670 1669 1669 1670 1671 1674 1675 1676 1676 1677 1676 1676 1677 1676 1677 1677 1676 1677 1676 1678 1676 1675 1676
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1705 1705 1704 1704 1703 1702 1701 1700 1699 1698 1698 1697 1696 1695 1695 1693 1691 1690 1688 1687 1685 1683 1681 1680 1679 1677 1675 1673 1672 1669 1668 1669 1670 1671 1673 1674 1674 1674 1673 1673 1673 1673 1673 1672 1672 1673 1673 1673 1672 1672 1672
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1705 1705 1704 1704 1704 1703 1702 1701 1701 1701 1700 1697 1697 1697 1694 1693 1692 1690 1689 1686 1685 1682 1681 1679 1678 1676 1674 1674 1670 1668 1668 1669 1670 1670 1672 1672 1671 1671 1670 1670 1670 1669 1669 1669 1669 1669 1669 1669 1668 1669
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1706 1706 1705 1705 1705 1704 1703 1702 1701 1701 1700 1698 1697 1696 1695 1694 1692 1690 1689 1687 1684 1683 1682 1679 1679 1677 1675 1674 1672 1670 1668 1667 1668 1668 1669 1669 1669 1668 1668 1668 1667 1666 1666 1665 1665 1665 1665 1665 1665 1665
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1707 1707 1707 1706 1705 1705 1704 1703 1703 1702 1701 1700 1700 1697 1697 1695 1694 1692 1691 1689 1687 1686 1683 1681 1679 1678 1677 1675 1674 1673 1671 1669 1668 1666 1666 1667 1667 1667 1667 1666 1666 1665 1665 1664 1663 1663 1663 1663 1663 1662 1662 1662
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1708 1706 1706 1705 1704 1704 1702 1702 1701 1700 1699 1698 1696 1695 1694 1692 1690 1689 1688 1685 1684 1681 1679 1676 1675 1673 1673 1672 1670 1669 1669 1667 1667 1667 1666 1666 1666 1666 1665 1665 1665 1664 1663 1663 1663 1662 1662 1662 1661 1661 1661
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1706 1706 1706 1705 1705 1704 1702 1702 1700 1700 1699 1697 1696 1694 1693 1691 1690 1688 1686 1685 1683 1681 1678 1676 1673 1672 1671 1670 1670 1669 1668 1668 1668 1667 1667 1666 1666 1665 1665 1664 1664 1664 1664 1664 1663 1663 1663 1662 1662 1662 1661 1660
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1705 1706 1705 1704 1704 1702 1701 1701 1699 1698 1697 1695 1694 1692 1691 1689 1687 1686 1684 1682 1680 1678 1676 1674 1672 1671 1670 1671 1669 1670 1670 1670 1669 1668 1670 1667 1666 1665 1666 1664 1665 1665 1665 1665 1664 1664 1664 1663 1664 1663 1662 1661
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1705 1704 1705 1704 1704 1703 1702 1701 1700 1698 1697 1696 1695 1694 1692 1690 1688 1686 1684 1682 1681 1679 1678 1676 1674 1672 1672 1673 1672 1673 1672 1672 1672 1673 1671 1671 1673 1673 1669 1667 1665 1666 1666 1668 1668 1667 1666 1667 1665 1664 1666 1665 1663 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1704 1703 1703 1702 1701 1701 1700 1698 1696 1695 1693 1692 1691 1690 1687 1685 1683 1681 1680 1678 1677 1675 1674 1673 1673 1673 1675 1676 1677 1675 1676 1675 1675 1673 1673 1674 1675 1673 1672 1672 1672 1670 1671 1670 1669 1668 1668 1666 1665 1666 1665 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1703 1702 1701 1700 1700 1699 1699 1698 1696 1694 1692 1691 1690 1688 1687 1685 1682 1681 1679 1678 1676 1675 1675 1674 1674 1676 1674 1676 1678 1679 1679 1679 1679 1677 1675 1674 1676 1679 1679 1679 1678 1674 1674 1673 1671 1670 1669 1668 1666 1666 1668 1668 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1699 1698 1697 1697 1697 1696 1695 1692 1691 1689 1686 1685 1684 1682 1680 1679 1676 1676 1675 1675 1676 1677 1678 1677 1676 1678 1681 1682 1681 1683 1682 1679 1677 1678 1679 1681 1682 1682 1680 1678 1677 1675 1673 1671 1669 1668 1666 1668 1671 1671 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1701 1699 1697 1696 1694 1695 1694 1694 1693 1691 1688 1686 1683 1683 1681 1680 1679 1677 1676 1676 1678 1680 1681 1680 1678 1679 1677 1678 1681 1683 1684 1685 1684 1682 1678 1680 1682 1684 1684 1684 1683 1680 1678 1676 1673 1671 1669 1668 1668 1671 1673 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1698 1696 1694 1692 1691 1691 1692 1691 1690 1687 1685 1682 1680 1679 1678 1677 1677 1677 1681 1682 1682 1683 1683 1684 1682 1682 1680 1683 1686 1685 1687 1686 1683 1681 1681 1684 1686 1687 1686 1685 1681 1679 1676 1673 1671 1669 1671 1672 1675 1676 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1703 1701 1700 1698 1696 1693 1691 1689 1689 1690 1689 1687 1685 1684 1681 1679 1679 1680 1681 1682 1684 1684 1687 1685 1686 1687 1687 1684 1682 1681 1684 1687 1688 1689 1687 1685 1682 1685 1688 1688 1688 1687 1685 1681 1678 1676 1673 1671 1672 1673 1677 1678 1679 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1697 1694 1692 1688 1687 1687 1686 1685 1684 1682 1680 1680 1681 1683 1684 1685 1688 1688 1689 1688 1688 1689 1687 1685 1684 1683 1684 1688 1689 1690 1689 1686 1686 1688 1691 1690 1689 1687 1685 1681 1678 1675 1673 1673 1674 1676 1678 1680 1682 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1699 1699 1696 1694 1692 1689 1686 1685 1684 1683 1682 1681 1680 1682 1684 1686 1687 1687 1690 1692 1691 1690 1692 1691 1690 1689 1686 1685 1687 1689 1692 1692 1691 1689 1689 1691 1692 1693 1691 1688 1686 1682 1677 1675 1675 1676 1677 1680 1681 1683 1684 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1698 1696 1694 1691 1689 1687 1685 1684 1683 1682 1682 1682 1684 1686 1690 1690 1691 1694 1694 1694 1695 1694 1693 1691 1691 1689 1689 1690 1692 1693 1694 1693 1692 1693 1693 1695 1694 1692 1688 1685 1682 1678 1676 1679 1679 1680 1683 1684 1685 1686 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1698 1697 1695 1693 1690 1689 1687 1686 1685 1685 1685 1684 1685 1687 1691 1693 1694 1696 1696 1698 1698 1697 1696 1694 1693 1693 1692 1692 1694 1695 1696 1695 1696 1695 1696 1696 1693 1692 1690 1687 1683 1680 1679 1681 1684 1683 1686 1688 1688 1690 1688 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1695 1694 1692 1690 1689 1689 1689 1688 1687 1686 1686 1689 1692 1694 1696 1698 1699 1700 1700 1700 1699 1697 1696 1696 1695 1694 1697 1697 1699 1698 1698 1696 1698 1697 1696 1694 1691 1689 1685 1683 1681 1686 1687 1688 1687 1691 1689 1691 1691 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1700 1700 1697 1696 1694 1693 1692 1691 1690 1690 1690 1688 1687 1690 1692 1694 1697 1699 1701 1700 1701 1701 1702 1698 1700 1698 1698 1697 1699 1699 1700 1700 1699 1701 1700 1699 1699 1696 1693 1690 1687 1685 1687 1689 1691 1691 1691 1693 1693 1692 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1698 1698 1698 1693 1693 1694 1693 1692 1692 1691 1689 1690 1693 1695 1697 1700 1701 1702 1702 1704 1702 1702 1703 1703 1701 1700 1699 1701 1702 1702 1705 1704 1702 1702 1700 1697 1695 1693 1691 1690 1690 1694 1694 1696 1696 1695 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1697 1698 1696 1695 1695 1695 1694 1694 1693 1693 1696 1698 1699 1701 1702 1705 1704 1704 1703 1704 1704 1702 1702 1702 1703 1704 1703 1706 1706 1705 1702 1703 1701 1698 1695 1694 1695 1696 1697 1697 1699 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1697 1697 1696 1697 1697 1696 1696 1694 1695 1697 1699 1700 1703 1704 1705 1704 1706 1705 1706 1702 1703 1705 1705 1708 1707 1703 1708 1708 1706 1706 1705 1703 1701 1699 1699 1699 1698 1700 1700 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1697 1698 1698 1700 1697 1698 1697 1699 1700 1702 1702 1705 1705 1706 1706 1706 1705 1706 1705 1707 1709 1706 1706 1708 1708 1709 1708 1706 1705 1705 1701 1700 1700 1701 1704 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1699 1701 1700 1699 1699 1700 1699 1699 1704 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 1709 1710 1710 1710 1710 1707 1708 1704 1704 1706 1704 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1699 1700 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1709 1709 1707 1707 1708 1707 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1710 1710 1709 1708 1709 1708 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1711 1710 1710 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+ncols 76
+nrows 55
+xllcorner 0
+yllcorner 0
+cellsize 10
+NODATA_value -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1708 -9999 1707 1708 -9999 1708 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1709 1708 1708 1708 1707 1708 1708 1707 1707 1707 1706 1705 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1708 1708 1707 1707 1707 1708 1707 1707 1706 1706 1705 1705 1707 1706 1705 1706 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1706 1707 1707 1707 1707 1707 1707 1707 1706 1706 1705 1705 1705 1705 1705 1706 1707 1706 1705 1705 1705 1705 1707 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1705 1705 1706 1706 1707 1706 1706 1707 1706 1706 1705 1704 1704 1703 1704 1704 1703 1704 1705 1704 1704 1705 1706 1705 1706 1704 1704 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1704 1704 1704 1704 1705 1704 1705 1705 1705 1706 1704 1704 1704 1703 1702 1702 1701 1702 1702 1704 1704 1705 1704 1704 1704 1705 1705 1703 1705 1704 1704 1704 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1704 1703 1702 1702 1703 1702 1703 1704 1703 1704 1704 1703 1702 1701 1700 1699 1699 1698 1700 1701 1702 1703 1703 1704 1704 1704 1704 1704 1705 1703 1702 1702 1702 1703 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1702 1702 1701 1700 1701 1701 1701 1702 1702 1702 1703 1702 1701 1699 1698 1696 1697 1695 1696 1699 1700 1699 1700 1700 1702 1702 1702 1702 1703 1702 1701 1701 1701 1701 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1700 1699 1698 1698 1698 1699 1698 1700 1699 1699 1699 1700 1699 1697 1696 1693 1693 1693 1694 1696 1698 1698 1698 1698 1699 1699 1700 1701 1700 1700 1699 1698 1699 1699 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1699 1698 1697 1696 1696 1695 1695 1696 1697 1697 1697 1697 1696 1696 1695 1693 1691 1689 1689 1691 1692 1695 1696 1695 1695 1695 1696 1697 1698 1698 1697 1695 1695 1696 1698 1698 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1702 1700 1698 1695 1694 1693 1692 1692 1693 1693 1693 1694 1693 1694 1693 1692 1692 1690 1688 1686 1686 1688 1691 1692 1693 1691 1692 1692 1694 1694 1695 1694 1693 1692 1692 1693 1695 1696 1697 1698 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1701 1699 1696 1694 1692 1690 1689 1689 1689 1690 1690 1690 1690 1690 1690 1690 1689 1688 1685 1684 1683 1686 1688 1689 1689 1689 1689 1689 1690 1691 1692 1692 1691 1690 1690 1691 1692 1694 1696 1696 1697 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1698 1696 1694 1691 1688 1687 1686 1686 1687 1687 1686 1687 1687 1687 1686 1686 1685 1683 1681 1681 1683 1685 1686 1686 1686 1686 1686 1687 1688 1689 1689 1688 1687 1686 1688 1689 1691 1694 1695 1695 1696 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1699 1696 1694 1691 1688 1685 1684 1684 1684 1684 1683 1683 1684 1683 1683 1683 1682 1681 1679 1678 1681 1683 1683 1683 1683 1682 1683 1684 1686 1687 1686 1685 1684 1684 1685 1687 1689 1691 1693 1693 1695 1694 1694 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1704 1703 1702 1700 1696 1695 1692 1689 1686 1684 1682 1682 1682 1681 1681 1681 1680 1680 1680 1680 1679 1677 1677 1679 1680 1680 1681 1680 1679 1680 1681 1683 1684 1684 1683 1681 1681 1682 1685 1687 1689 1691 1693 1694 1691 1693 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1702 1700 1698 1696 1692 1690 1688 1685 1685 1684 1681 1680 1680 1679 1678 1678 1678 1677 1677 1676 1675 1677 1677 1677 1678 1678 1677 1677 1679 1681 1682 1682 1681 1679 1678 1680 1683 1686 1688 1689 1690 1692 1691 1691 1692 1692 1692 1692 1691 1690 1692 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1706 1705 1705 1703 1701 1699 1696 1694 1692 1691 1690 1688 1687 1685 1683 1682 1681 1680 1678 1679 1676 1676 1676 1675 1675 1675 1675 1675 1675 1674 1676 1677 1678 1679 1679 1679 1677 1676 1678 1681 1684 1686 1688 1688 1689 1691 1691 1691 1690 1691 1689 1690 1690 1690 1689 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1705 1704 1702 1700 1698 1696 1695 1694 1692 1691 1691 1688 1687 1686 1685 1684 1682 1682 1680 1678 1677 1675 1675 1674 1674 1673 1673 1673 1674 1675 1675 1676 1676 1677 1676 1675 1677 1680 1683 1684 1687 1686 1687 1688 1687 1688 1687 1688 1687 1687 1687 1687 1686 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1706 1705 1705 1703 1701 1700 1699 1697 1696 1695 1694 1693 1691 1690 1688 1688 1687 1685 1685 1683 1682 1680 1678 1678 1677 1675 1673 1672 1671 1672 1673 1673 1673 1674 1675 1673 1673 1676 1679 1680 1682 1683 1684 1683 1684 1684 1683 1684 1684 1684 1683 1684 1683 1682 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1704 1703 1702 1700 1700 1699 1698 1697 1696 1694 1693 1692 1691 1689 1689 1688 1687 1684 1683 1681 1681 1679 1677 1677 1674 1673 1670 1670 1670 1670 1671 1672 1671 1672 1674 1678 1678 1680 1680 1680 1679 1680 1680 1680 1680 1680 1681 1680 1680 1679 1679 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1706 1706 1705 1703 1703 1703 1702 1701 1699 1698 1696 1696 1695 1695 1694 1692 1691 1689 1688 1685 1685 1683 1682 1680 1679 1678 1676 1675 1673 1671 1670 1669 1669 1670 1671 1674 1675 1676 1676 1677 1676 1676 1677 1676 1677 1677 1676 1677 1676 1678 1676 1675 1676
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1705 1705 1704 1704 1703 1702 1701 1700 1699 1698 1698 1697 1696 1695 1695 1693 1691 1690 1688 1687 1685 1683 1681 1680 1679 1677 1675 1673 1672 1669 1668 1669 1670 1671 1673 1674 1674 1674 1673 1673 1673 1673 1673 1672 1672 1673 1673 1673 1672 1672 1672
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1705 1705 1704 1704 1704 1703 1702 1701 1701 1701 1700 1697 1697 1697 1694 1693 1692 1690 1689 1686 1685 1682 1681 1679 1678 1676 1674 1674 1670 1668 1668 1669 1670 1670 1672 1672 1671 1671 1670 1670 1670 1669 1669 1669 1669 1669 1669 1669 1668 1669
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1706 1706 1705 1705 1705 1704 1703 1702 1701 1701 1700 1698 1697 1696 1695 1694 1692 1690 1689 1687 1684 1683 1682 1679 1679 1677 1675 1674 1672 1670 1668 1667 1668 1668 1669 1669 1669 1668 1668 1668 1667 1666 1666 1665 1665 1665 1665 1665 1665 1665
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1707 1707 1707 1706 1705 1705 1704 1703 1703 1702 1701 1700 1700 1697 1697 1695 1694 1692 1691 1689 1687 1686 1683 1681 1679 1678 1677 1675 1674 1673 1671 1669 1668 1666 1666 1667 1667 1667 1667 1666 1666 1665 1665 1664 1663 1663 1663 1663 1663 1662 1662 1662
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1708 1706 1706 1705 1704 1704 1702 1702 1701 1700 1699 1698 1696 1695 1694 1692 1690 1689 1688 1685 1684 1681 1679 1676 1675 1673 1673 1672 1670 1669 1669 1667 1667 1667 1666 1666 1666 1666 1665 1665 1665 1664 1663 1663 1663 1662 1662 1662 1661 1661 1661
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1706 1706 1706 1705 1705 1704 1702 1702 1700 1700 1699 1697 1696 1694 1693 1691 1690 1688 1686 1685 1683 1681 1678 1676 1673 1672 1671 1670 1670 1669 1668 1668 1668 1667 1667 1666 1666 1665 1665 1664 1664 1664 1664 1664 1663 1663 1663 1662 1662 1662 1661 1660
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1705 1706 1705 1704 1704 1702 1701 1701 1699 1698 1697 1695 1694 1692 1691 1689 1687 1686 1684 1682 1680 1678 1676 1674 1672 1671 1670 1671 1669 1670 1670 1670 1669 1668 1670 1667 1666 1665 1666 1664 1665 1665 1665 1665 1664 1664 1664 1663 1664 1663 1662 1661
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1705 1704 1705 1704 1704 1703 1702 1701 1700 1698 1697 1696 1695 1694 1692 1690 1688 1686 1684 1682 1681 1679 1678 1676 1674 1672 1672 1673 1672 1673 1672 1672 1672 1673 1671 1671 1673 1673 1669 1667 1665 1666 1666 1668 1668 1667 1666 1667 1665 1664 1666 1665 1663 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1704 1703 1703 1702 1701 1701 1700 1698 1696 1695 1693 1692 1691 1690 1687 1685 1683 1681 1680 1678 1677 1675 1674 1673 1673 1673 1675 1676 1677 1675 1676 1675 1675 1673 1673 1674 1675 1673 1672 1672 1672 1670 1671 1670 1669 1668 1668 1666 1665 1666 1665 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1703 1702 1701 1700 1700 1699 1699 1698 1696 1694 1692 1691 1690 1688 1687 1685 1682 1681 1679 1678 1676 1675 1675 1674 1674 1676 1674 1676 1678 1679 1679 1679 1679 1677 1675 1674 1676 1679 1679 1679 1678 1674 1674 1673 1671 1670 1669 1668 1666 1666 1668 1668 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1699 1698 1697 1697 1697 1696 1695 1692 1691 1689 1686 1685 1684 1682 1680 1679 1676 1676 1675 1675 1676 1677 1678 1677 1676 1678 1681 1682 1681 1683 1682 1679 1677 1678 1679 1681 1682 1682 1680 1678 1677 1675 1673 1671 1669 1668 1666 1668 1671 1671 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1701 1699 1697 1696 1694 1695 1694 1694 1693 1691 1688 1686 1683 1683 1681 1680 1679 1677 1676 1676 1678 1680 1681 1680 1678 1679 1677 1678 1681 1683 1684 1685 1684 1682 1678 1680 1682 1684 1684 1684 1683 1680 1678 1676 1673 1671 1669 1668 1668 1671 1673 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1698 1696 1694 1692 1691 1691 1692 1691 1690 1687 1685 1682 1680 1679 1678 1677 1677 1677 1681 1682 1682 1683 1683 1684 1682 1682 1680 1683 1686 1685 1687 1686 1683 1681 1681 1684 1686 1687 1686 1685 1681 1679 1676 1673 1671 1669 1671 1672 1675 1676 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1703 1701 1700 1698 1696 1693 1691 1689 1689 1690 1689 1687 1685 1684 1681 1679 1679 1680 1681 1682 1684 1684 1687 1685 1686 1687 1687 1684 1682 1681 1684 1687 1688 1689 1687 1685 1682 1685 1688 1688 1688 1687 1685 1681 1678 1676 1673 1671 1672 1673 1677 1678 1679 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1697 1694 1692 1688 1687 1687 1686 1685 1684 1682 1680 1680 1681 1683 1684 1685 1688 1688 1689 1688 1688 1689 1687 1685 1684 1683 1684 1688 1689 1690 1689 1686 1686 1688 1691 1690 1689 1687 1685 1681 1678 1675 1673 1673 1674 1676 1678 1680 1682 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1699 1699 1696 1694 1692 1689 1686 1685 1684 1683 1682 1681 1680 1682 1684 1686 1687 1687 1690 1692 1691 1690 1692 1691 1690 1689 1686 1685 1687 1689 1692 1692 1691 1689 1689 1691 1692 1693 1691 1688 1686 1682 1677 1675 1675 1676 1677 1680 1681 1683 1684 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1698 1696 1694 1691 1689 1687 1685 1684 1683 1682 1682 1682 1684 1686 1690 1690 1691 1694 1694 1694 1695 1694 1693 1691 1691 1689 1689 1690 1692 1693 1694 1693 1692 1693 1693 1695 1694 1692 1688 1685 1682 1678 1676 1679 1679 1680 1683 1684 1685 1686 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1698 1697 1695 1693 1690 1689 1687 1686 1685 1685 1685 1684 1685 1687 1691 1693 1694 1696 1696 1698 1698 1697 1696 1694 1693 1693 1692 1692 1694 1695 1696 1695 1696 1695 1696 1696 1693 1692 1690 1687 1683 1680 1679 1681 1684 1683 1686 1688 1688 1690 1688 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1695 1694 1692 1690 1689 1689 1689 1688 1687 1686 1686 1689 1692 1694 1696 1698 1699 1700 1700 1700 1699 1697 1696 1696 1695 1694 1697 1697 1699 1698 1698 1696 1698 1697 1696 1694 1691 1689 1685 1683 1681 1686 1687 1688 1687 1691 1689 1691 1691 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1700 1700 1697 1696 1694 1693 1692 1691 1690 1690 1690 1688 1687 1690 1692 1694 1697 1699 1701 1700 1701 1701 1702 1698 1700 1698 1698 1697 1699 1699 1700 1700 1699 1701 1700 1699 1699 1696 1693 1690 1687 1685 1687 1689 1691 1691 1691 1693 1693 1692 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1698 1698 1698 1693 1693 1694 1693 1692 1692 1691 1689 1690 1693 1695 1697 1700 1701 1702 1702 1704 1702 1702 1703 1703 1701 1700 1699 1701 1702 1702 1705 1704 1702 1702 1700 1697 1695 1693 1691 1690 1690 1694 1694 1696 1696 1695 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1697 1698 1696 1695 1695 1695 1694 1694 1693 1693 1696 1698 1699 1701 1702 1705 1704 1704 1703 1704 1704 1702 1702 1702 1703 1704 1703 1706 1706 1705 1702 1703 1701 1698 1695 1694 1695 1696 1697 1697 1699 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1697 1697 1696 1697 1697 1696 1696 1694 1695 1697 1699 1700 1703 1704 1705 1704 1706 1705 1706 1702 1703 1705 1705 1708 1707 1703 1708 1708 1706 1706 1705 1703 1701 1699 1699 1699 1698 1700 1700 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1697 1698 1698 1700 1697 1698 1697 1699 1700 1702 1702 1705 1705 1706 1706 1706 1705 1706 1705 1707 1709 1706 1706 1708 1708 1709 1708 1706 1705 1705 1701 1700 1700 1701 1704 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1699 1701 1700 1699 1699 1700 1699 1699 1704 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 1709 1710 1710 1710 1710 1707 1708 1704 1704 1706 1704 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1699 1700 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1709 1709 1707 1707 1708 1707 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1710 1710 1709 1708 1709 1708 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1711 1710 1710 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
diff --git a/docs/source/tutorials/network_sediment_transporter/nst_scaling_profiling.ipynb b/docs/source/tutorials/network_sediment_transporter/nst_scaling_profiling.ipynb
index 98e988c78c..5f277a2c53 100644
--- a/docs/source/tutorials/network_sediment_transporter/nst_scaling_profiling.ipynb
+++ b/docs/source/tutorials/network_sediment_transporter/nst_scaling_profiling.ipynb
@@ -77,7 +77,7 @@
"- `y_of_node`\n",
"- `nodes_at_link`\n",
"\n",
- "These inputs and outputs are defined in the function docstring below. The function was designed to produce output that could be directly provided to the [`NetworkModelGrid`](https://landlab.readthedocs.io/en/master/reference/grid/network_api.html#module-landlab.grid.network) init function. "
+ "These inputs and outputs are defined in the function docstring below. The function was designed to produce output that could be directly provided to the [`NetworkModelGrid`](https://landlab.csdms.io/generated/api/landlab.grid.network.html) init function. "
]
},
{
@@ -214,7 +214,7 @@
"source": [
"### 1b: Generic grid.\n",
"\n",
- "In order to run the NST, our grids need fields related to channel geometry and flow characteristics. Here, we'll create a function that takes only the number of layers and uses the function `create_node_xy_and_links` that we just created, creates a grid, adds, those fields and populate them with generic values. The NST also needs a [`FlowDirectorSteepest`](https://landlab.readthedocs.io/en/master/reference/components/flow_director.html?highlight=FlowDirectorSteepest#module-landlab.components.flow_director.flow_director_steepest) instance, so we'll create that too. \n",
+ "In order to run the NST, our grids need fields related to channel geometry and flow characteristics. Here, we'll create a function that takes only the number of layers and uses the function `create_node_xy_and_links` that we just created, creates a grid, adds, those fields and populate them with generic values. The NST also needs a [`FlowDirectorSteepest`](https://landlab.csdms.io/generated/api/landlab.components.flow_director.flow_director_steepest.html) instance, so we'll create that too. \n",
"\n",
"Thus, with these two functions we can specifiy the desired number of layers and get both of these objects we need to instantiate the NST. "
]
diff --git a/docs/source/tutorials/network_sediment_transporter/run_network_generator_OpenTopoDEM.ipynb b/docs/source/tutorials/network_sediment_transporter/run_network_generator_OpenTopoDEM.ipynb
index 774e05fc6b..2a25288426 100644
--- a/docs/source/tutorials/network_sediment_transporter/run_network_generator_OpenTopoDEM.ipynb
+++ b/docs/source/tutorials/network_sediment_transporter/run_network_generator_OpenTopoDEM.ipynb
@@ -43,7 +43,7 @@
"source": [
"Create a function to download and save SRTM images using [BMI_topography](https://bmi-topography.readthedocs.io/en/latest/).\n",
"* From: \n",
- "https://github.com/landlab/landlab/blob/master/notebooks/tutorials/flow_direction_and_accumulation/PriorityFlood_realDEMs.ipynb"
+ "https://github.com/landlab/landlab/blob/master/docs/source/tutorials/flow_direction_and_accumulation/PriorityFlood_realDEMs.ipynb"
]
},
{
@@ -353,7 +353,7 @@
"metadata": {},
"source": [
"### Create a mask to isolate the largest watershed:\n",
- "Here we use the get_watershed_mask_with_area_threshhold function: https://landlab.readthedocs.io/en/master/reference/utils/watershed.html#landlab.utils.watershed.get_watershed_masks_with_area_threshold with a critical threshhold as the maximum drainage area. (This will filter out all watersheds draining to an area smaller than this.) "
+ "Here we use the [get_watershed_mask_with_area_threshhold](https://landlab.csdms.io/generated/api/landlab.utils.watershed.html#landlab.utils.watershed.get_watershed_masks_with_area_threshold) function with a critical threshhold as the maximum drainage area. (This will filter out all watersheds draining to an area smaller than this.) "
]
},
{
diff --git a/docs/source/tutorials/output/writing_legacy_vtk_files.ipynb b/docs/source/tutorials/output/writing_legacy_vtk_files.ipynb
index f7b8ffbae2..21df1eabc1 100644
--- a/docs/source/tutorials/output/writing_legacy_vtk_files.ipynb
+++ b/docs/source/tutorials/output/writing_legacy_vtk_files.ipynb
@@ -9,7 +9,7 @@
"\n",
"*(GE Tucker, CU Boulder, first version June 2023)*\n",
"\n",
- "The [Visualization Toolkit (VTK)](https://docs.vtk.org/en/latest/index.html) is an open-source software system for visualization. It offers two file formats: one based on XML, and the other---the so-called **legacy VTK** format---using a simple text-based format. These file formats are readable by visualization packages such as [ParaView](https://www.paraview.org/), so it is useful to be able to output VTK format for Landlab grids and fields. This tutorial demonstrates Landlab's legacy VTK file-output capability.\n",
+ "The [Visualization Toolkit (VTK)](https://docs.vtk.org/en/latest/) is an open-source software system for visualization. It offers two file formats: one based on XML, and the other---the so-called **legacy VTK** format---using a simple text-based format. These file formats are readable by visualization packages such as [ParaView](https://www.paraview.org/), so it is useful to be able to output VTK format for Landlab grids and fields. This tutorial demonstrates Landlab's legacy VTK file-output capability.\n",
"\n",
"## The format\n",
"\n",
diff --git a/docs/source/tutorials/overland_flow/how_to_d4_pitfill_a_dem.ipynb b/docs/source/tutorials/overland_flow/how_to_d4_pitfill_a_dem.ipynb
index 00b8137cc2..0b323fecbe 100644
--- a/docs/source/tutorials/overland_flow/how_to_d4_pitfill_a_dem.ipynb
+++ b/docs/source/tutorials/overland_flow/how_to_d4_pitfill_a_dem.ipynb
@@ -40,7 +40,7 @@
"id": "3",
"metadata": {},
"source": [
- "Read the un-filled DEM, which happens to be in Arc/Info ASCII Grid format (a.k.a., ESRI ASCII). We will use the `set_watershed_boundary_condition` function to set all nodes with an elevation value equal to a \"no data\" code (default -9999) to closed boundaries, and any nodes with valid elevation values that lie on the grid's perimeter to open (fixed value) boundaries. You can learn more about the raster version of this handy function [here](https://landlab.readthedocs.io/en/latest/reference/grid/raster_api.html#landlab.grid.raster.RasterModelGrid.set_watershed_boundary_condition). "
+ "Read the un-filled DEM, which happens to be in Arc/Info ASCII Grid format (a.k.a., ESRI ASCII). We will use the `set_watershed_boundary_condition` function to set all nodes with an elevation value equal to a \"no data\" code (default -9999) to closed boundaries, and any nodes with valid elevation values that lie on the grid's perimeter to open (fixed value) boundaries. You can learn more about the raster version of this handy function [here](https://landlab.csdms.io/generated/api/landlab.grid.raster.html#landlab.grid.raster.RasterModelGrid.set_watershed_boundary_condition). "
]
},
{
diff --git a/docs/source/tutorials/overland_flow/hugo_site.asc b/docs/source/tutorials/overland_flow/hugo_site.asc
index 8d37cafd42..61c8e89340 100644
--- a/docs/source/tutorials/overland_flow/hugo_site.asc
+++ b/docs/source/tutorials/overland_flow/hugo_site.asc
@@ -1,61 +1,61 @@
-ncols 76
-nrows 55
-xllcorner 0
-yllcorner 0
-cellsize 10
-NODATA_value -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1708 -9999 1707 1708 -9999 1708 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1709 1708 1708 1708 1707 1708 1708 1707 1707 1707 1706 1705 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1708 1708 1707 1707 1707 1708 1707 1707 1706 1706 1705 1705 1707 1706 1705 1706 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1706 1707 1707 1707 1707 1707 1707 1707 1706 1706 1705 1705 1705 1705 1705 1706 1707 1706 1705 1705 1705 1705 1707 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1705 1705 1706 1706 1707 1706 1706 1707 1706 1706 1705 1704 1704 1703 1704 1704 1703 1704 1705 1704 1704 1705 1706 1705 1706 1704 1704 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1704 1704 1704 1704 1705 1704 1705 1705 1705 1706 1704 1704 1704 1703 1702 1702 1701 1702 1702 1704 1704 1705 1704 1704 1704 1705 1705 1703 1705 1704 1704 1704 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1704 1703 1702 1702 1703 1702 1703 1704 1703 1704 1704 1703 1702 1701 1700 1699 1699 1698 1700 1701 1702 1703 1703 1704 1704 1704 1704 1704 1705 1703 1702 1702 1702 1703 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1702 1702 1701 1700 1701 1701 1701 1702 1702 1702 1703 1702 1701 1699 1698 1696 1697 1695 1696 1699 1700 1699 1700 1700 1702 1702 1702 1702 1703 1702 1701 1701 1701 1701 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1700 1699 1698 1698 1698 1699 1698 1700 1699 1699 1699 1700 1699 1697 1696 1693 1693 1693 1694 1696 1698 1698 1698 1698 1699 1699 1700 1701 1700 1700 1699 1698 1699 1699 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1699 1698 1697 1696 1696 1695 1695 1696 1697 1697 1697 1697 1696 1696 1695 1693 1691 1689 1689 1691 1692 1695 1696 1695 1695 1695 1696 1697 1698 1698 1697 1695 1695 1696 1698 1698 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1702 1700 1698 1695 1694 1693 1692 1692 1693 1693 1693 1694 1693 1694 1693 1692 1692 1690 1688 1686 1686 1688 1691 1692 1693 1691 1692 1692 1694 1694 1695 1694 1693 1692 1692 1693 1695 1696 1697 1698 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1701 1699 1696 1694 1692 1690 1689 1689 1689 1690 1690 1690 1690 1690 1690 1690 1689 1688 1685 1684 1683 1686 1688 1689 1689 1689 1689 1689 1690 1691 1692 1692 1691 1690 1690 1691 1692 1694 1696 1696 1697 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1698 1696 1694 1691 1688 1687 1686 1686 1687 1687 1686 1687 1687 1687 1686 1686 1685 1683 1681 1681 1683 1685 1686 1686 1686 1686 1686 1687 1688 1689 1689 1688 1687 1686 1688 1689 1691 1694 1695 1695 1696 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1699 1696 1694 1691 1688 1685 1684 1684 1684 1684 1683 1683 1684 1683 1683 1683 1682 1681 1679 1678 1681 1683 1683 1683 1683 1682 1683 1684 1686 1687 1686 1685 1684 1684 1685 1687 1689 1691 1693 1693 1695 1694 1694 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1704 1703 1702 1700 1696 1695 1692 1689 1686 1684 1682 1682 1682 1681 1681 1681 1680 1680 1680 1680 1679 1677 1677 1679 1680 1680 1681 1680 1679 1680 1681 1683 1684 1684 1683 1681 1681 1682 1685 1687 1689 1691 1693 1694 1691 1693 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1702 1700 1698 1696 1692 1690 1688 1685 1685 1684 1681 1680 1680 1679 1678 1678 1678 1677 1677 1676 1675 1677 1677 1677 1678 1678 1677 1677 1679 1681 1682 1682 1681 1679 1678 1680 1683 1686 1688 1689 1690 1692 1691 1691 1692 1692 1692 1692 1691 1690 1692 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1706 1705 1705 1703 1701 1699 1696 1694 1692 1691 1690 1688 1687 1685 1683 1682 1681 1680 1678 1679 1676 1676 1676 1675 1675 1675 1675 1675 1675 1674 1676 1677 1678 1679 1679 1679 1677 1676 1678 1681 1684 1686 1688 1688 1689 1691 1691 1691 1690 1691 1689 1690 1690 1690 1689 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1705 1704 1702 1700 1698 1696 1695 1694 1692 1691 1691 1688 1687 1686 1685 1684 1682 1682 1680 1678 1677 1675 1675 1674 1674 1673 1673 1673 1674 1675 1675 1676 1676 1677 1676 1675 1677 1680 1683 1684 1687 1686 1687 1688 1687 1688 1687 1688 1687 1687 1687 1687 1686 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1706 1705 1705 1703 1701 1700 1699 1697 1696 1695 1694 1693 1691 1690 1688 1688 1687 1685 1685 1683 1682 1680 1678 1678 1677 1675 1673 1672 1671 1672 1673 1673 1673 1674 1675 1673 1673 1676 1679 1680 1682 1683 1684 1683 1684 1684 1683 1684 1684 1684 1683 1684 1683 1682 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1704 1703 1702 1700 1700 1699 1698 1697 1696 1694 1693 1692 1691 1689 1689 1688 1687 1684 1683 1681 1681 1679 1677 1677 1674 1673 1670 1670 1670 1670 1671 1672 1671 1672 1674 1678 1678 1680 1680 1680 1679 1680 1680 1680 1680 1680 1681 1680 1680 1679 1679 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1706 1706 1705 1703 1703 1703 1702 1701 1699 1698 1696 1696 1695 1695 1694 1692 1691 1689 1688 1685 1685 1683 1682 1680 1679 1678 1676 1675 1673 1671 1670 1669 1669 1670 1671 1674 1675 1676 1676 1677 1676 1676 1677 1676 1677 1677 1676 1677 1676 1678 1676 1675 1676
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1705 1705 1704 1704 1703 1702 1701 1700 1699 1698 1698 1697 1696 1695 1695 1693 1691 1690 1688 1687 1685 1683 1681 1680 1679 1677 1675 1673 1672 1669 1668 1669 1670 1671 1673 1674 1674 1674 1673 1673 1673 1673 1673 1672 1672 1673 1673 1673 1672 1672 1672
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1705 1705 1704 1704 1704 1703 1702 1701 1701 1701 1700 1697 1697 1697 1694 1693 1692 1690 1689 1686 1685 1682 1681 1679 1678 1676 1674 1674 1670 1668 1668 1669 1670 1670 1672 1672 1671 1671 1670 1670 1670 1669 1669 1669 1669 1669 1669 1669 1668 1669
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1706 1706 1705 1705 1705 1704 1703 1702 1701 1701 1700 1698 1697 1696 1695 1694 1692 1690 1689 1687 1684 1683 1682 1679 1679 1677 1675 1674 1672 1670 1668 1667 1668 1668 1669 1669 1669 1668 1668 1668 1667 1666 1666 1665 1665 1665 1665 1665 1665 1665
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1707 1707 1707 1706 1705 1705 1704 1703 1703 1702 1701 1700 1700 1697 1697 1695 1694 1692 1691 1689 1687 1686 1683 1681 1679 1678 1677 1675 1674 1673 1671 1669 1668 1666 1666 1667 1667 1667 1667 1666 1666 1665 1665 1664 1663 1663 1663 1663 1663 1662 1662 1662
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1708 1706 1706 1705 1704 1704 1702 1702 1701 1700 1699 1698 1696 1695 1694 1692 1690 1689 1688 1685 1684 1681 1679 1676 1675 1673 1673 1672 1670 1669 1669 1667 1667 1667 1666 1666 1666 1666 1665 1665 1665 1664 1663 1663 1663 1662 1662 1662 1661 1661 1661
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1706 1706 1706 1705 1705 1704 1702 1702 1700 1700 1699 1697 1696 1694 1693 1691 1690 1688 1686 1685 1683 1681 1678 1676 1673 1672 1671 1670 1670 1669 1668 1668 1668 1667 1667 1666 1666 1665 1665 1664 1664 1664 1664 1664 1663 1663 1663 1662 1662 1662 1661 1660
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1705 1706 1705 1704 1704 1702 1701 1701 1699 1698 1697 1695 1694 1692 1691 1689 1687 1686 1684 1682 1680 1678 1676 1674 1672 1671 1670 1671 1669 1670 1670 1670 1669 1668 1670 1667 1666 1665 1666 1664 1665 1665 1665 1665 1664 1664 1664 1663 1664 1663 1662 1661
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1705 1704 1705 1704 1704 1703 1702 1701 1700 1698 1697 1696 1695 1694 1692 1690 1688 1686 1684 1682 1681 1679 1678 1676 1674 1672 1672 1673 1672 1673 1672 1672 1672 1673 1671 1671 1673 1673 1669 1667 1665 1666 1666 1668 1668 1667 1666 1667 1665 1664 1666 1665 1663 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1704 1703 1703 1702 1701 1701 1700 1698 1696 1695 1693 1692 1691 1690 1687 1685 1683 1681 1680 1678 1677 1675 1674 1673 1673 1673 1675 1676 1677 1675 1676 1675 1675 1673 1673 1674 1675 1673 1672 1672 1672 1670 1671 1670 1669 1668 1668 1666 1665 1666 1665 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1703 1702 1701 1700 1700 1699 1699 1698 1696 1694 1692 1691 1690 1688 1687 1685 1682 1681 1679 1678 1676 1675 1675 1674 1674 1676 1674 1676 1678 1679 1679 1679 1679 1677 1675 1674 1676 1679 1679 1679 1678 1674 1674 1673 1671 1670 1669 1668 1666 1666 1668 1668 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1699 1698 1697 1697 1697 1696 1695 1692 1691 1689 1686 1685 1684 1682 1680 1679 1676 1676 1675 1675 1676 1677 1678 1677 1676 1678 1681 1682 1681 1683 1682 1679 1677 1678 1679 1681 1682 1682 1680 1678 1677 1675 1673 1671 1669 1668 1666 1668 1671 1671 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1701 1699 1697 1696 1694 1695 1694 1694 1693 1691 1688 1686 1683 1683 1681 1680 1679 1677 1676 1676 1678 1680 1681 1680 1678 1679 1677 1678 1681 1683 1684 1685 1684 1682 1678 1680 1682 1684 1684 1684 1683 1680 1678 1676 1673 1671 1669 1668 1668 1671 1673 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1698 1696 1694 1692 1691 1691 1692 1691 1690 1687 1685 1682 1680 1679 1678 1677 1677 1677 1681 1682 1682 1683 1683 1684 1682 1682 1680 1683 1686 1685 1687 1686 1683 1681 1681 1684 1686 1687 1686 1685 1681 1679 1676 1673 1671 1669 1671 1672 1675 1676 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1703 1701 1700 1698 1696 1693 1691 1689 1689 1690 1689 1687 1685 1684 1681 1679 1679 1680 1681 1682 1684 1684 1687 1685 1686 1687 1687 1684 1682 1681 1684 1687 1688 1689 1687 1685 1682 1685 1688 1688 1688 1687 1685 1681 1678 1676 1673 1671 1672 1673 1677 1678 1679 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1697 1694 1692 1688 1687 1687 1686 1685 1684 1682 1680 1680 1681 1683 1684 1685 1688 1688 1689 1688 1688 1689 1687 1685 1684 1683 1684 1688 1689 1690 1689 1686 1686 1688 1691 1690 1689 1687 1685 1681 1678 1675 1673 1673 1674 1676 1678 1680 1682 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1699 1699 1696 1694 1692 1689 1686 1685 1684 1683 1682 1681 1680 1682 1684 1686 1687 1687 1690 1692 1691 1690 1692 1691 1690 1689 1686 1685 1687 1689 1692 1692 1691 1689 1689 1691 1692 1693 1691 1688 1686 1682 1677 1675 1675 1676 1677 1680 1681 1683 1684 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1698 1696 1694 1691 1689 1687 1685 1684 1683 1682 1682 1682 1684 1686 1690 1690 1691 1694 1694 1694 1695 1694 1693 1691 1691 1689 1689 1690 1692 1693 1694 1693 1692 1693 1693 1695 1694 1692 1688 1685 1682 1678 1676 1679 1679 1680 1683 1684 1685 1686 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1698 1697 1695 1693 1690 1689 1687 1686 1685 1685 1685 1684 1685 1687 1691 1693 1694 1696 1696 1698 1698 1697 1696 1694 1693 1693 1692 1692 1694 1695 1696 1695 1696 1695 1696 1696 1693 1692 1690 1687 1683 1680 1679 1681 1684 1683 1686 1688 1688 1690 1688 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1695 1694 1692 1690 1689 1689 1689 1688 1687 1686 1686 1689 1692 1694 1696 1698 1699 1700 1700 1700 1699 1697 1696 1696 1695 1694 1697 1697 1699 1698 1698 1696 1698 1697 1696 1694 1691 1689 1685 1683 1681 1686 1687 1688 1687 1691 1689 1691 1691 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1700 1700 1697 1696 1694 1693 1692 1691 1690 1690 1690 1688 1687 1690 1692 1694 1697 1699 1701 1700 1701 1701 1702 1698 1700 1698 1698 1697 1699 1699 1700 1700 1699 1701 1700 1699 1699 1696 1693 1690 1687 1685 1687 1689 1691 1691 1691 1693 1693 1692 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1698 1698 1698 1693 1693 1694 1693 1692 1692 1691 1689 1690 1693 1695 1697 1700 1701 1702 1702 1704 1702 1702 1703 1703 1701 1700 1699 1701 1702 1702 1705 1704 1702 1702 1700 1697 1695 1693 1691 1690 1690 1694 1694 1696 1696 1695 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1697 1698 1696 1695 1695 1695 1694 1694 1693 1693 1696 1698 1699 1701 1702 1705 1704 1704 1703 1704 1704 1702 1702 1702 1703 1704 1703 1706 1706 1705 1702 1703 1701 1698 1695 1694 1695 1696 1697 1697 1699 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1697 1697 1696 1697 1697 1696 1696 1694 1695 1697 1699 1700 1703 1704 1705 1704 1706 1705 1706 1702 1703 1705 1705 1708 1707 1703 1708 1708 1706 1706 1705 1703 1701 1699 1699 1699 1698 1700 1700 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1697 1698 1698 1700 1697 1698 1697 1699 1700 1702 1702 1705 1705 1706 1706 1706 1705 1706 1705 1707 1709 1706 1706 1708 1708 1709 1708 1706 1705 1705 1701 1700 1700 1701 1704 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1699 1701 1700 1699 1699 1700 1699 1699 1704 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 1709 1710 1710 1710 1710 1707 1708 1704 1704 1706 1704 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1699 1700 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1709 1709 1707 1707 1708 1707 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1710 1710 1709 1708 1709 1708 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1711 1710 1710 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+ncols 76
+nrows 55
+xllcorner 0
+yllcorner 0
+cellsize 10
+NODATA_value -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1708 -9999 1707 1708 -9999 1708 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1709 1708 1708 1708 1707 1708 1708 1707 1707 1707 1706 1705 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1708 1708 1707 1707 1707 1708 1707 1707 1706 1706 1705 1705 1707 1706 1705 1706 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1706 1707 1707 1707 1707 1707 1707 1707 1706 1706 1705 1705 1705 1705 1705 1706 1707 1706 1705 1705 1705 1705 1707 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1705 1705 1706 1706 1707 1706 1706 1707 1706 1706 1705 1704 1704 1703 1704 1704 1703 1704 1705 1704 1704 1705 1706 1705 1706 1704 1704 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1704 1704 1704 1704 1705 1704 1705 1705 1705 1706 1704 1704 1704 1703 1702 1702 1701 1702 1702 1704 1704 1705 1704 1704 1704 1705 1705 1703 1705 1704 1704 1704 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1704 1703 1702 1702 1703 1702 1703 1704 1703 1704 1704 1703 1702 1701 1700 1699 1699 1698 1700 1701 1702 1703 1703 1704 1704 1704 1704 1704 1705 1703 1702 1702 1702 1703 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1702 1702 1701 1700 1701 1701 1701 1702 1702 1702 1703 1702 1701 1699 1698 1696 1697 1695 1696 1699 1700 1699 1700 1700 1702 1702 1702 1702 1703 1702 1701 1701 1701 1701 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1700 1699 1698 1698 1698 1699 1698 1700 1699 1699 1699 1700 1699 1697 1696 1693 1693 1693 1694 1696 1698 1698 1698 1698 1699 1699 1700 1701 1700 1700 1699 1698 1699 1699 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1699 1698 1697 1696 1696 1695 1695 1696 1697 1697 1697 1697 1696 1696 1695 1693 1691 1689 1689 1691 1692 1695 1696 1695 1695 1695 1696 1697 1698 1698 1697 1695 1695 1696 1698 1698 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1702 1700 1698 1695 1694 1693 1692 1692 1693 1693 1693 1694 1693 1694 1693 1692 1692 1690 1688 1686 1686 1688 1691 1692 1693 1691 1692 1692 1694 1694 1695 1694 1693 1692 1692 1693 1695 1696 1697 1698 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1701 1699 1696 1694 1692 1690 1689 1689 1689 1690 1690 1690 1690 1690 1690 1690 1689 1688 1685 1684 1683 1686 1688 1689 1689 1689 1689 1689 1690 1691 1692 1692 1691 1690 1690 1691 1692 1694 1696 1696 1697 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1698 1696 1694 1691 1688 1687 1686 1686 1687 1687 1686 1687 1687 1687 1686 1686 1685 1683 1681 1681 1683 1685 1686 1686 1686 1686 1686 1687 1688 1689 1689 1688 1687 1686 1688 1689 1691 1694 1695 1695 1696 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1699 1696 1694 1691 1688 1685 1684 1684 1684 1684 1683 1683 1684 1683 1683 1683 1682 1681 1679 1678 1681 1683 1683 1683 1683 1682 1683 1684 1686 1687 1686 1685 1684 1684 1685 1687 1689 1691 1693 1693 1695 1694 1694 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1704 1703 1702 1700 1696 1695 1692 1689 1686 1684 1682 1682 1682 1681 1681 1681 1680 1680 1680 1680 1679 1677 1677 1679 1680 1680 1681 1680 1679 1680 1681 1683 1684 1684 1683 1681 1681 1682 1685 1687 1689 1691 1693 1694 1691 1693 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1702 1700 1698 1696 1692 1690 1688 1685 1685 1684 1681 1680 1680 1679 1678 1678 1678 1677 1677 1676 1675 1677 1677 1677 1678 1678 1677 1677 1679 1681 1682 1682 1681 1679 1678 1680 1683 1686 1688 1689 1690 1692 1691 1691 1692 1692 1692 1692 1691 1690 1692 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1706 1705 1705 1703 1701 1699 1696 1694 1692 1691 1690 1688 1687 1685 1683 1682 1681 1680 1678 1679 1676 1676 1676 1675 1675 1675 1675 1675 1675 1674 1676 1677 1678 1679 1679 1679 1677 1676 1678 1681 1684 1686 1688 1688 1689 1691 1691 1691 1690 1691 1689 1690 1690 1690 1689 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1705 1704 1702 1700 1698 1696 1695 1694 1692 1691 1691 1688 1687 1686 1685 1684 1682 1682 1680 1678 1677 1675 1675 1674 1674 1673 1673 1673 1674 1675 1675 1676 1676 1677 1676 1675 1677 1680 1683 1684 1687 1686 1687 1688 1687 1688 1687 1688 1687 1687 1687 1687 1686 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1706 1705 1705 1703 1701 1700 1699 1697 1696 1695 1694 1693 1691 1690 1688 1688 1687 1685 1685 1683 1682 1680 1678 1678 1677 1675 1673 1672 1671 1672 1673 1673 1673 1674 1675 1673 1673 1676 1679 1680 1682 1683 1684 1683 1684 1684 1683 1684 1684 1684 1683 1684 1683 1682 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1704 1703 1702 1700 1700 1699 1698 1697 1696 1694 1693 1692 1691 1689 1689 1688 1687 1684 1683 1681 1681 1679 1677 1677 1674 1673 1670 1670 1670 1670 1671 1672 1671 1672 1674 1678 1678 1680 1680 1680 1679 1680 1680 1680 1680 1680 1681 1680 1680 1679 1679 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1706 1706 1705 1703 1703 1703 1702 1701 1699 1698 1696 1696 1695 1695 1694 1692 1691 1689 1688 1685 1685 1683 1682 1680 1679 1678 1676 1675 1673 1671 1670 1669 1669 1670 1671 1674 1675 1676 1676 1677 1676 1676 1677 1676 1677 1677 1676 1677 1676 1678 1676 1675 1676
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1705 1705 1704 1704 1703 1702 1701 1700 1699 1698 1698 1697 1696 1695 1695 1693 1691 1690 1688 1687 1685 1683 1681 1680 1679 1677 1675 1673 1672 1669 1668 1669 1670 1671 1673 1674 1674 1674 1673 1673 1673 1673 1673 1672 1672 1673 1673 1673 1672 1672 1672
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1705 1705 1704 1704 1704 1703 1702 1701 1701 1701 1700 1697 1697 1697 1694 1693 1692 1690 1689 1686 1685 1682 1681 1679 1678 1676 1674 1674 1670 1668 1668 1669 1670 1670 1672 1672 1671 1671 1670 1670 1670 1669 1669 1669 1669 1669 1669 1669 1668 1669
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1706 1706 1705 1705 1705 1704 1703 1702 1701 1701 1700 1698 1697 1696 1695 1694 1692 1690 1689 1687 1684 1683 1682 1679 1679 1677 1675 1674 1672 1670 1668 1667 1668 1668 1669 1669 1669 1668 1668 1668 1667 1666 1666 1665 1665 1665 1665 1665 1665 1665
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1707 1707 1707 1706 1705 1705 1704 1703 1703 1702 1701 1700 1700 1697 1697 1695 1694 1692 1691 1689 1687 1686 1683 1681 1679 1678 1677 1675 1674 1673 1671 1669 1668 1666 1666 1667 1667 1667 1667 1666 1666 1665 1665 1664 1663 1663 1663 1663 1663 1662 1662 1662
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1708 1706 1706 1705 1704 1704 1702 1702 1701 1700 1699 1698 1696 1695 1694 1692 1690 1689 1688 1685 1684 1681 1679 1676 1675 1673 1673 1672 1670 1669 1669 1667 1667 1667 1666 1666 1666 1666 1665 1665 1665 1664 1663 1663 1663 1662 1662 1662 1661 1661 1661
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1706 1706 1706 1705 1705 1704 1702 1702 1700 1700 1699 1697 1696 1694 1693 1691 1690 1688 1686 1685 1683 1681 1678 1676 1673 1672 1671 1670 1670 1669 1668 1668 1668 1667 1667 1666 1666 1665 1665 1664 1664 1664 1664 1664 1663 1663 1663 1662 1662 1662 1661 1660
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1705 1706 1705 1704 1704 1702 1701 1701 1699 1698 1697 1695 1694 1692 1691 1689 1687 1686 1684 1682 1680 1678 1676 1674 1672 1671 1670 1671 1669 1670 1670 1670 1669 1668 1670 1667 1666 1665 1666 1664 1665 1665 1665 1665 1664 1664 1664 1663 1664 1663 1662 1661
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1705 1704 1705 1704 1704 1703 1702 1701 1700 1698 1697 1696 1695 1694 1692 1690 1688 1686 1684 1682 1681 1679 1678 1676 1674 1672 1672 1673 1672 1673 1672 1672 1672 1673 1671 1671 1673 1673 1669 1667 1665 1666 1666 1668 1668 1667 1666 1667 1665 1664 1666 1665 1663 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1704 1703 1703 1702 1701 1701 1700 1698 1696 1695 1693 1692 1691 1690 1687 1685 1683 1681 1680 1678 1677 1675 1674 1673 1673 1673 1675 1676 1677 1675 1676 1675 1675 1673 1673 1674 1675 1673 1672 1672 1672 1670 1671 1670 1669 1668 1668 1666 1665 1666 1665 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1703 1702 1701 1700 1700 1699 1699 1698 1696 1694 1692 1691 1690 1688 1687 1685 1682 1681 1679 1678 1676 1675 1675 1674 1674 1676 1674 1676 1678 1679 1679 1679 1679 1677 1675 1674 1676 1679 1679 1679 1678 1674 1674 1673 1671 1670 1669 1668 1666 1666 1668 1668 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1699 1698 1697 1697 1697 1696 1695 1692 1691 1689 1686 1685 1684 1682 1680 1679 1676 1676 1675 1675 1676 1677 1678 1677 1676 1678 1681 1682 1681 1683 1682 1679 1677 1678 1679 1681 1682 1682 1680 1678 1677 1675 1673 1671 1669 1668 1666 1668 1671 1671 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1701 1699 1697 1696 1694 1695 1694 1694 1693 1691 1688 1686 1683 1683 1681 1680 1679 1677 1676 1676 1678 1680 1681 1680 1678 1679 1677 1678 1681 1683 1684 1685 1684 1682 1678 1680 1682 1684 1684 1684 1683 1680 1678 1676 1673 1671 1669 1668 1668 1671 1673 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1698 1696 1694 1692 1691 1691 1692 1691 1690 1687 1685 1682 1680 1679 1678 1677 1677 1677 1681 1682 1682 1683 1683 1684 1682 1682 1680 1683 1686 1685 1687 1686 1683 1681 1681 1684 1686 1687 1686 1685 1681 1679 1676 1673 1671 1669 1671 1672 1675 1676 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1703 1701 1700 1698 1696 1693 1691 1689 1689 1690 1689 1687 1685 1684 1681 1679 1679 1680 1681 1682 1684 1684 1687 1685 1686 1687 1687 1684 1682 1681 1684 1687 1688 1689 1687 1685 1682 1685 1688 1688 1688 1687 1685 1681 1678 1676 1673 1671 1672 1673 1677 1678 1679 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1697 1694 1692 1688 1687 1687 1686 1685 1684 1682 1680 1680 1681 1683 1684 1685 1688 1688 1689 1688 1688 1689 1687 1685 1684 1683 1684 1688 1689 1690 1689 1686 1686 1688 1691 1690 1689 1687 1685 1681 1678 1675 1673 1673 1674 1676 1678 1680 1682 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1699 1699 1696 1694 1692 1689 1686 1685 1684 1683 1682 1681 1680 1682 1684 1686 1687 1687 1690 1692 1691 1690 1692 1691 1690 1689 1686 1685 1687 1689 1692 1692 1691 1689 1689 1691 1692 1693 1691 1688 1686 1682 1677 1675 1675 1676 1677 1680 1681 1683 1684 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1698 1696 1694 1691 1689 1687 1685 1684 1683 1682 1682 1682 1684 1686 1690 1690 1691 1694 1694 1694 1695 1694 1693 1691 1691 1689 1689 1690 1692 1693 1694 1693 1692 1693 1693 1695 1694 1692 1688 1685 1682 1678 1676 1679 1679 1680 1683 1684 1685 1686 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1698 1697 1695 1693 1690 1689 1687 1686 1685 1685 1685 1684 1685 1687 1691 1693 1694 1696 1696 1698 1698 1697 1696 1694 1693 1693 1692 1692 1694 1695 1696 1695 1696 1695 1696 1696 1693 1692 1690 1687 1683 1680 1679 1681 1684 1683 1686 1688 1688 1690 1688 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1695 1694 1692 1690 1689 1689 1689 1688 1687 1686 1686 1689 1692 1694 1696 1698 1699 1700 1700 1700 1699 1697 1696 1696 1695 1694 1697 1697 1699 1698 1698 1696 1698 1697 1696 1694 1691 1689 1685 1683 1681 1686 1687 1688 1687 1691 1689 1691 1691 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1700 1700 1697 1696 1694 1693 1692 1691 1690 1690 1690 1688 1687 1690 1692 1694 1697 1699 1701 1700 1701 1701 1702 1698 1700 1698 1698 1697 1699 1699 1700 1700 1699 1701 1700 1699 1699 1696 1693 1690 1687 1685 1687 1689 1691 1691 1691 1693 1693 1692 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1698 1698 1698 1693 1693 1694 1693 1692 1692 1691 1689 1690 1693 1695 1697 1700 1701 1702 1702 1704 1702 1702 1703 1703 1701 1700 1699 1701 1702 1702 1705 1704 1702 1702 1700 1697 1695 1693 1691 1690 1690 1694 1694 1696 1696 1695 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1697 1698 1696 1695 1695 1695 1694 1694 1693 1693 1696 1698 1699 1701 1702 1705 1704 1704 1703 1704 1704 1702 1702 1702 1703 1704 1703 1706 1706 1705 1702 1703 1701 1698 1695 1694 1695 1696 1697 1697 1699 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1697 1697 1696 1697 1697 1696 1696 1694 1695 1697 1699 1700 1703 1704 1705 1704 1706 1705 1706 1702 1703 1705 1705 1708 1707 1703 1708 1708 1706 1706 1705 1703 1701 1699 1699 1699 1698 1700 1700 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1697 1698 1698 1700 1697 1698 1697 1699 1700 1702 1702 1705 1705 1706 1706 1706 1705 1706 1705 1707 1709 1706 1706 1708 1708 1709 1708 1706 1705 1705 1701 1700 1700 1701 1704 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1699 1701 1700 1699 1699 1700 1699 1699 1704 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 1709 1710 1710 1710 1710 1707 1708 1704 1704 1706 1704 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1699 1700 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1709 1709 1707 1707 1708 1707 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1710 1710 1709 1708 1709 1708 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1711 1710 1710 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
diff --git a/docs/source/tutorials/overland_flow/overland_flow_erosion/ol_flow_erosion_components.ipynb b/docs/source/tutorials/overland_flow/overland_flow_erosion/ol_flow_erosion_components.ipynb
index 82f8e5ba47..a0a1559c6d 100644
--- a/docs/source/tutorials/overland_flow/overland_flow_erosion/ol_flow_erosion_components.ipynb
+++ b/docs/source/tutorials/overland_flow/overland_flow_erosion/ol_flow_erosion_components.ipynb
@@ -119,7 +119,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "(See [here](https://landlab.readthedocs.io/en/latest/reference/grid/gradients.html#landlab.grid.gradients.calc_grad_at_link) to learn how `calc_grad_at_link` works, and [here](https://landlab.readthedocs.io/en/latest/reference/grid/raster_mappers.html#landlab.grid.raster_mappers.map_link_vector_components_to_node_raster) to learn how \n",
+ "(See [here](https://landlab.csdms.io/generated/api/landlab.grid.gradients.html#landlab.grid.gradients.calc_grad_at_link) to learn how `calc_grad_at_link` works, and [here](https://landlab.csdms.io/generated/api/landlab.grid.raster_mappers.html#landlab.grid.raster_mappers.map_link_vector_components_to_node_raster) to learn how \n",
"`map_link_vector_components_to_node` works.)\n",
"\n",
"Next, define some parameters we'll need.\n",
diff --git a/docs/source/tutorials/plotting/animate-landlab-output.ipynb b/docs/source/tutorials/plotting/animate-landlab-output.ipynb
index f025245a8a..12bfe607eb 100644
--- a/docs/source/tutorials/plotting/animate-landlab-output.ipynb
+++ b/docs/source/tutorials/plotting/animate-landlab-output.ipynb
@@ -8,7 +8,7 @@
"
\n",
"\n",
"More Landlab tutorials:\n",
- "https://landlab.readthedocs.io/en/latest/user_guide/tutorials.html
\n",
+ "https://landlab.csdms.io/tutorials/\n",
"\n",
"
"
]
diff --git a/docs/source/tutorials/river_flow_dynamics/DEM-kootenai_37x50_1x1.asc b/docs/source/tutorials/river_flow_dynamics/DEM-kootenai_37x50_1x1.asc
new file mode 100644
index 0000000000..e7d8608719
--- /dev/null
+++ b/docs/source/tutorials/river_flow_dynamics/DEM-kootenai_37x50_1x1.asc
@@ -0,0 +1,43 @@
+NCOLS 50
+NROWS 37
+XLLCORNER 556440
+YLLCORNER 5394932
+CELLSIZE 1
+NODATA_value -9999
+543.340026855468977 543.299987792969 543.27001953125 543.260009765625 543.309997558594 543.320007324219 543.340026855469 543.359985351562 543.380004882812 543.400024414062 543.409973144531 543.429992675781 543.440002441406 543.390014648438 543.320007324219 543.340026855469 543.349975585938 543.380004882812 543.450012207031 543.549987792969 543.549987792969 543.559997558594 543.52001953125 543.539978027344 543.539978027344 543.549987792969 543.609985351562 543.659973144531 543.719970703125 543.789978027344 543.719970703125 543.72998046875 543.700012207031 543.799987792969 543.739990234375 543.700012207031 543.530029296875 543.409973144531 543.030029296875 542.330017089844 541.929992675781 541.380004882812 540.679992675781 540.320007324219 540.059997558594 539.830017089844 539.590026855469 539.400024414062 539.27001953125 539.190002441406
+543.359985351562 543.359985351562 543.330017089844 543.280029296875 543.299987792969 543.309997558594 543.309997558594 543.320007324219 543.330017089844 543.340026855469 543.349975585938 543.369995117188 543.340026855469 543.309997558594 543.280029296875 543.320007324219 543.369995117188 543.390014648438 543.429992675781 543.52001953125 543.559997558594 543.570007324219 543.52001953125 543.510009765625 543.510009765625 543.570007324219 543.609985351562 543.710021972656 543.75 543.789978027344 543.710021972656 543.659973144531 543.690002441406 543.690002441406 543.5 543.510009765625 543.030029296875 542.419982910156 541.840026855469 541.450012207031 540.840026855469 540.330017089844 540.150024414062 539.830017089844 539.609985351562 539.419982910156 539.239990234375 539.119995117188 539.010009765625 538.830017089844
+543.380004882812 543.349975585938 543.330017089844 543.340026855469 543.330017089844 543.330017089844 543.280029296875 543.289978027344 543.289978027344 543.289978027344 543.299987792969 543.320007324219 543.299987792969 543.280029296875 543.289978027344 543.320007324219 543.340026855469 543.359985351562 543.429992675781 543.530029296875 543.549987792969 543.539978027344 543.5 543.549987792969 543.609985351562 543.570007324219 543.619995117188 543.75 543.760009765625 543.75 543.690002441406 543.609985351562 543.489990234375 543.22998046875 542.820007324219 542.580017089844 542.059997558594 541.340026855469 540.719970703125 540.400024414062 540.140014648438 539.909973144531 539.580017089844 539.359985351562 539.210021972656 539.070007324219 538.929992675781 538.799987792969 538.650024414062 538.469970703125
+543.409973144531 543.390014648438 543.330017089844 543.320007324219 543.309997558594 543.349975585938 543.260009765625 543.260009765625 543.260009765625 543.27001953125 543.289978027344 543.330017089844 543.320007324219 543.289978027344 543.280029296875 543.299987792969 543.320007324219 543.359985351562 543.390014648438 543.409973144531 543.429992675781 543.469970703125 543.549987792969 543.599975585938 543.650024414062 543.549987792969 543.640014648438 543.77001953125 543.809997558594 543.780029296875 543.659973144531 543.429992675781 542.940002441406 542.440002441406 542.010009765625 541.47998046875 540.900024414062 540.380004882812 540.099975585938 539.820007324219 539.590026855469 539.340026855469 539.260009765625 539.059997558594 538.909973144531 538.809997558594 538.690002441406 538.549987792969 538.380004882812 538.359985351562
+543.349975585938 543.330017089844 543.280029296875 543.299987792969 543.260009765625 543.219970703125 543.22998046875 543.219970703125 543.25 543.280029296875 543.25 543.219970703125 543.27001953125 543.25 543.260009765625 543.25 543.299987792969 543.330017089844 543.320007324219 543.369995117188 543.460021972656 543.549987792969 543.570007324219 543.669982910156 543.659973144531 543.580017089844 543.630004882812 543.690002441406 543.719970703125 543.719970703125 543.669982910156 543.210021972656 542.349975585938 541.429992675781 540.940002441406 540.559997558594 540.119995117188 539.809997558594 539.590026855469 539.359985351562 539.140014648438 539.049987792969 538.950012207031 538.809997558594 538.609985351562 538.559997558594 538.429992675781 538.340026855469 538.309997558594 538.309997558594
+543.359985351562 543.330017089844 543.299987792969 543.299987792969 543.299987792969 543.239990234375 543.219970703125 543.260009765625 543.219970703125 543.159973144531 543.140014648438 543.190002441406 543.25 543.219970703125 543.25 543.260009765625 543.280029296875 543.280029296875 543.390014648438 543.440002441406 543.530029296875 543.599975585938 543.619995117188 543.640014648438 543.669982910156 543.609985351562 543.570007324219 543.609985351562 543.489990234375 543.489990234375 543.239990234375 542.47998046875 541.52001953125 540.530029296875 540.190002441406 539.789978027344 539.5 539.340026855469 539.169982910156 539 538.940002441406 538.739990234375 538.619995117188 538.440002441406 538.419982910156 538.359985351562 538.299987792969 538.309997558594 538.289978027344 538.309997558594
+543.27001953125 543.25 543.239990234375 543.22998046875 543.22998046875 543.239990234375 543.210021972656 543.140014648438 543.109985351562 543.080017089844 543.099975585938 543.169982910156 543.239990234375 543.260009765625 543.280029296875 543.280029296875 543.309997558594 543.340026855469 543.419982910156 543.510009765625 543.489990234375 543.590026855469 543.630004882812 543.640014648438 543.630004882812 543.619995117188 543.549987792969 543.380004882812 543.190002441406 542.97998046875 542.25 541.489990234375 540.599975585938 539.940002441406 539.700012207031 539.320007324219 539.140014648438 539.030029296875 538.890014648438 538.710021972656 538.539978027344 538.330017089844 538.340026855469 538.340026855469 538.289978027344 538.289978027344 538.299987792969 538.320007324219 538.289978027344 538.330017089844
+543.200012207031 543.159973144531 543.169982910156 543.200012207031 543.25 543.27001953125 543.27001953125 543.219970703125 543.169982910156 543.090026855469 543.080017089844 543.099975585938 543.150024414062 543.219970703125 543.150024414062 543.119995117188 543.299987792969 543.299987792969 543.469970703125 543.52001953125 543.47998046875 543.469970703125 543.47998046875 543.570007324219 543.570007324219 543.330017089844 543.179992675781 542.840026855469 541.830017089844 541.47998046875 541.260009765625 540.489990234375 539.72998046875 539.489990234375 539.200012207031 539 538.869995117188 538.77001953125 538.640014648438 538.469970703125 538.320007324219 538.260009765625 538.239990234375 538.239990234375 538.239990234375 538.260009765625 538.27001953125 538.289978027344 538.299987792969 538.369995117188
+543.25 543.25 543.200012207031 543.239990234375 543.260009765625 543.25 543.289978027344 543.239990234375 543.179992675781 543.109985351562 543.02001953125 543.030029296875 542.989990234375 542.960021972656 542.900024414062 543.030029296875 543.239990234375 543.340026855469 543.440002441406 543.530029296875 543.489990234375 543.369995117188 543.450012207031 543.330017089844 543.200012207031 542.940002441406 542.489990234375 541.760009765625 540.940002441406 539.880004882812 539.989990234375 539.530029296875 539.309997558594 539.090026855469 538.859985351562 538.739990234375 538.580017089844 538.489990234375 538.340026855469 538.280029296875 538.239990234375 538.239990234375 538.219970703125 538.260009765625 538.25 538.289978027344 538.299987792969 538.349975585938 538.369995117188 538.419982910156
+543.330017089844 543.25 543.25 543.260009765625 543.239990234375 543.239990234375 543.25 543.200012207031 543.080017089844 542.929992675781 542.900024414062 542.760009765625 542.650024414062 542.650024414062 542.619995117188 542.890014648438 543.140014648438 543.219970703125 543.299987792969 543.380004882812 543.419982910156 543.25 543.239990234375 543.140014648438 542.739990234375 542.159973144531 541.409973144531 540.669982910156 539.940002441406 539.330017089844 539.140014648438 538.97998046875 538.909973144531 538.809997558594 538.630004882812 538.460021972656 538.340026855469 538.299987792969 538.25 538.239990234375 538.219970703125 538.280029296875 538.27001953125 538.349975585938 538.369995117188 538.390014648438 538.359985351562 538.400024414062 538.460021972656 538.460021972656
+543.320007324219 543.22998046875 543.239990234375 543.219970703125 543.27001953125 543.260009765625 543.239990234375 543.099975585938 542.969970703125 542.840026855469 542.609985351562 542.429992675781 542.380004882812 542.330017089844 542.450012207031 542.590026855469 542.859985351562 542.849975585938 542.969970703125 543.080017089844 542.989990234375 542.369995117188 542.320007324219 542.010009765625 541.489990234375 541.150024414062 540.580017089844 539.830017089844 539.150024414062 539.02001953125 538.919982910156 538.760009765625 538.650024414062 538.460021972656 538.369995117188 538.289978027344 538.219970703125 538.239990234375 538.25 538.239990234375 538.289978027344 538.289978027344 538.340026855469 538.390014648438 538.419982910156 538.429992675781 538.429992675781 538.460021972656 538.47998046875 538.510009765625
+543.25 543.22998046875 543.22998046875 543.239990234375 543.239990234375 543.210021972656 543.119995117188 543.010009765625 542.840026855469 542.580017089844 542.390014648438 542.210021972656 542.150024414062 542.080017089844 542.119995117188 542.169982910156 542.299987792969 542.469970703125 542.549987792969 542.619995117188 541.890014648438 541.260009765625 541.02001953125 540.780029296875 540.25 539.960021972656 539.630004882812 539.010009765625 538.840026855469 538.799987792969 538.590026855469 538.450012207031 538.390014648438 538.340026855469 538.289978027344 538.219970703125 538.25 538.280029296875 538.260009765625 538.299987792969 538.340026855469 538.369995117188 538.429992675781 538.429992675781 538.460021972656 538.5 538.5 538.530029296875 538.570007324219 538.599975585938
+543.210021972656 543.210021972656 543.239990234375 543.179992675781 543.159973144531 543.109985351562 542.969970703125 542.859985351562 542.679992675781 542.440002441406 542.150024414062 541.900024414062 541.789978027344 541.780029296875 541.609985351562 541.580017089844 541.619995117188 541.570007324219 541.640014648438 541.299987792969 540.640014648438 540.130004882812 539.760009765625 539.489990234375 539.039978027344 538.859985351562 538.690002441406 538.609985351562 538.469970703125 538.330017089844 538.289978027344 538.289978027344 538.25 538.25 538.25 538.299987792969 538.289978027344 538.299987792969 538.27001953125 538.320007324219 538.390014648438 538.390014648438 538.400024414062 538.450012207031 538.5 538.530029296875 538.580017089844 538.599975585938 538.619995117188 538.659973144531
+543.22998046875 543.219970703125 543.210021972656 543.119995117188 543.049987792969 542.849975585938 542.72998046875 542.630004882812 542.419982910156 542.22998046875 541.849975585938 541.559997558594 541.510009765625 541.369995117188 541.130004882812 541.099975585938 540.919982910156 540.75 540.409973144531 539.960021972656 539.570007324219 539.299987792969 539.059997558594 538.809997558594 538.619995117188 538.450012207031 538.320007324219 538.27001953125 538.219970703125 538.239990234375 538.200012207031 538.210021972656 538.22998046875 538.239990234375 538.27001953125 538.27001953125 538.299987792969 538.320007324219 538.369995117188 538.419982910156 538.409973144531 538.429992675781 538.429992675781 538.489990234375 538.580017089844 538.590026855469 538.619995117188 538.650024414062 538.690002441406 538.72998046875
+543.210021972656 543.179992675781 543.130004882812 542.989990234375 542.760009765625 542.599975585938 542.47998046875 542.349975585938 542.159973144531 541.900024414062 541.570007324219 541.369995117188 541.27001953125 541.039978027344 540.679992675781 540.429992675781 540.150024414062 539.890014648438 539.659973144531 539.27001953125 538.919982910156 538.780029296875 538.580017089844 538.380004882812 538.239990234375 538.179992675781 538.099975585938 538.070007324219 538.099975585938 538.140014648438 538.200012207031 538.22998046875 538.25 538.289978027344 538.320007324219 538.330017089844 538.359985351562 538.429992675781 538.419982910156 538.460021972656 538.47998046875 538.510009765625 538.559997558594 538.570007324219 538.609985351562 538.690002441406 538.679992675781 538.719970703125 538.739990234375 538.809997558594
+543.099975585938 542.969970703125 542.780029296875 542.619995117188 542.440002441406 542.309997558594 542.200012207031 542.030029296875 541.809997558594 541.590026855469 541.340026855469 541.070007324219 541.080017089844 540.77001953125 540.369995117188 540.02001953125 539.719970703125 539.400024414062 539.169982910156 538.880004882812 538.650024414062 538.409973144531 538.260009765625 538.109985351562 538.030029296875 537.900024414062 537.919982910156 538.02001953125 538.109985351562 538.190002441406 538.200012207031 538.260009765625 538.320007324219 538.369995117188 538.380004882812 538.390014648438 538.400024414062 538.419982910156 538.489990234375 538.559997558594 538.549987792969 538.580017089844 538.630004882812 538.619995117188 538.669982910156 538.75 538.77001953125 538.710021972656 538.820007324219 538.869995117188
+542.859985351562 542.650024414062 542.429992675781 542.25 542.260009765625 541.97998046875 541.830017089844 541.609985351562 541.349975585938 541.059997558594 540.75 540.830017089844 540.72998046875 540.469970703125 540.070007324219 539.650024414062 539.419982910156 539.219970703125 538.900024414062 538.659973144531 538.289978027344 538.099975585938 537.960021972656 537.900024414062 537.840026855469 537.840026855469 537.950012207031 538.059997558594 538.169982910156 538.25 538.309997558594 538.390014648438 538.429992675781 538.469970703125 538.429992675781 538.460021972656 538.5 538.530029296875 538.52001953125 538.559997558594 538.52001953125 538.640014648438 538.640014648438 538.690002441406 538.739990234375 538.789978027344 538.820007324219 538.809997558594 538.840026855469 538.840026855469
+542.590026855469 542.359985351562 542.059997558594 541.929992675781 541.72998046875 541.559997558594 541.330017089844 541.109985351562 540.619995117188 540.369995117188 540.299987792969 540.419982910156 540.150024414062 539.799987792969 539.440002441406 539.22998046875 538.960021972656 538.619995117188 538.330017089844 538.049987792969 537.929992675781 537.809997558594 537.72998046875 537.739990234375 537.809997558594 537.900024414062 538.049987792969 538.190002441406 538.260009765625 538.349975585938 538.390014648438 538.409973144531 538.47998046875 538.469970703125 538.429992675781 538.419982910156 538.52001953125 538.570007324219 538.590026855469 538.510009765625 538.539978027344 538.690002441406 538.669982910156 538.690002441406 538.830017089844 538.830017089844 538.820007324219 538.830017089844 538.820007324219 538.859985351562
+542.289978027344 542.02001953125 541.780029296875 541.450012207031 541.159973144531 540.940002441406 540.530029296875 540.179992675781 540.010009765625 539.919982910156 539.940002441406 539.830017089844 539.47998046875 539.239990234375 538.859985351562 538.580017089844 538.200012207031 538.030029296875 537.849975585938 537.780029296875 537.659973144531 537.599975585938 537.690002441406 537.739990234375 537.890014648438 538.030029296875 538.169982910156 538.299987792969 538.359985351562 538.409973144531 538.489990234375 538.559997558594 538.52001953125 538.530029296875 538.429992675781 538.349975585938 538.450012207031 538.549987792969 538.590026855469 538.539978027344 538.640014648438 538.719970703125 538.690002441406 538.760009765625 538.820007324219 538.840026855469 538.880004882812 538.859985351562 538.859985351562 538.909973144531
+541.909973144531 541.630004882812 541.450012207031 540.940002441406 540.570007324219 540.260009765625 539.929992675781 539.780029296875 539.650024414062 539.690002441406 539.510009765625 539.150024414062 538.830017089844 538.549987792969 538.280029296875 538.059997558594 537.890014648438 537.760009765625 537.659973144531 537.599975585938 537.52001953125 537.549987792969 537.659973144531 537.830017089844 538.02001953125 538.190002441406 538.289978027344 538.390014648438 538.450012207031 538.530029296875 538.570007324219 538.590026855469 538.580017089844 538.5 538.5 538.429992675781 538.5 538.549987792969 538.52001953125 538.609985351562 538.690002441406 538.72998046875 538.789978027344 538.840026855469 538.809997558594 538.869995117188 538.919982910156 538.909973144531 538.919982910156 538.969970703125
+541.469970703125 541.440002441406 541.030029296875 540.530029296875 540.179992675781 539.890014648438 539.650024414062 539.489990234375 539.380004882812 539.200012207031 538.969970703125 538.570007324219 538.25 538.049987792969 538.010009765625 537.830017089844 537.739990234375 537.570007324219 537.469970703125 537.429992675781 537.450012207031 537.52001953125 537.710021972656 538 538.159973144531 538.289978027344 538.390014648438 538.460021972656 538.510009765625 538.559997558594 538.580017089844 538.580017089844 538.590026855469 538.539978027344 538.510009765625 538.559997558594 538.539978027344 538.580017089844 538.630004882812 538.75 538.780029296875 538.820007324219 538.849975585938 538.890014648438 538.900024414062 538.97998046875 538.969970703125 538.969970703125 538.989990234375 538.989990234375
+541.049987792969 540.880004882812 540.47998046875 540.109985351562 539.820007324219 539.570007324219 539.429992675781 539.219970703125 538.940002441406 538.700012207031 538.390014648438 538.130004882812 537.989990234375 537.890014648438 537.880004882812 537.690002441406 537.640014648438 537.510009765625 537.440002441406 537.390014648438 537.440002441406 537.630004882812 537.880004882812 538.090026855469 538.22998046875 538.359985351562 538.440002441406 538.489990234375 538.539978027344 538.580017089844 538.580017089844 538.590026855469 538.630004882812 538.650024414062 538.640014648438 538.659973144531 538.609985351562 538.640014648438 538.700012207031 538.780029296875 538.869995117188 538.830017089844 538.909973144531 538.940002441406 539.02001953125 539.039978027344 539.010009765625 539.010009765625 539 539
+540.640014648438 540.289978027344 539.989990234375 539.659973144531 539.460021972656 539.309997558594 539.179992675781 538.739990234375 538.489990234375 538.260009765625 538.059997558594 537.950012207031 537.77001953125 537.659973144531 537.669982910156 537.570007324219 537.530029296875 537.440002441406 537.369995117188 537.359985351562 537.52001953125 537.72998046875 538.039978027344 538.150024414062 538.359985351562 538.469970703125 538.570007324219 538.570007324219 538.539978027344 538.559997558594 538.599975585938 538.619995117188 538.650024414062 538.679992675781 538.679992675781 538.690002441406 538.710021972656 538.75 538.789978027344 538.830017089844 538.909973144531 538.940002441406 539.010009765625 539.030029296875 539.02001953125 539 539.02001953125 539 538.97998046875 538.929992675781
+540.359985351562 539.950012207031 539.510009765625 539.27001953125 539.130004882812 538.969970703125 538.650024414062 538.409973144531 538.210021972656 538.070007324219 537.940002441406 537.830017089844 537.700012207031 537.599975585938 537.539978027344 537.530029296875 537.419982910156 537.400024414062 537.369995117188 537.460021972656 537.630004882812 537.909973144531 538.119995117188 538.22998046875 538.380004882812 538.530029296875 538.619995117188 538.590026855469 538.599975585938 538.630004882812 538.659973144531 538.690002441406 538.679992675781 538.710021972656 538.679992675781 538.700012207031 538.760009765625 538.849975585938 538.880004882812 538.929992675781 538.919982910156 538.940002441406 539.030029296875 539.080017089844 539.039978027344 539.039978027344 539.049987792969 539 538.929992675781 538.909973144531
+539.909973144531 539.559997558594 539.219970703125 538.859985351562 538.710021972656 538.549987792969 538.390014648438 538.190002441406 538.150024414062 538.030029296875 537.859985351562 537.760009765625 537.669982910156 537.5 537.450012207031 537.450012207031 537.440002441406 537.419982910156 537.510009765625 537.690002441406 537.900024414062 538.02001953125 538.109985351562 538.260009765625 538.419982910156 538.450012207031 538.580017089844 538.630004882812 538.650024414062 538.690002441406 538.700012207031 538.72998046875 538.75 538.780029296875 538.780029296875 538.840026855469 538.890014648438 538.900024414062 538.940002441406 539 539.010009765625 539.010009765625 539.049987792969 539 539.039978027344 539.030029296875 539.030029296875 539 538.940002441406 538.919982910156
+539.489990234375 539.119995117188 538.840026855469 538.609985351562 538.450012207031 538.349975585938 538.289978027344 538.210021972656 538.080017089844 537.960021972656 537.809997558594 537.640014648438 537.489990234375 537.400024414062 537.419982910156 537.419982910156 537.549987792969 537.669982910156 537.830017089844 537.969970703125 538.059997558594 538.090026855469 538.190002441406 538.299987792969 538.400024414062 538.450012207031 538.619995117188 538.669982910156 538.690002441406 538.700012207031 538.72998046875 538.77001953125 538.799987792969 538.849975585938 538.880004882812 538.919982910156 538.929992675781 538.909973144531 538.929992675781 539.030029296875 539.049987792969 539.080017089844 539.030029296875 538.989990234375 539 539.010009765625 539.010009765625 538.969970703125 538.989990234375 539.010009765625
+539.02001953125 538.590026855469 538.440002441406 538.280029296875 538.25 538.27001953125 538.219970703125 538.200012207031 538.109985351562 537.97998046875 537.780029296875 537.590026855469 537.5 537.419982910156 537.409973144531 537.530029296875 537.77001953125 537.940002441406 538.080017089844 538.169982910156 538.239990234375 538.289978027344 538.330017089844 538.369995117188 538.460021972656 538.650024414062 538.700012207031 538.690002441406 538.72998046875 538.739990234375 538.789978027344 538.820007324219 538.859985351562 538.890014648438 538.880004882812 538.890014648438 538.919982910156 538.880004882812 539.039978027344 539.109985351562 539.049987792969 539.080017089844 539.049987792969 539.02001953125 539.039978027344 539.030029296875 539.039978027344 539.039978027344 539.059997558594 539.090026855469
+538.590026855469 538.330017089844 538.109985351562 538.030029296875 538.109985351562 538.22998046875 538.27001953125 538.200012207031 538.179992675781 538.039978027344 537.880004882812 537.690002441406 537.580017089844 537.510009765625 537.590026855469 537.77001953125 537.929992675781 538.109985351562 538.140014648438 538.349975585938 538.409973144531 538.450012207031 538.489990234375 538.5 538.619995117188 538.679992675781 538.710021972656 538.75 538.799987792969 538.830017089844 538.840026855469 538.909973144531 538.950012207031 538.940002441406 538.929992675781 538.960021972656 539 538.97998046875 539.02001953125 539.070007324219 539.119995117188 539.130004882812 539.090026855469 539.090026855469 539.109985351562 539.130004882812 539.070007324219 539.099975585938 539.119995117188 539.140014648438
+538.280029296875 538.030029296875 537.840026855469 537.809997558594 538.049987792969 538.260009765625 538.280029296875 538.239990234375 538.190002441406 538.099975585938 537.97998046875 537.880004882812 537.820007324219 537.830017089844 537.900024414062 538.010009765625 538.130004882812 538.27001953125 538.400024414062 538.450012207031 538.47998046875 538.539978027344 538.549987792969 538.710021972656 538.700012207031 538.710021972656 538.75 538.77001953125 538.820007324219 538.869995117188 538.909973144531 538.909973144531 538.909973144531 538.950012207031 539.010009765625 539.030029296875 539.030029296875 539.030029296875 539.039978027344 539.070007324219 539.150024414062 539.119995117188 539.119995117188 539.159973144531 539.200012207031 539.239990234375 539.25 539.239990234375 539.239990234375 539.219970703125
+538 537.789978027344 537.710021972656 537.900024414062 538.140014648438 538.299987792969 538.340026855469 538.320007324219 538.22998046875 538.179992675781 538.119995117188 538.099975585938 538.159973144531 538.159973144531 538.150024414062 538.210021972656 538.369995117188 538.47998046875 538.489990234375 538.47998046875 538.570007324219 538.599975585938 538.659973144531 538.72998046875 538.710021972656 538.75 538.799987792969 538.840026855469 538.859985351562 538.890014648438 538.909973144531 538.909973144531 538.950012207031 538.969970703125 539 539.010009765625 539.010009765625 539.039978027344 539.049987792969 539.090026855469 539.140014648438 539.169982910156 539.190002441406 539.25 539.289978027344 539.320007324219 539.400024414062 539.380004882812 539.340026855469 539.299987792969
+537.989990234375 537.849975585938 537.840026855469 537.989990234375 538.22998046875 538.369995117188 538.460021972656 538.429992675781 538.320007324219 538.27001953125 538.280029296875 538.280029296875 538.320007324219 538.340026855469 538.380004882812 538.469970703125 538.489990234375 538.549987792969 538.549987792969 538.539978027344 538.609985351562 538.669982910156 538.700012207031 538.700012207031 538.739990234375 538.780029296875 538.809997558594 538.900024414062 538.890014648438 538.960021972656 538.960021972656 538.960021972656 538.960021972656 538.940002441406 539 539.049987792969 539.039978027344 539.030029296875 539.119995117188 539.119995117188 539.140014648438 539.190002441406 539.280029296875 539.400024414062 539.359985351562 539.419982910156 539.419982910156 539.419982910156 539.390014648438 539.380004882812
+538 537.940002441406 537.900024414062 538.090026855469 538.289978027344 538.450012207031 538.530029296875 538.469970703125 538.409973144531 538.390014648438 538.419982910156 538.460021972656 538.5 538.559997558594 538.599975585938 538.590026855469 538.549987792969 538.630004882812 538.590026855469 538.609985351562 538.669982910156 538.710021972656 538.75 538.72998046875 538.809997558594 538.869995117188 538.900024414062 538.929992675781 538.960021972656 539 539 538.97998046875 538.950012207031 538.97998046875 539 539.039978027344 539.070007324219 539.099975585938 539.140014648438 539.159973144531 539.239990234375 539.330017089844 539.380004882812 539.440002441406 539.460021972656 539.419982910156 539.419982910156 539.400024414062 539.380004882812 539.429992675781
+538.090026855469 538.02001953125 538.02001953125 538.140014648438 538.340026855469 538.559997558594 538.580017089844 538.590026855469 538.510009765625 538.539978027344 538.52001953125 538.559997558594 538.590026855469 538.659973144531 538.609985351562 538.590026855469 538.599975585938 538.609985351562 538.599975585938 538.630004882812 538.679992675781 538.75 538.820007324219 538.859985351562 538.859985351562 538.909973144531 538.919982910156 538.97998046875 539.049987792969 539.02001953125 539.02001953125 539.049987792969 539.049987792969 539.049987792969 539.059997558594 539.150024414062 539.190002441406 539.150024414062 539.190002441406 539.280029296875 539.309997558594 539.400024414062 539.409973144531 539.409973144531 539.429992675781 539.390014648438 539.359985351562 539.359985351562 539.419982910156 539.47998046875
+538.119995117188 538.090026855469 538.049987792969 538.169982910156 538.340026855469 538.630004882812 538.690002441406 538.640014648438 538.650024414062 538.669982910156 538.640014648438 538.609985351562 538.669982910156 538.650024414062 538.619995117188 538.609985351562 538.580017089844 538.580017089844 538.599975585938 538.690002441406 538.710021972656 538.859985351562 538.859985351562 538.869995117188 538.940002441406 538.969970703125 538.960021972656 538.950012207031 539 539.049987792969 539.059997558594 539.039978027344 539.140014648438 539.179992675781 539.25 539.280029296875 539.27001953125 539.25 539.27001953125 539.320007324219 539.349975585938 539.400024414062 539.400024414062 539.409973144531 539.390014648438 539.289978027344 539.309997558594 539.380004882812 539.429992675781 539.549987792969
+538.140014648438 538.109985351562 538.150024414062 538.219970703125 538.409973144531 538.760009765625 538.77001953125 538.719970703125 538.760009765625 538.77001953125 538.719970703125 538.700012207031 538.690002441406 538.659973144531 538.659973144531 538.580017089844 538.559997558594 538.599975585938 538.659973144531 538.710021972656 538.799987792969 538.869995117188 538.840026855469 538.909973144531 539.010009765625 539.059997558594 539.059997558594 539.02001953125 539.049987792969 539.070007324219 539.02001953125 539.059997558594 539.190002441406 539.260009765625 539.309997558594 539.320007324219 539.280029296875 539.299987792969 539.330017089844 539.359985351562 539.380004882812 539.409973144531 539.400024414062 539.390014648438 539.320007324219 539.330017089844 539.349975585938 539.359985351562 539.460021972656 539.489990234375
+538.159973144531 538.159973144531 538.200012207031 538.260009765625 538.489990234375 538.780029296875 538.900024414062 538.809997558594 538.799987792969 538.739990234375 538.690002441406 538.679992675781 538.700012207031 538.669982910156 538.619995117188 538.599975585938 538.609985351562 538.669982910156 538.72998046875 538.799987792969 538.880004882812 538.849975585938 538.909973144531 538.97998046875 539.070007324219 539.080017089844 539.070007324219 539.109985351562 539.150024414062 539.159973144531 539.179992675781 539.190002441406 539.210021972656 539.239990234375 539.320007324219 539.309997558594 539.330017089844 539.359985351562 539.380004882812 539.340026855469 539.380004882812 539.380004882812 539.369995117188 539.349975585938 539.309997558594 539.369995117188 539.400024414062 539.419982910156 539.429992675781 539.460021972656
+538.239990234375 538.190002441406 538.190002441406 538.25 538.5 538.72998046875 538.869995117188 538.820007324219 538.849975585938 538.700012207031 538.690002441406 538.630004882812 538.669982910156 538.659973144531 538.619995117188 538.630004882812 538.679992675781 538.719970703125 538.780029296875 538.859985351562 538.880004882812 538.900024414062 538.97998046875 539.030029296875 539.090026855469 539.150024414062 539.179992675781 539.169982910156 539.219970703125 539.25 539.239990234375 539.27001953125 539.27001953125 539.25 539.280029296875 539.340026855469 539.369995117188 539.390014648438 539.409973144531 539.409973144531 539.380004882812 539.390014648438 539.369995117188 539.390014648438 539.409973144531 539.429992675781 539.460021972656 539.469970703125 539.510009765625 539.559997558594
diff --git a/docs/source/tutorials/river_flow_dynamics/river_flow_dynamics_tutorial.ipynb b/docs/source/tutorials/river_flow_dynamics/river_flow_dynamics_tutorial.ipynb
new file mode 100644
index 0000000000..950538d4b2
--- /dev/null
+++ b/docs/source/tutorials/river_flow_dynamics/river_flow_dynamics_tutorial.ipynb
@@ -0,0 +1,656 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# 2D Surface Water Flow component\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Overview\n",
+ "\n",
+ "This notebook demonstrate the usage of the `river flow dynamics` Landlab component. The component runs a semi-implicit, semi-Lagrangian finite-volume approximation to the depth-averaged 2D shallow-water equations of Casulli and Cheng (1992) and related work.\n",
+ "\n",
+ "### Theory\n",
+ "\n",
+ "The depth-averaged 2D shallow-water equations are the simplification of the Navier-Stokes equations, which correspond to the balance of momentum and mass in the fluid. It is possible to simplify these equations by assuming a well-mixed water column and a small water depth to width ratio, where a vertical integration results in depth-averaged equations. These require boundary conditions at the top and bottom of the water column, which are provided by the wind stress and the Manning-Chezy formula, respectively:\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial U}{\\partial t}\n",
+ "+ U\\frac{\\partial U}{\\partial x} + V\\frac{\\partial U}{\\partial y}\n",
+ "= \n",
+ "- g\\frac{\\partial \\eta}{\\partial x}\n",
+ "+ \\epsilon\\left(\\frac{\\partial^2 U}{\\partial x^2} + \\frac{\\partial^2 U}{\\partial y^2}\\right)\n",
+ "+ \\frac{\\gamma_T(U_a - U)}{H} - g\\frac{\\sqrt{U^2 + V^2}}{Cz^2}U + \\mathbf{f}V\n",
+ "$$\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial V}{\\partial t}\n",
+ "+ U\\frac{\\partial V}{\\partial x} + V\\frac{\\partial V}{\\partial y}\n",
+ "= \n",
+ "- g\\frac{\\partial \\eta}{\\partial y}\n",
+ "+ \\epsilon\\left(\\frac{\\partial^2 V}{\\partial x^2} + \\frac{\\partial^2 V}{\\partial y^2}\\right)\n",
+ "+ \\frac{\\gamma_T(V_a - V)}{H} - g\\frac{\\sqrt{U^2 + V^2}}{Cz^2}V + \\mathbf{f}U\n",
+ "$$\n",
+ "\n",
+ "$$\n",
+ "\\frac{\\partial \\eta}{\\partial t}\n",
+ "+ \\frac{\\partial (HU)}{\\partial x} + \\frac{\\partial (HV)}{\\partial y}\n",
+ "= 0\n",
+ "$$\n",
+ "\n",
+ "where $U$ is the water velocity in the $x$-direction, $V$ is the water velocity in the $y$-direction, $H$ is the water depth, $\\eta$ is the water surface elevation, $Cz$ is the Chezy friction coefficient, and $t$ is time. For the constants $g$ is the gravity acceleration, $\\epsilon$ is the horizontal eddy viscosity, $\\mathbf{f}$ is the Coriolis parameter, $\\gamma_T$ is the wind stress coefficient, and $U_a$ and $V_a$ are the prescribed wind velocities.\n",
+ "\n",
+ "### Numerical representation\n",
+ "\n",
+ "A semi-implicit, semi-Lagrangian, finite volume numerical approximation represents the depth averaged, 2D shallow-water equations described before. The water surface elevation, $\\eta$, is defined at the center of each computational volume (nodes). Water depth, $H$, and velocity components, $U$ and $V$, are defined at the midpoint of volume faces (links). The finite volume structure provides a control volume representation that is inherently mass conservative.\n",
+ "\n",
+ "The combination of a semi-implciit water surface elevation solution and a semi-Lagrangian representation of advection provides the advantages of a stable solution and of time steps that exceed the CFL criterion. In the semi-implicit process, $\\eta$ in the momentum equations, and the velocity divergence in the continuity equation, are treated implicitly. The advective terms in the momentum equations, are discretized explicitly. See the cited literature for more details.\n",
+ "\n",
+ "### The component\n",
+ "\n",
+ "Import the needed libraries:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np\n",
+ "from IPython.display import clear_output\n",
+ "from tqdm import trange\n",
+ "\n",
+ "from landlab import RasterModelGrid\n",
+ "from landlab.components import RiverFlowDynamics\n",
+ "from landlab.io import esri_ascii"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Information about the component\n",
+ "\n",
+ "Using the class name as argument for the `help` function returns descriptions of the various methods and parameters."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "help(RiverFlowDynamics)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Examples\n",
+ "\n",
+ "-- --\n",
+ "\n",
+ "### Example 1: Flow in a rectangular channel 6.0 m long\n",
+ "\n",
+ "This first basic example illustrates water flowing through a rectangular channel 1.0 $m$ wide and 6.0 $m$ long. Our channel is made in concrete, so we choose a Manning's roughness coefficient equal to 0.012 $s/m^\\frac{1}{3}$, and it has a slope of 0.01 $m/m$.\n",
+ "\n",
+ "We specify some basic parameters such as the grid resolution, time step duration, number of time steps, and the domain dimensions by specifying the number of columns and rows. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Basic parameters\n",
+ "mannings_n = 0.012 # Manning's roughness coefficient, [s/m^(1/3)]\n",
+ "channel_slope = 0.01 # Channel slope [m/m]\n",
+ "\n",
+ "# Simulation parameters\n",
+ "n_timesteps = 1000 # Number of timesteps\n",
+ "dt = 0.1 # Timestep duration, [s]\n",
+ "nrows = 20 # Number of node rows\n",
+ "ncols = 60 # Number of node cols\n",
+ "dx = 0.1 # Node spacing in the x-direction, [m]\n",
+ "dy = 0.1 # Node spacing in the y-direction, [m]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Create the grid:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Create and set up the grid\n",
+ "grid = RasterModelGrid((nrows, ncols), xy_spacing=(dx, dy))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Create the elevation field and define the topography to represent our rectangular channel:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# The grid represents a basic rectangular channel with slope equal to 0.01 m/m\n",
+ "te = grid.add_field(\n",
+ " \"topographic__elevation\", 1.0 - channel_slope * grid.x_of_node, at=\"node\"\n",
+ ")\n",
+ "te[grid.y_of_node > 1.5] = 2.5\n",
+ "te[grid.y_of_node < 0.5] = 2.5"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We show a top view of the domain:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Showing the topography\n",
+ "grid.imshow(\"topographic__elevation\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The channel is empty at the beginning of the simulation, so we create the fields for the water surface elevation, depth and velocity:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# We establish the initial conditions, which represent an empty channel\n",
+ "h = grid.add_zeros(\"surface_water__depth\", at=\"node\")\n",
+ "\n",
+ "# Water velocity is zero in everywhere since there is no water yet\n",
+ "vel = grid.add_zeros(\"surface_water__velocity\", at=\"link\")\n",
+ "\n",
+ "# Calculating the initial water surface elevation from water depth and topographic elevation\n",
+ "wse = grid.add_field(\"surface_water__elevation\", te, at=\"node\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Then, we specify the nodes at which water is entering into the domain, and also the associated links. These are going to be the entry boundary conditions for water depth and velocity. In this case, water flows from left to right at 0.5 $m$ depth, with a velocity of 0.45 $m/s$:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# We set fixed boundary conditions, specifying the nodes and links in which the water is flowing into the grid\n",
+ "fixed_entry_nodes = np.array([300, 360, 420, 480, 540, 600, 660, 720, 780, 840, 900])\n",
+ "fixed_entry_links = grid.links_at_node[fixed_entry_nodes][:, 0]\n",
+ "\n",
+ "# We set the fixed values in the entry nodes/links\n",
+ "entry_nodes_h_values = np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5])\n",
+ "entry_links_vel_values = np.array(\n",
+ " [0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45]\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "And now we show the boundary condition in the cross-section:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plt.plot(\n",
+ " grid.y_of_node[fixed_entry_nodes], entry_nodes_h_values + te[fixed_entry_nodes]\n",
+ ")\n",
+ "plt.plot(grid.y_of_node[grid.nodes_at_left_edge], te[grid.nodes_at_left_edge])\n",
+ "plt.title(\"Cross-section\")\n",
+ "plt.xlabel(\"Distance [m]\")\n",
+ "plt.ylabel(\"Elevation [m]\")\n",
+ "plt.axis([0.25, 1.75, 0.75, 2.75])\n",
+ "plt.grid(True)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We construct our component by passing the arguments we defined previously:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Finally, we run the model and let the water fill our channel\n",
+ "rfd = RiverFlowDynamics(\n",
+ " grid,\n",
+ " dt=dt,\n",
+ " mannings_n=mannings_n,\n",
+ " fixed_entry_nodes=fixed_entry_nodes,\n",
+ " fixed_entry_links=fixed_entry_links,\n",
+ " entry_nodes_h_values=entry_nodes_h_values,\n",
+ " entry_links_vel_values=entry_links_vel_values,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "And finally, we run the simulation for 100 timesteps (10 seconds).\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Set the animation frequency to n_timesteps if you\n",
+ "# don't want to plot the water depth\n",
+ "# display_animation_freq = n_timesteps\n",
+ "display_animation_freq = 5\n",
+ "\n",
+ "grid.imshow(\"surface_water__depth\", output=True)\n",
+ "for timestep in trange(n_timesteps):\n",
+ " rfd.run_one_step()\n",
+ "\n",
+ " if timestep % display_animation_freq == 0:\n",
+ " clear_output(wait=True) # This will clear the previous image\n",
+ " grid.imshow(\"surface_water__depth\", output=True)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Exploring the water depth results at the latest time:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "grid.imshow(\"surface_water__depth\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "And the water surface elevation:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "grid.imshow(\"surface_water__elevation\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "-- --\n",
+ "## Example 2: Surface water flowing over a DEM\n",
+ "\n",
+ "On this case, we will import a digital elevation model (DEM) for a side-channel of the Kootenai River, Idaho, US."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Getting the grid and some parameters\n",
+ "asc_file = \"DEM-kootenai_37x50_1x1.asc\"\n",
+ "with open(asc_file) as fp:\n",
+ " grid = esri_ascii.load(fp, name=\"topographic__elevation\")\n",
+ "te = grid.at_node[\"topographic__elevation\"]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Again, we specify some basic parameters such as the time step number and duration. For simplicity, we will keep our previous Manning's coefficient. Notice that we already loaded all the required libraries."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Basic parameters\n",
+ "mannings_n = 0.012 # Manning's roughness coefficient, [s/m^(1/3)]\n",
+ "\n",
+ "# Simulation parameters\n",
+ "n_timesteps = 75 # Number of timesteps\n",
+ "dt = 1.0 # Timestep duration, [s]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's see our new topography:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Showing the topography\n",
+ "grid.imshow(\"topographic__elevation\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Our side-channel is empty at the beggining of the simulation, so we create the proper fields:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# We establish the initial conditions, which represent an empty channel\n",
+ "h = grid.add_zeros(\"surface_water__depth\", at=\"node\")\n",
+ "\n",
+ "# Water velocity is zero in everywhere since there is no water yet\n",
+ "vel = grid.add_zeros(\"surface_water__velocity\", at=\"link\")\n",
+ "\n",
+ "# Calculating the initial water surface elevation from water depth and topographic elevation\n",
+ "wse = grid.add_field(\"surface_water__elevation\", te, at=\"node\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Then, we specify the nodes at which water is entering into the domain, and also the associated links. These are going to be our entry boundary conditions for water depth and velocity. On this case, water flows from right to left:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# We set fixed boundary conditions, specifying the nodes and links in which the water is flowing into the grid\n",
+ "fixed_entry_nodes = grid.nodes_at_right_edge\n",
+ "fixed_entry_links = grid.links_at_node[fixed_entry_nodes][:, 2]\n",
+ "\n",
+ "# We set the fixed values in the entry nodes/links\n",
+ "entry_nodes_h_values = np.array(\n",
+ " [\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.04998779,\n",
+ " 0.05999756,\n",
+ " 0.03997803,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.05999756,\n",
+ " 0.10998535,\n",
+ " 0.12994385,\n",
+ " 0.09997559,\n",
+ " 0.15997314,\n",
+ " 0.23999023,\n",
+ " 0.30999756,\n",
+ " 0.36999512,\n",
+ " 0.45996094,\n",
+ " 0.50994873,\n",
+ " 0.54998779,\n",
+ " 0.59997559,\n",
+ " 0.63995361,\n",
+ " 0.65997314,\n",
+ " 0.65997314,\n",
+ " 0.60998535,\n",
+ " 0.5,\n",
+ " 0.13995361,\n",
+ " 0.0,\n",
+ " ]\n",
+ ")\n",
+ "entry_links_vel_values = np.array(\n",
+ " [\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " 0.0,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " -2.58638018,\n",
+ " 0.0,\n",
+ " ]\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now we can plot our entry boundary condition in the cross-section:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plt.plot(\n",
+ " grid.y_of_node[fixed_entry_nodes], entry_nodes_h_values + te[fixed_entry_nodes]\n",
+ ")\n",
+ "plt.plot(grid.y_of_node[grid.nodes_at_right_edge], te[grid.nodes_at_right_edge])\n",
+ "plt.title(\"Entry cross-section\")\n",
+ "plt.xlabel(\"Distance [m]\")\n",
+ "plt.ylabel(\"Elevation [m]\")\n",
+ "plt.grid(True)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Then we create the component by passing the arguments defined previously:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Finally, we run the model and let the water fill our channel\n",
+ "rfd = RiverFlowDynamics(\n",
+ " grid,\n",
+ " dt=dt,\n",
+ " mannings_n=mannings_n,\n",
+ " fixed_entry_nodes=fixed_entry_nodes,\n",
+ " fixed_entry_links=fixed_entry_links,\n",
+ " entry_nodes_h_values=entry_nodes_h_values,\n",
+ " entry_links_vel_values=entry_links_vel_values,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "And we run 75 time steps of 1 $s$ duration (around 1 minute of computing time):"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Set the animation frequency to n_timesteps if you\n",
+ "# don't want to plot the water depth\n",
+ "# display_animation_freq = n_timesteps\n",
+ "display_animation_freq = 5\n",
+ "\n",
+ "grid.imshow(\"surface_water__depth\", output=True)\n",
+ "for timestep in trange(n_timesteps):\n",
+ " rfd.run_one_step()\n",
+ "\n",
+ " if timestep % display_animation_freq == 0:\n",
+ " clear_output(wait=True) # This will clear the previous image\n",
+ " grid.imshow(\"surface_water__depth\", output=True)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Finally, we can explore the results by plotting the resulting water depth:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "grid.imshow(\"surface_water__depth\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "-- --\n",
+ "### And that's it! \n",
+ "\n",
+ "Nice work completing this tutorial. You know now how to use the `RiverFlowDynamics` Landlab component to run your own simulations :)\n",
+ "\n",
+ "-- --\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Click here for more Landlab tutorials"
+ ]
+ }
+ ],
+ "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.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/source/tutorials/river_flow_dynamics/river_flow_dynamics_tutorial2.ipynb b/docs/source/tutorials/river_flow_dynamics/river_flow_dynamics_tutorial2.ipynb
new file mode 100644
index 0000000000..1ccc359061
--- /dev/null
+++ b/docs/source/tutorials/river_flow_dynamics/river_flow_dynamics_tutorial2.ipynb
@@ -0,0 +1,425 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# 2D Surface Water Flow component\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# River Flow Dynamics Simulation with Landlab"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "For more Landlab tutorials, click here: https://landlab.csdms.io/tutorials/\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Overview\n",
+ "\n",
+ "This notebook demonstrate the usage of the `river flow dynamics` Landlab component. The component runs a semi-implicit, semi-Lagrangian finite-volume approximation to the depth-averaged 2D shallow-water equations of Casulli and Cheng (1992) and related work.\n",
+ "\n",
+ "This notebook demonstrates how to simulate river flow dynamics using the Landlab library, implementing the semi-implicit, semi-Lagrangian finite-volume approximation of the depth-averaged shallow water equations (Casulli and Cheng, 1992).\n",
+ "\n",
+ "\n",
+ "## Setup and Imports\n",
+ "\n",
+ "Import the needed libraries:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np\n",
+ "\n",
+ "from landlab import RasterModelGrid\n",
+ "from landlab.components import RiverFlowDynamics # Note: Using updated CamelCase naming\n",
+ "from landlab.plot.imshow import imshow_grid"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Create Grid and Set Initial Conditions\n",
+ "\n",
+ "First, let's create a rectangular grid for our flow dynamics calculations:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "nRows = 20\n",
+ "nCols = 60\n",
+ "cellSize = 0.1"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Creating the grid"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "grid = RasterModelGrid((nRows, nCols), xy_spacing=(cellSize, cellSize))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Setting up the initial topographic elevation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "te = grid.add_zeros(\"topographic__elevation\", at=\"node\")\n",
+ "te += 0.059 - 0.01 * grid.x_of_node\n",
+ "te[grid.y_of_node > 1.5] = 1.0\n",
+ "te[grid.y_of_node < 0.5] = 1.0"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Visualizing the initial topography"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plt.figure(figsize=(12, 4))\n",
+ "imshow_grid(grid, \"topographic__elevation\")\n",
+ "plt.title(\"Initial Topographic Elevation\")\n",
+ "plt.colorbar(label=\"Elevation (m)\")\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Visualizing the middle bed profile"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "middleBedProfile = np.reshape(te, (nRows, nCols))[10, :]\n",
+ "plt.figure(figsize=(12, 3))\n",
+ "plt.plot(middleBedProfile)\n",
+ "plt.title(\"Middle Longitudinal Section of Bed Profile\")\n",
+ "plt.xlabel(\"Distance (cells)\")\n",
+ "plt.ylabel(\"Elevation (m)\")\n",
+ "plt.grid(True)\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Initializing Required Fields\n",
+ "\n",
+ "Create water depth field (initially empty channel)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "h = grid.add_zeros(\"surface_water__depth\", at=\"node\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Create velocity field (initially zero)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "vel = grid.add_zeros(\"surface_water__velocity\", at=\"link\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Calculate initial water surface elevation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "wse = grid.add_zeros(\"surface_water__elevation\", at=\"node\")\n",
+ "wse += h + te"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Setting up the boundary conditions"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fixed_entry_nodes = np.arange(300, 910, 60)\n",
+ "fixed_entry_links = grid.links_at_node[fixed_entry_nodes][:, 0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Set fixed values for entry nodes/links"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "entry_nodes_h_values = np.full(11, 0.5) # 0.5m water depth\n",
+ "entry_links_vel_values = np.full(11, 0.45) # 0.45 m/s velocity"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Run Simulation\n",
+ "\n",
+ "Initialize the RiverFlowDynamics component"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "rfd = RiverFlowDynamics(\n",
+ " grid,\n",
+ " dt=0.1,\n",
+ " mannings_n=0.012,\n",
+ " fixed_entry_nodes=fixed_entry_nodes,\n",
+ " fixed_entry_links=fixed_entry_links,\n",
+ " entry_nodes_h_values=entry_nodes_h_values,\n",
+ " entry_links_vel_values=entry_links_vel_values,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Run the simulation for 100 timesteps (10 seconds)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "n_timesteps = 100\n",
+ "for timestep in range(n_timesteps):\n",
+ " rfd.run_one_step()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Analyze Results\n",
+ "\n",
+ "Get flow depth along center of channel"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "flow_depth = np.reshape(grid[\"node\"][\"surface_water__depth\"], (nRows, nCols))[10, :]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Plot flow depth"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "plt.figure(figsize=(12, 4))\n",
+ "plt.plot(flow_depth, label=\"Simulated\")\n",
+ "plt.title(\"Flow Depth Along Channel Centerline\")\n",
+ "plt.xlabel(\"Distance (cells)\")\n",
+ "plt.ylabel(\"Depth (m)\")\n",
+ "plt.grid(True)\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Get and plot velocity along center of channel"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "linksAtCenter = grid.links_at_node[np.array(np.arange(600, 660))][:-1, 0]\n",
+ "flow_velocity = grid[\"link\"][\"surface_water__velocity\"][linksAtCenter]\n",
+ "\n",
+ "plt.figure(figsize=(12, 4))\n",
+ "plt.plot(flow_velocity, label=\"Simulated\")\n",
+ "plt.title(\"Flow Velocity Along Channel Centerline\")\n",
+ "plt.xlabel(\"Distance (cells)\")\n",
+ "plt.ylabel(\"Velocity (m/s)\")\n",
+ "plt.grid(True)\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Visualization of Final State\n",
+ "\n",
+ "Create a figure with two subplots and then let's plot final water depth"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))\n",
+ "\n",
+ "# Plot final water depth\n",
+ "plt.subplot(2, 1, 1)\n",
+ "im1 = imshow_grid(grid, \"surface_water__depth\")\n",
+ "plt.title(\"Final Water Depth\")\n",
+ "plt.colorbar(label=\"Depth (m)\")\n",
+ "\n",
+ "# Plot final water surface elevation\n",
+ "plt.subplot(2, 1, 2)\n",
+ "im2 = imshow_grid(grid, \"surface_water__elevation\")\n",
+ "plt.title(\"Final Water Surface Elevation\")\n",
+ "plt.colorbar(label=\"Elevation (m)\")\n",
+ "\n",
+ "plt.tight_layout()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "-- --\n",
+ "### And that's it! \n",
+ "\n",
+ "Nice work completing this tutorial. You know now how to use the `RiverFlowDynamics` Landlab component to run your own simulations :)\n",
+ "\n",
+ "-- --\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Click here for more Landlab tutorials"
+ ]
+ }
+ ],
+ "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.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/source/tutorials/terrain_analysis/hack_calculator/hack_calculator.ipynb b/docs/source/tutorials/terrain_analysis/hack_calculator/hack_calculator.ipynb
index 11ede691c9..9d44fef567 100644
--- a/docs/source/tutorials/terrain_analysis/hack_calculator/hack_calculator.ipynb
+++ b/docs/source/tutorials/terrain_analysis/hack_calculator/hack_calculator.ipynb
@@ -205,7 +205,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "The `ChannelProfiler` data is an ordered dict, in this case containing data for one watershed: the one that drains to node 6576 (for details see the [reference documentation](https://landlab.readthedocs.io/en/latest/reference/components/channel_profiler.html#landlab.components.profiler.channel_profiler.ChannelProfiler) and tutorial resources for `ChannelProfiler`).\n",
+ "The `ChannelProfiler` data is an ordered dict, in this case containing data for one watershed: the one that drains to node 6576 (for details see the [reference documentation](https://landlab.csdms.io/generated/api/landlab.components.profiler.channel_profiler.html#landlab.components.profiler.channel_profiler.ChannelProfiler) and tutorial resources for `ChannelProfiler`).\n",
"\n",
"For this example, we might wish to visualize the main channel for which the Hack coefficient and exponent were calculated. We can do that with the profiler's `plot_profiles_in_map_view` method:"
]
diff --git a/docs/source/tutorials/terrain_analysis/steepness_finder/steepness_finder.ipynb b/docs/source/tutorials/terrain_analysis/steepness_finder/steepness_finder.ipynb
index 00fd6f9e27..4aadc4d91c 100644
--- a/docs/source/tutorials/terrain_analysis/steepness_finder/steepness_finder.ipynb
+++ b/docs/source/tutorials/terrain_analysis/steepness_finder/steepness_finder.ipynb
@@ -55,7 +55,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "The [Reference Documentation](https://landlab.readthedocs.io/en/latest/reference/components/index.html#landlab.components.SteepnessFinder) provides information about the SteepnessFinder class, describes its methods and attributes, and provides a link to the source code.\n",
+ "The [Reference Documentation](https://landlab.csdms.io/generated/api/landlab.components.steepness_index.channel_steepness.html#landlab.components.steepness_index.channel_steepness.SteepnessFinder) provides information about the SteepnessFinder class, describes its methods and attributes, and provides a link to the source code.\n",
"\n",
"The SteepnessFinder class docstring describes the component and provides some simple examples:"
]
diff --git a/docs/source/user_guide/grid_methods/01_nodes_links_patches.md b/docs/source/user_guide/grid_methods/01_nodes_links_patches.md
index 76d9ebed53..ee32178197 100644
--- a/docs/source/user_guide/grid_methods/01_nodes_links_patches.md
+++ b/docs/source/user_guide/grid_methods/01_nodes_links_patches.md
@@ -21,7 +21,7 @@
:nosignatures:
{% for func in grids[grid][cat] %}
- ~{{func}}
+ ~{{func | replace("landlab.", "")}}
{% endfor %}
{% endfor %}
{% endfor %}
diff --git a/docs/source/user_guide/grid_methods/02_corners_faces_cells.md b/docs/source/user_guide/grid_methods/02_corners_faces_cells.md
index c01e8d0a31..189f793122 100644
--- a/docs/source/user_guide/grid_methods/02_corners_faces_cells.md
+++ b/docs/source/user_guide/grid_methods/02_corners_faces_cells.md
@@ -21,7 +21,7 @@
:nosignatures:
{% for func in grids[grid][cat] %}
- ~{{func}}
+ ~{{func | replace("landlab.", "")}}
{% endfor %}
{% endfor %}
{% endfor %}
diff --git a/docs/source/user_guide/grid_methods/03_boundary_conditions.md b/docs/source/user_guide/grid_methods/03_boundary_conditions.md
index 8028286222..5a4a4da4dc 100644
--- a/docs/source/user_guide/grid_methods/03_boundary_conditions.md
+++ b/docs/source/user_guide/grid_methods/03_boundary_conditions.md
@@ -23,7 +23,7 @@ update the conditions defined at other grid elements.
:nosignatures:
{% for func in grids[grid]['boundary-condition'] %}
- ~{{func}}
+ ~{{func | replace("landlab.", "")}}
{% endfor %}
{% endfor %}
```
diff --git a/docs/source/user_guide/grid_methods/04_element_subsets.md b/docs/source/user_guide/grid_methods/04_element_subsets.md
index 195e7b6eb0..30d924a4a8 100644
--- a/docs/source/user_guide/grid_methods/04_element_subsets.md
+++ b/docs/source/user_guide/grid_methods/04_element_subsets.md
@@ -20,7 +20,7 @@ to a point; nodes at edges.
:nosignatures:
{% for func in grids[grid]['subset'] %}
- ~{{func}}
+ ~{{func | replace("landlab.", "")}}
{% endfor %}
{% endfor %}
```
diff --git a/docs/source/user_guide/grid_methods/05_element_mapping.md b/docs/source/user_guide/grid_methods/05_element_mapping.md
index a44acef866..b9c71ae557 100644
--- a/docs/source/user_guide/grid_methods/05_element_mapping.md
+++ b/docs/source/user_guide/grid_methods/05_element_mapping.md
@@ -23,7 +23,7 @@ nodes.
:nosignatures:
{% for func in grids[grid]['map'] %}
- ~{{func}}
+ ~{{func | replace("landlab.", "")}}
{% endfor %}
{% endfor %}
```
diff --git a/docs/source/user_guide/grid_methods/06_gradients.md b/docs/source/user_guide/grid_methods/06_gradients.md
index 98a4c78774..15cd420898 100644
--- a/docs/source/user_guide/grid_methods/06_gradients.md
+++ b/docs/source/user_guide/grid_methods/06_gradients.md
@@ -22,7 +22,7 @@ methods tend to start with `calc_`.
:nosignatures:
{% for func in grids[grid]['gradient'] %}
- ~{{func}}
+ ~{{func | replace("landlab.", "")}}
{% endfor %}
{% endfor %}
```
diff --git a/docs/source/user_guide/grid_methods/07_surface_analysis.md b/docs/source/user_guide/grid_methods/07_surface_analysis.md
index 0985dc10a5..9e443f49db 100644
--- a/docs/source/user_guide/grid_methods/07_surface_analysis.md
+++ b/docs/source/user_guide/grid_methods/07_surface_analysis.md
@@ -20,7 +20,7 @@ find in GIS software.
:nosignatures:
{% for func in grids[grid]['surface'] %}
- ~{{func}}
+ ~{{func | replace("landlab.", "")}}
{% endfor %}
{% endfor %}
```
diff --git a/docs/source/user_guide/grid_methods/99_uncategorized.md b/docs/source/user_guide/grid_methods/99_uncategorized.md
index 1cb1190b86..02bedbe752 100644
--- a/docs/source/user_guide/grid_methods/99_uncategorized.md
+++ b/docs/source/user_guide/grid_methods/99_uncategorized.md
@@ -27,7 +27,7 @@ a future *Landlab* release and so their use is discouraged.
:nosignatures:
{% for func in grids[grid][cat] %}
- ~{{func}}
+ ~{{func | replace("landlab.", "")}}
{% endfor %}
{% endfor %}
{% endfor %}
diff --git a/docs/source/user_guide/reference/components.md b/docs/source/user_guide/reference/components.md
index 683ee1d52c..17fedd3a06 100644
--- a/docs/source/user_guide/reference/components.md
+++ b/docs/source/user_guide/reference/components.md
@@ -7,172 +7,103 @@ following categories of components:
## Hillslope geomorphology
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.diffusion
-/generated/api/landlab.components.nonlinear_diffusion
-/generated/api/landlab.components.depth_dependent_diffusion
-/generated/api/landlab.components.transport_length_diffusion
-/generated/api/landlab.components.taylor_nonlinear_hillslope_flux
-/generated/api/landlab.components.depth_dependent_taylor_soil_creep
-/generated/api/landlab.components.threshold_eroder
-/generated/api/landlab.components.concentration_tracker
-```
+* {mod}`landlab.components.diffusion`
+* {mod}`landlab.components.nonlinear_diffusion`
+* {mod}`landlab.components.transport_length_diffusion`
+* {mod}`landlab.components.taylor_nonlinear_hillslope_flux`
+* {mod}`landlab.components.depth_dependent_taylor_soil_creep`
+* {mod}`landlab.components.threshold_eroder`
+* {mod}`landlab.components.concentration_tracker`
## Fluvial geomorphology
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.stream_power
-/generated/api/landlab.components.detachment_ltd_erosion
-/generated/api/landlab.components.erosion_deposition
-/generated/api/landlab.components.space
-/generated/api/landlab.components.network_sediment_transporter
-/generated/api/landlab.components.gravel_river_transporter
-/generated/api/landlab.components.area_slope_transporter
-/generated/api/landlab.components.gravel_bedrock_eroder
-```
+* {mod}`landlab.components.stream_power`
+* {mod}`landlab.components.detachment_ltd_erosion`
+* {mod}`landlab.components.erosion_deposition`
+* {mod}`landlab.components.space`
+* {mod}`landlab.components.network_sediment_transporter`
+* {mod}`landlab.components.gravel_river_transporter`
+* {mod}`landlab.components.area_slope_transporter`
+* {mod}`landlab.components.gravel_bedrock_eroder`
## Flow routing
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.flow_director
-/generated/api/landlab.components.flow_accum
-/generated/api/landlab.components.depression_finder
-/generated/api/landlab.components.lake_fill
-/generated/api/landlab.components.priority_flood_flow_router
-/generated/api/landlab.components.sink_fill
-```
+* {mod}`landlab.components.flow_director`
+* {mod}`landlab.components.flow_accum`
+* {mod}`landlab.components.depression_finder`
+* {mod}`landlab.components.lake_fill`
+* {mod}`landlab.components.priority_flood_flow_router`
+* {mod}`landlab.components.sink_fill`
## Shallow water hydrodynamics
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.overland_flow
-/generated/api/landlab.components.tidal_flow
-```
+* {mod}`landlab.components.overland_flow`
+* {mod}`landlab.components.tidal_flow`
## Land surface hydrology
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.radiation
-/generated/api/landlab.components.pet
-/generated/api/landlab.components.soil_moisture
-```
+* {mod}`landlab.components.radiation`
+* {mod}`landlab.components.pet`
+* {mod}`landlab.components.soil_moisture`
## Groundwater hydrology
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.groundwater
-```
+* {mod}`landlab.components.groundwater`
## Landslides
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.bedrock_landslider
-/generated/api/landlab.components.landslides
-/generated/api/landlab.components.dimensionless_discharge
-```
+* {mod}`landlab.components.bedrock_landslider`
+* {mod}`landlab.components.landslides`
+* {mod}`landlab.components.dimensionless_discharge`
## Vegetation
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.vegetation_dynamics
-/generated/api/landlab.components.plant_competition_ca
-```
+* {mod}`landlab.components.vegetation_dynamics`
+* {mod}`landlab.components.plant_competition_ca`
## Biota
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.species_evolution
-```
+* {mod}`landlab.components.species_evolution`
## Precipitation
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.uniform_precip
-/generated/api/landlab.components.spatial_precip
-```
+* {mod}`landlab.components.uniform_precip`
+* {mod}`landlab.components.spatial_precip`
## Weathering
-```{toctree}
-:maxdepth: 2
-
-/generated/api/landlab.components.weathering
-```
+* {mod}`landlab.components.weathering`
## Subaqueous / Submarine Processes
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.carbonate
-/generated/api/landlab.components.marine_sediment_transport
-```
+* {mod}`landlab.components.carbonate`
+* {mod}`landlab.components.marine_sediment_transport`
## Generic numerical components
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.advection
-```
+* {mod}`landlab.components.advection`
## Terrain Analysis
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.steepness_index
-/generated/api/landlab.components.chi_index
-/generated/api/landlab.components.drainage_density
-/generated/api/landlab.components.profiler.channel_profiler
-/generated/api/landlab.components.profiler.trickle_down_profiler
-/generated/api/landlab.components.hack_calculator
-/generated/api/landlab.components.hand_calculator
-```
+* {mod}`landlab.components.steepness_index`
+* {mod}`landlab.components.chi_index`
+* {mod}`landlab.components.drainage_density`
+* {mod}`landlab.components.profiler.channel_profiler`
+* {mod}`landlab.components.profiler.trickle_down_profiler`
+* {mod}`landlab.components.hack_calculator`
+* {mod}`landlab.components.hand_calculator`
## Tectonics
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.flexure
-/generated/api/landlab.components.gflex
-/generated/api/landlab.components.normal_fault
-/generated/api/landlab.components.tectonics
-```
+* {mod}`landlab.components.flexure`
+* {mod}`landlab.components.gflex`
+* {mod}`landlab.components.normal_fault`
+* {mod}`landlab.components.tectonics`
## Fire
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.fire_generator
-```
+* {mod}`landlab.components.fire_generator`
## Fracture Generation
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.fracture_grid
-```
+* {mod}`landlab.components.fracture_grid`
diff --git a/docs/source/user_guide/reference/grid.md b/docs/source/user_guide/reference/grid.md
index 4f375bce75..dcdbbf1475 100644
--- a/docs/source/user_guide/reference/grid.md
+++ b/docs/source/user_guide/reference/grid.md
@@ -11,50 +11,39 @@ The following is an introduction to their properties and methods:
```{jinja} llcats
{% for name in grids|sort %}
-* {{"{"}}class{{"}"}}`~.{{name}}`
+* {{"{"}}class{{"}"}}`landlab.{{name}}`
{% endfor %}
```
## Additional Methods and Properties
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.grid.base
-/generated/api/landlab.grid.create
-/generated/api/landlab.grid.decorators
-/generated/api/landlab.grid.diagonals
-/generated/api/landlab.grid.divergence
-/generated/api/landlab.grid.gradients
-/generated/api/landlab.grid.grid_funcs
-/generated/api/landlab.grid.linkstatus
-/generated/api/landlab.grid.mappers
-/generated/api/landlab.grid.nodestatus
-/generated/api/landlab.grid.raster_aspect
-/generated/api/landlab.grid.raster_funcs
-/generated/api/landlab.grid.raster_gradients
-/generated/api/landlab.grid.raster_mappers
-/generated/api/landlab.grid.raster_set_status
-/generated/api/landlab.grid.warnings
-```
+* {mod}`landlab.grid.create`
+* {mod}`landlab.grid.decorators`
+* {mod}`landlab.grid.diagonals`
+* {mod}`landlab.grid.divergence`
+* {mod}`landlab.grid.gradients`
+* {mod}`landlab.grid.grid_funcs`
+* {mod}`landlab.grid.linkstatus`
+* {mod}`landlab.grid.mappers`
+* {mod}`landlab.grid.nodestatus`
+* {mod}`landlab.grid.raster_aspect`
+* {mod}`landlab.grid.raster_funcs`
+* {mod}`landlab.grid.raster_gradients`
+* {mod}`landlab.grid.raster_mappers`
+* {mod}`landlab.grid.raster_set_status`
+* {mod}`landlab.grid.warnings`
## API for each grid type
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.grid.base
-/generated/api/landlab.grid.raster
-/generated/api/landlab.grid.voronoi
-/generated/api/landlab.grid.framed_voronoi
-/generated/api/landlab.grid.hex
-/generated/api/landlab.grid.radial
-/generated/api/landlab.grid.network
-/generated/api/landlab.grid.icosphere
-```
+* {mod}`landlab.grid.base`
+* {mod}`landlab.grid.raster`
+* {mod}`landlab.grid.voronoi`
+* {mod}`landlab.grid.framed_voronoi`
+* {mod}`landlab.grid.hex`
+* {mod}`landlab.grid.radial`
+* {mod}`landlab.grid.network`
+* {mod}`landlab.grid.icosphere`
## Additional Grid Base Classes
-```{toctree}
-/generated/api/landlab.grid.unstructured
-```
+* {mod}`landlab.grid.unstructured`
diff --git a/docs/source/user_guide/reference/index.md b/docs/source/user_guide/reference/index.md
index cc699c4c73..ad7bd8e034 100644
--- a/docs/source/user_guide/reference/index.md
+++ b/docs/source/user_guide/reference/index.md
@@ -11,54 +11,8 @@ methods.
:maxdepth: 2
grid
-```
-
-## Layers
-
-```{toctree}
-:maxdepth: 2
-
layers
-```
-
-## Lithology
-
-Two objects based on the EventLayers object exist to make it easier to deal
-with spatially variable lithology and associated properties. The Lithology
-components contain information about spatially variable lithology and connect
-with the Landlab model grid so that when rock is eroded or advected upward by
-rock uplift the values of rock propeties at the topographic surface are updated.
-
-First is the Lithology component which is a generic object for variable
-lithology.
-
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.lithology.lithology
-```
-
-Second is LithoLayers which makes it easy to make layered rock.
-
-```{toctree}
-:maxdepth: 1
-
-/generated/api/landlab.components.lithology.litholayers
-```
-
-## Values
-
-```{toctree}
-:maxdepth: 2
-
values
-```
-
-## Components
-
-```{toctree}
-:maxdepth: 2
-
components
```
diff --git a/docs/source/user_guide/reference/layers.md b/docs/source/user_guide/reference/layers.md
index cbf0e9e3e6..15c61973cd 100644
--- a/docs/source/user_guide/reference/layers.md
+++ b/docs/source/user_guide/reference/layers.md
@@ -3,15 +3,33 @@
# Layers
Landlab has the ability to add layers to the grid. Two types of layers are
-currently supported. First is EventLayers in which each event is preserved as
-an entry into the datastructure, even if no deposition occurs. If you are
-interested in chronostratigraphy, this is probably what you are interested in.
-Second is MaterialLayers, in which each layer must contain some material.
-If an entire layer is eroded in MaterialLayers, the layer is removed.
-MaterialLayers will likely use less memory than EventLayers.
-
-```{toctree}
-:maxdepth: 2
-
-/generated/api/landlab.layers
-```
+currently supported. First is {class}`~landlab.layers.eventlayers.EventLayers`
+in which each event is preserved as an entry into the datastructure, even if no
+deposition occurs. If you are interested in chronostratigraphy, this is probably what
+you are interested in. Second is {class}`~landlab.layers.materiallayers.MaterialLayers`,
+in which each layer must contain some material. If an entire layer is eroded in
+{class}`~landlab.layers.materiallayers.MaterialLayers`, the layer is removed.
+{class}`~landlab.layers.materiallayers.MaterialLayers` will likely use less memory
+than {class}`~landlab.layers.eventlayers.EventLayers`.
+
+* {class}`landlab.layers.eventlayers.EventLayers`
+* {class}`landlab.layers.materiallayers.MaterialLayers`
+
+## Lithology
+
+Two objects based on the {class}`~landlab.layers.eventlayers.EventLayers` object exist
+to make it easier to deal with spatially variable lithology and associated properties.
+The {mod}`~landlab.components.lithology` components contain information about spatially
+variable lithology and connect with the Landlab model grid so that when rock is eroded
+or advected upward by rock uplift the values of rock propeties at the topographic
+surface are updated.
+
+First is the {class}`~landlab.components.lithology.lithology.Lithology` component,
+which is a generic object for variable lithology.
+
+* {class}`landlab.components.lithology.lithology.Lithology`
+
+Second is {class}`~landlab.components.lithology.litholayers.LithoLayers` which makes
+it easy to make layered rock.
+
+* {class}`landlab.components.lithology.litholayers.LithoLayers`
diff --git a/docs/source/user_guide/reference/values.md b/docs/source/user_guide/reference/values.md
index 04bd207941..dc0c48e02a 100644
--- a/docs/source/user_guide/reference/values.md
+++ b/docs/source/user_guide/reference/values.md
@@ -5,8 +5,4 @@
Landlab includes a number of ways to create values for model grid fields.
As with the rest of Landlab, we welcome contributions to this package.
-```{toctree}
-:maxdepth: 2
-
-/generated/api/landlab.values
-```
+* {mod}`landlab.values`
diff --git a/joss/in_preparation/river_flow_dynamics/paper.bib b/joss/in_preparation/river_flow_dynamics/paper.bib
new file mode 100644
index 0000000000..d5ccbba1c1
--- /dev/null
+++ b/joss/in_preparation/river_flow_dynamics/paper.bib
@@ -0,0 +1,138 @@
+@article{hobley:2017,
+ title={
+ Creative computing with Landlab: an open-source toolkit for building,
+ coupling, and exploring two-dimensional numerical models of
+ Earth-surface dynamics
+ },
+ author={
+ Hobley, Daniel EJ and Adams, Jordan M and Nudurupati, Sai Siddhartha and
+ Hutton, Eric WH and Gasparini, Nicole M and Istanbulluoglu, Erkan and
+ Tucker, Gregory E
+ },
+ journal={Earth Surface Dynamics},
+ volume={5},
+ number={1},
+ pages={21--46},
+ year={2017},
+ publisher={Copernicus GmbH},
+ url={https://esurf.copernicus.org/articles/5/21/2017/},
+ doi={10.5194/esurf-5-21-2017}
+}
+
+@article{barnhart:2020,
+ title={Landlab v2. 0: a software package for Earth surface dynamics},
+ author={
+ Barnhart, Katherine R and Hutton, Eric WH and Tucker, Gregory E and
+ Gasparini, Nicole M and Istanbulluoglu, Erkan and Hobley, Daniel EJ and
+ Lyons, Nathan J and Mouchene, Margaux and Nudurupati, Sai Siddhartha and
+ Adams, Jordan M and others
+ },
+ journal={Earth Surface Dynamics},
+ volume={8},
+ number={2},
+ pages={379--397},
+ year={2020},
+ publisher={Copernicus GmbH}
+ url = {https://esurf.copernicus.org/articles/8/379/2020/},
+ doi = {10.5194/esurf-8-379-2020}
+}
+
+@article{casulli_semi-implicit_1999,
+ title = {A semi-implicit finite difference method for non-hydrostatic, free-surface flows},
+ volume = {30},
+ copyright = {http://doi.wiley.com/10.1002/tdm\_license\_1.1},
+ issn = {0271-2091, 1097-0363},
+ url = {https://onlinelibrary.wiley.com/doi/10.1002/(SICI)1097-0363(19990630)30:4<425::AID-FLD847>3.0.CO;2-D},
+ doi = {10.1002/(SICI)1097-0363(19990630)30:4<425::AID-FLD847>3.0.CO;2-D},
+ abstract = {In this paper a semi-implicit finite difference model for non-hydrostatic, free-surface flows is analyzed and discussed. It is shown that the present algorithm is generally more accurate than recently developed models for quasi-hydrostatic flows. The governing equations are the free-surface Navier – Stokes equations defined on a general, irregular domain of arbitrary scale. The momentum equations, the incompressibility condition and the equation for the free-surface are integrated by a semi-implicit algorithm in such a fashion that the resulting numerical solution is mass conservative and unconditionally stable with respect to the gravity wave speed, wind stress, vertical viscosity and bottom friction. Copyright © 1999 John Wiley \& Sons, Ltd.},
+ language = {en},
+ number = {4},
+ urldate = {2024-09-05},
+ journal = {International Journal for Numerical Methods in Fluids},
+ author = {Casulli, Vincenzo},
+ month = jun,
+ year = {1999},
+ pages = {425--440}
+}
+
+@article{casulli1990semi,
+ title={Semi-implicit finite difference methods for the two-dimensional shallow water equations},
+ author={Casulli, Vincenzo},
+ journal={Journal of Computational Physics},
+ volume={86},
+ number={1},
+ pages={56--74},
+ year={1990},
+ publisher={Elsevier}
+}
+
+@article{robert1985semi,
+ title={A semi-Lagrangian and semi-implicit numerical integration scheme for multilevel atmospheric models},
+ author={Robert, Andr{\'e} and Yee, Tai Loy and Ritchie, Harold},
+ journal={Monthly Weather Review},
+ volume={113},
+ number={3},
+ pages={388--394},
+ year={1985}
+}
+
+@article{robert_stable_1981,
+ title = {A stable numerical integration scheme for the primitive meteorological equations},
+ volume = {19},
+ issn = {0705-5900, 1480-9214},
+ url = {http://www.tandfonline.com/doi/abs/10.1080/07055900.1981.9649098},
+ doi = {10.1080/07055900.1981.9649098},
+ abstract = {A stable numerical integration scheme is applied to the non-divergent barotropic vorticity equation. Integrations areperformed with time steps rangingfrom 15minto 4 h. The root-mean-square differences between theforecasts are calculated in order to measure the sensitivity of the predictions to thesize of the time step. These experiments show that the truncation errors remain reasonably small with time steps as large as two hours.},
+ language = {en},
+ number = {1},
+ urldate = {2024-09-05},
+ journal = {Atmosphere-Ocean},
+ author = {Robert, André},
+ month = mar,
+ year = {1981},
+ pages = {35--46},
+}
+
+@article{staniforth1991semi,
+ title={Semi-Lagrangian integration schemes for atmospheric models—A review},
+ author={Staniforth, Andrew and C{\^o}t{\'e}, Jean},
+ journal={Monthly weather review},
+ volume={119},
+ number={9},
+ pages={2206--2223},
+ year={1991}
+}
+
+@article{bates1982multiply,
+ title={Multiply-upstream, semi-Lagrangian advective schemes: Analysis and application to a multi-level primitive equation model},
+ author={Bates, JR and McDonald, A},
+ journal={Monthly Weather Review},
+ volume={110},
+ number={12},
+ pages={1831--1842},
+ year={1982}
+}
+
+@book{andersson2011computational,
+ title={Computational fluid dynamics for engineers},
+ author={Andersson, Bengt and Andersson, Ronnie and H{\aa}kansson, Love and Mortensen, Mikael and Sudiyo, Rahman and Van Wachem, Berend},
+ year={2011},
+ publisher={Cambridge university press}
+}
+
+@book{fletcher2012computational,
+ title={Computational techniques for fluid dynamics 2: Specific techniques for different flow categories},
+ author={Fletcher, Clive AJ},
+ year={2012},
+ publisher={Springer Science \& Business Media}
+}
+
+@software{Hutton:2020,
+author = {Hutton, Eric and Barnhart, Katy and Hobley, Dan and Tucker, Greg and Nudurupati, Sai and Adams, Jordan and Gasparini, Nicole and Shobe, Charlie and Strauch, Ronda and Knuth, Jenny and Mouchene, Margaux and Lyons, Nathan and Litwin, David and Glade, Rachel and {Giuseppecipolla95} and Manaster, Amanda and Abby, Langston and Thyng, Kristen and Rengers, Francis},
+doi = {10.5281/zenodo.595872},
+license = {MIT},
+month = {4},
+title = {{landlab}},
+url = {https://github.com/landlab/landlab},
+year = {2020}
+}
diff --git a/joss/in_preparation/river_flow_dynamics/paper.md b/joss/in_preparation/river_flow_dynamics/paper.md
new file mode 100644
index 0000000000..d18c67db2c
--- /dev/null
+++ b/joss/in_preparation/river_flow_dynamics/paper.md
@@ -0,0 +1,70 @@
+---
+title: 'RiverFlowDynamics v1.0: A Landlab component for computing two-dimensional river flow dynamics'
+
+tags:
+ - Landlab
+ - Python
+ - Shallow water equations
+ - Saint-Venant equation
+ - river
+
+authors:
+ - name: Sebastian Bernal
+ orcid: 0009-0006-7758-3648
+ equal-contrib: true
+ affiliation: 1
+ - name: Angel Monsalve
+ orcid: 0000-0002-7369-1602
+ equal-contrib: true
+ affiliation: 1
+ corresponding: true
+ - name: Oscar Link
+ orcid: 0000-0002-2188-6504
+ equal-contrib: true
+ affiliation: 2
+
+affiliations:
+ - name: Center for Ecohydraulics Research, Civil and Environmental Engineering, University of Idaho, Boise, ID, USA
+ index: 1
+ - name: Departamento de Ingeniería Civil, Universidad de Concepción, Concepción, Chile
+ index: 2
+
+date: 05 September 2024
+
+bibliography: paper.bib
+
+---
+# Summary
+
+Numerical modeling of surface water flow is a critical tool in hydrology, hydraulics, and environmental science. These models play a crucial role in predicting and analyzing flow patterns in rivers, flood plains, and coastal areas, informing decisions in water resource management, flood risk assessment, and ecosystem conservation. This paper introduces a novel two-dimensional flow model, RiverFlowDynamics, developed as a component of the LandLab Python Package [@hobley:2017;@barnhart:2020;@Hutton:2020;@Hutton:2020], designed to simulate the behavior of rivers and streams under various flow conditions over natural and artificial topography
+
+RiverFlowDynamics is founded on the depth-averaged Saint-Venant equations, also known as the shallow water equations [@casulli1990semi;@casulli_semi-implicit_1999]. These equations, derived from the Navier-Stokes equations for incompressible flow, are simplified by integrating over the water depth. This approach assumes that vertical accelerations are negligible compared to horizontal ones, a reasonable approximation for many surface water flows. The governing equations consist of continuity and momentum balance equations in two dimensions, capturing the essential dynamics of free-surface flows.
+
+For the numerical solution of these equations, RiverFlowDynamics employs the finite volume method, chosen for its robustness, capacity to handle complex geometries, and inherent conservation properties [@andersson2011computational;@fletcher2012computational]. The computational domain is discretized into a uniform rectangular grid, with water surface elevation defined at cell centers and velocity components at cell interfaces. This staggered grid arrangement helps in maintaining numerical stability and accuracy. The numerical implementation results in a penta-diagonal, positive-definite system of equations. This system is solved efficiently using the preconditioned conjugate gradient method, ensuring rapid convergence even for large domains. The model's structure allows for easy parallelization, potentially enabling simulations of extensive river networks or large coastal areas.
+
+A key feature of the model is its semi-implicit and semi-Lagrangian representation. The semi-implicit scheme treats water surface elevation and velocity implicitly, while handling advective terms explicitly. This approach allows for larger time steps compared to fully explicit schemes, enhancing computational efficiency. The semi-Lagrangian method for advection involves tracking fluid particles backwards along their flow lines, providing additional stability and accuracy, particularly for flows with strong advective components [@robert1985semi;@robert_stable_1981].
+
+The advection representation uses a semi-Lagrangian scheme on an Eulerian grid, a two-step process where particles are tracked backwards along their flow lines to their starting points [@staniforth1991semi]. This method, combined with the semi-implicit time discretization, allows for a relaxation of the Courant-Friedrichs-Lewy (CFL) condition, typically a limiting factor in explicit schemes [@bates1982multiply].
+
+Source terms in the model primarily account for bottom friction, implemented using the Manning-Chezy formula [@he2017numerical;@brufau2000two]. While the model framework allows for the inclusion of wind stress and Coriolis effects, these are considered negligible in the current implementation, focusing on river and stream applications where these effects are typically less significant.
+
+Flow line tracing, crucial for the semi-Lagrangian advection scheme, employs Pollock's semi-analytical method [@pollock1988semianalytical]. This method assumes linear velocity variation within each grid cell, allowing for an efficient and accurate computation of particle trajectories. This approach is particularly effective in capturing complex flow patterns in natural river systems.
+
+A notable feature of the model is its robust handling of dry/wet cell transitions, crucial for simulating flows over complex topography or in areas with varying water levels. RiverFLowDynamics employs the method of @casulli1992semi, in which the model automatically determines wet and dry cell faces based on local flow conditions, eliminating the need for explicit specification of internal boundaries.
+
+Boundary conditions are implemented to handle both open and closed boundaries. Dirichlet conditions are used for inlet boundaries, specifying flow rates and water depths. For open boundaries where water can freely enter or exit the domain, the model offers both gradient-based and radiation-based conditions. These allow for the realistic simulation of wave propagation and minimize artificial reflections at the domain boundaries.
+
+RiverFlowDynamics, as a full 2D flow model, offers several advantages over simpler flow models, including traditional overland flow models available in Landlab [@adams2017landlab;@de2012improving]. While overland flow models typically focus on shallow sheet flow and often use simplified equations like the kinematic wave approximation, RiverFlowDynamics solves the complete depth-averaged Saint-Venant equations. This approach allows for a more comprehensive representation of complex flow dynamics, including subcritical and supercritical flows, hydraulic jumps, and intricate channel-floodplain interactions. The model's ability to capture these phenomena makes it superior in scenarios involving rapid flood propagation in urban areas, detailed floodplain mapping, or the analysis of complex river morphodynamics. Furthermore, the semi-Lagrangian scheme employed in RiverFlowDynamics provides enhanced stability and accuracy for advection-dominated flows, a critical advantage when modeling high-velocity currents or steep terrain where simpler models might fail. This makes RiverFlowDynamics particularly well-suited for applications in mountainous regions, urban flood modeling, from small-scale stream dynamics to large-scale flood simulations, or any situation where capturing the full range of flow regimes and their transitions is crucial for accurate predictions. The accessibility of this code within the Landlab framework will make it easier for future users to modify and contribute to its continual evolution.
+
+Source code for RiverFlowDynamics is available as part of the Landlab Python package (v2.7.0 and later) and can be found in the RiverFlowDynamics component. The Landlab project maintains a separate repository containing tutorials, including a complete example of RiverFlowDynamics usage in a Jupyter Notebook.
+
+# Statement of need
+
+RiverFlowDynamics is a Python-based 2D flow model developed as a component of the Landlab framework, addressing a critical gap in the modeling of complex river systems and flood dynamics. Prior to RiverFlowDynamics, Landlab lacked a comprehensive 2D flow model capable of handling fully advective-dominated problems, particularly in rivers with complex topographies. This limitation hindered accurate simulations of diverse flow regimes and transitions crucial for advanced hydrological and environmental studies.
+
+RiverFlowDynamics solves the complete depth-averaged Saint-Venant equations, offering a significant advancement over existing Landlab components that typically use simplified equations like the kinematic wave approximation. This approach enables the model to capture complex flow dynamics, including subcritical and supercritical flows, hydraulic jumps, and intricate channel-floodplain interactions. The model's capabilities make it particularly valuable for a wide range of applications, from small-scale stream dynamics to large-scale flood simulations. It is design to be applicable in scenarios involving rapid flood propagation in urban areas, detailed floodplain mapping, and the analysis of complex river morphodynamics in mountainous regions. By integrating RiverFlowDynamics into the Landlab framework, we provide researchers, students, and practitioners with a powerful, accessible tool for hydraulics modeling. This integration facilitates future modifications and contributions, ensuring the model's continual evolution to meet emerging challenges in river system analysis and flood risk assessment.
+
+# Acknowledgements
+Funding for this research was provided by Chilean National Agency for Research and Development – ANID though the programme FONDECYT Iniciación grant 11200949. Landlab is supported by the National Science Foundation (NSF Award Numbers 1147454, 1148305, 1450409, 1450338, and 1450412) and by the Community Surface Dynamics Modeling System (NSF Award Numbers 1226297 and 1831623).
+
+# References
diff --git a/joss/published/groundwater/Litwin_et_al_2020_paper.md b/joss/published/groundwater/Litwin_et_al_2020_paper.md
index 156aeb8f20..27db1cebc4 100644
--- a/joss/published/groundwater/Litwin_et_al_2020_paper.md
+++ b/joss/published/groundwater/Litwin_et_al_2020_paper.md
@@ -43,7 +43,7 @@ The ``GroundwaterDupuitPercolator`` solves the governing groundwater flow equati
The ``GroundwaterDupuitPercolator`` can be implemented on both regular (e.g. rectangular and hexagonal) and irregular grids determined by the user. Recharge, hydraulic conductivity, and porosity may be specified as single values uniform over the model domain, or as vectors on the nodes (recharge, porosity) or links (hydraulic conductivity) of the grid. Link hydraulic conductivity can also be specified from a two-dimensional hydraulic conductivity tensor using an included function. For mass balance calculations, the model includes methods to determine the total groundwater storage on the grid domain, the total recharge flux in, and total groundwater and surface water fluxes leaving through the boundaries.
-The ``GroundwaterDupuitPercolator`` is implemented in Landlab, a Python-based open source Earth surface modeling toolkit [@hobley_creative_2017]. Landlab has a modular framework, which allows for easy coupling of different process components to meet the needs of the modeler. For example, the surface water flux from the ``GroundwaterDupuitPercolator`` can be passed to the ``FlowAccumulator`` module to route overland flow and calculate discharge at nodes. A summary of links to the documentation and example Jupyter notebooks is provided by the submodule [README](https://github.com/landlab/landlab/tree/master/landlab/components/groundwater). A diverse array of components are available, yielding many possibilities for model coupling that have not yet been explored. Given the importance of groundwater for many Earth surface processes, this component is an important contribution to the Landlab environment.
+The ``GroundwaterDupuitPercolator`` is implemented in Landlab, a Python-based open source Earth surface modeling toolkit [@hobley_creative_2017]. Landlab has a modular framework, which allows for easy coupling of different process components to meet the needs of the modeler. For example, the surface water flux from the ``GroundwaterDupuitPercolator`` can be passed to the ``FlowAccumulator`` module to route overland flow and calculate discharge at nodes. A summary of links to the documentation and example Jupyter notebooks is provided by the submodule [README](https://github.com/landlab/landlab/tree/master/src/landlab/components/groundwater). A diverse array of components are available, yielding many possibilities for model coupling that have not yet been explored. Given the importance of groundwater for many Earth surface processes, this component is an important contribution to the Landlab environment.
# Acknowledgements
diff --git a/joss/published/lithology/barnhart_et_al_2019_paper.md b/joss/published/lithology/barnhart_et_al_2019_paper.md
index 30804ccfdc..6a57683f50 100644
--- a/joss/published/lithology/barnhart_et_al_2019_paper.md
+++ b/joss/published/lithology/barnhart_et_al_2019_paper.md
@@ -79,9 +79,9 @@ submodule](https://github.com/landlab/landlab/tree/release/landlab/components/li
The ``Lithology`` submodule is documented using Docstrings, and the
documentation can be found on the Landlab ReadTheDocs site. One page exists for
the [Lithology
-component](https://landlab.readthedocs.io/en/release/landlab.components.lithology.html)
+component](https://landlab.csdms.io/generated/api/landlab.components.lithology.lithology.html)
and a second for the [LithoLayers
-component](https://landlab.readthedocs.io/en/release/landlab.components.litholayers.html).
+component](https://landlab.csdms.io/generated/api/landlab.components.lithology.litholayers.html).
Unit and docstring tests provide 100% coverage of this submodule. [Pull Request #
674](https://github.com/landlab/landlab/pull/674) brought the ``Lithology``
submodule into the core Landlab source code. The first release version of
@@ -92,7 +92,7 @@ and the archive for this manuscript points to the Zenodo archive of v1.5.4.
The Landlab project maintains a separate repository containing tutorials that
introduce core concepts and the use of individual submodules. In addition to the
source code, a [Jupyter Notebook introducing the use of Lithology and
-Litholayers](https://nbviewer.jupyter.org/github/landlab/tutorials/blob/release/lithology/lithology_and_litholayers.ipynb)
+Litholayers](https://landlab.csdms.io/tutorials/lithology/lithology_and_litholayers.html)
is now part of the Landlab tutorials repository. This tutorial was brought into
the repository with [Pull Request #
19](https://github.com/landlab/tutorials/pull/19). The first release version of
diff --git a/joss/in_preparation/network_sediment_transporter/papers.bib b/joss/published/network_sediment_transporter/papers.bib
similarity index 100%
rename from joss/in_preparation/network_sediment_transporter/papers.bib
rename to joss/published/network_sediment_transporter/papers.bib
diff --git a/joss/in_preparation/network_sediment_transporter/paper.md b/joss/published/network_sediment_transporter/pfeiffer_et_at_2020.md
similarity index 100%
rename from joss/in_preparation/network_sediment_transporter/paper.md
rename to joss/published/network_sediment_transporter/pfeiffer_et_at_2020.md
diff --git a/joss/published/species_evolver/lyons_et_al_2020_paper.md b/joss/published/species_evolver/lyons_et_al_2020_paper.md
index fc939d3c0e..f986d50c86 100644
--- a/joss/published/species_evolver/lyons_et_al_2020_paper.md
+++ b/joss/published/species_evolver/lyons_et_al_2020_paper.md
@@ -50,7 +50,7 @@ Landscape connectivity of ``ZoneTaxon`` is determined by the spatiotemporal rela
* many-to-many: Multiple zones in the prior step are overlapped by multiple zones in the current step. Zone counts in both the prior and current steps must be greater than one for the connectivity to be assigned this relationship. Zone counts in these steps do not need to be the same for the connectivity to be assigned this relationship. Taxa extant in prior step zones are relocated to current step zones. Speciation occurs following the ``allopatric_wait_time`` parameter set for the taxon.
* one-to-none: A zone in the prior step overlaps no zones in the current step. Taxa in the zone of the prior step become extinct as of the current time step.
-@Lyons:2019 used the built-in taxon type, ``ZoneTaxon`` to investigate how changes in stream network connectivity impacted the diversity of simulated riverine species in this first application of ``SpeciesEvolver``. The species were populated to stream grid nodes and diversification emerged where stream connectivity changed. The flexibility of ``SpeciesEvolver`` with the growing library of surface processes in ``Landlab`` provides ample opportunities to discover links between landscapes and its biota. Links to ``SpeciesEvolver`` documentation and Jupyter Notebook tutorials are provided in the component [README](https://github.com/landlab/landlab/tree/master/landlab/components/species_evolution).
+@Lyons:2019 used the built-in taxon type, ``ZoneTaxon`` to investigate how changes in stream network connectivity impacted the diversity of simulated riverine species in this first application of ``SpeciesEvolver``. The species were populated to stream grid nodes and diversification emerged where stream connectivity changed. The flexibility of ``SpeciesEvolver`` with the growing library of surface processes in ``Landlab`` provides ample opportunities to discover links between landscapes and its biota. Links to ``SpeciesEvolver`` documentation and Jupyter Notebook tutorials are provided in the component [README](https://github.com/landlab/landlab/tree/master/src/landlab/components/species_evolution).
# Figures
diff --git a/news/1979.component.rst b/news/1979.component.rst
new file mode 100644
index 0000000000..e3a9351ce9
--- /dev/null
+++ b/news/1979.component.rst
@@ -0,0 +1,5 @@
+
+Adds a new 2D flow solver to Landlab. RiverFlowDynamics implements a semi-implicit,
+semi-Lagrangian finite-volume approximation of the depth-averaged shallow water
+equations, originally proposed by Casulli and Cheng in 1992, along with
+subsequent related work.
diff --git a/news/1986.misc b/news/1986.misc
new file mode 100644
index 0000000000..19254d66ca
--- /dev/null
+++ b/news/1986.misc
@@ -0,0 +1 @@
+Minor improvements to plot_network_and_parcels to allow straightforward compatability with imshowgrid.
diff --git a/news/1999.misc b/news/1999.misc
new file mode 100644
index 0000000000..51a5a037ba
--- /dev/null
+++ b/news/1999.misc
@@ -0,0 +1,3 @@
+
+Deprecated passing the `at` keyword as the first argument to
+functions like, for example, :meth:`~.GraphFields.add_ones`.
diff --git a/news/2017.misc b/news/2017.misc
new file mode 100644
index 0000000000..616077eda9
--- /dev/null
+++ b/news/2017.misc
@@ -0,0 +1,2 @@
+
+Added support for Python 3.13 and dropped support for 3.10.
diff --git a/news/2020.component b/news/2020.component
new file mode 100644
index 0000000000..165deebc5f
--- /dev/null
+++ b/news/2020.component
@@ -0,0 +1 @@
+Added ConcentrationTrackerForSpace companion component to the SpaceLargeScaleEroder. The component calculates the movement of sediment property concentrations by fluvial transport across the Landlab grid.
diff --git a/news/2032.docs b/news/2032.docs
new file mode 100644
index 0000000000..e458a43456
--- /dev/null
+++ b/news/2032.docs
@@ -0,0 +1 @@
+Update notebooks that demonstrate Mesa + Landlab.
diff --git a/news/2048.misc b/news/2048.misc
new file mode 100644
index 0000000000..487d4e2fd3
--- /dev/null
+++ b/news/2048.misc
@@ -0,0 +1 @@
+Removed unnecessary toctree directives from the docs.
diff --git a/news/2049.docs b/news/2049.docs
new file mode 100644
index 0000000000..f0bf0aee30
--- /dev/null
+++ b/news/2049.docs
@@ -0,0 +1,3 @@
+
+Fixed an issue with the citation section of the docs that caused the
+tabs to not render correctly.
diff --git a/news/2050.docs b/news/2050.docs
new file mode 100644
index 0000000000..247a4cf075
--- /dev/null
+++ b/news/2050.docs
@@ -0,0 +1,2 @@
+Moved *Lithology* text from the top-level reference page to the *layers* page,
+which describes different types of layering that *Landlab* supports.
diff --git a/news/2051.misc b/news/2051.misc
new file mode 100644
index 0000000000..ea05228090
--- /dev/null
+++ b/news/2051.misc
@@ -0,0 +1,2 @@
+Fixed a *jinja* error when building the docs using newer versions of
+*sphinx*.
diff --git a/news/2052.misc b/news/2052.misc
new file mode 100644
index 0000000000..fd48d6c39a
--- /dev/null
+++ b/news/2052.misc
@@ -0,0 +1,2 @@
+Removed the current module from *sphinx* autosummary tables to be compatible
+with newer version of *sphinx*.
diff --git a/news/2083.misc b/news/2083.misc
new file mode 100644
index 0000000000..41731a6f0b
--- /dev/null
+++ b/news/2083.misc
@@ -0,0 +1,2 @@
+Changed the *mixed-line-ending* *pre-commit* hook to ensure all files
+use a line feed as the end-of-line character.
diff --git a/news/2087.misc b/news/2087.misc
new file mode 100644
index 0000000000..9a8f960225
--- /dev/null
+++ b/news/2087.misc
@@ -0,0 +1,3 @@
+Removed the benchmarks from our unit tests, as they'll be moved to a separate
+repostory. This reduces the amount of time our continuous integration
+tests take to run.
diff --git a/news/2098.feature.rst b/news/2098.feature.rst
new file mode 100644
index 0000000000..b8a4921f4d
--- /dev/null
+++ b/news/2098.feature.rst
@@ -0,0 +1,2 @@
+Updated `KinwaveImplicitOverlandFlow` to accept arrays of floats in
+addition to scalars for both the `runoff_rate` and `roughness` keywords.
diff --git a/news/2117.docs b/news/2117.docs
new file mode 100644
index 0000000000..3fc0084a2c
--- /dev/null
+++ b/news/2117.docs
@@ -0,0 +1 @@
+Updated the links to the landlab documentation to point to landlab.csdms.io.
diff --git a/news/2118.docs b/news/2118.docs
new file mode 100644
index 0000000000..863390a122
--- /dev/null
+++ b/news/2118.docs
@@ -0,0 +1 @@
+Fixed a number of broken links in the documentation.
diff --git a/news/2121.misc b/news/2121.misc
new file mode 100644
index 0000000000..e90a238ce7
--- /dev/null
+++ b/news/2121.misc
@@ -0,0 +1 @@
+Added a new GitHub Actions job that checks the documentation for broken links.
diff --git a/news/2122.misc b/news/2122.misc
new file mode 100644
index 0000000000..035136f8e8
--- /dev/null
+++ b/news/2122.misc
@@ -0,0 +1,2 @@
+Simplified the github actions job that builds the docs by using
+the setup-python action rather than setup-miniconda.
diff --git a/news/2129.misc b/news/2129.misc
new file mode 100644
index 0000000000..3a35889f3a
--- /dev/null
+++ b/news/2129.misc
@@ -0,0 +1,3 @@
+Improved the speed of the continuous integration tests by switching to using
+the *setup-python* action and running the *richdem* tests as their own job
+using a *conda* environment.
diff --git a/news/2132.misc b/news/2132.misc
new file mode 100644
index 0000000000..182343b5c3
--- /dev/null
+++ b/news/2132.misc
@@ -0,0 +1,2 @@
+Added ubuntu arm64 runners to our continuous integration builds. This drastically
+speeds up building for arm64 as compared to using emulation via QEMU.
diff --git a/news/2133.misc b/news/2133.misc
new file mode 100644
index 0000000000..1425b85afd
--- /dev/null
+++ b/news/2133.misc
@@ -0,0 +1 @@
+Changed from *coveralls* to *codecov* for tracking test coverage.
diff --git a/news/2155.docs b/news/2155.docs
new file mode 100644
index 0000000000..5a9de96ab2
--- /dev/null
+++ b/news/2155.docs
@@ -0,0 +1 @@
+Fixed some formatting in the developer installation instructions.
diff --git a/news/2163.bugfix b/news/2163.bugfix
new file mode 100644
index 0000000000..f26e76dccf
--- /dev/null
+++ b/news/2163.bugfix
@@ -0,0 +1 @@
+Fix dimensional error in calculation of Courant number.
diff --git a/news/2166.misc b/news/2166.misc
new file mode 100644
index 0000000000..7ac2f81e6b
--- /dev/null
+++ b/news/2166.misc
@@ -0,0 +1 @@
+Added a mass balance check in the unit tests for deAlmeida OverlandFlow component.
diff --git a/notebooks/requirements.in b/notebooks/requirements.in
index 32af0c84eb..e1ad319663 100644
--- a/notebooks/requirements.in
+++ b/notebooks/requirements.in
@@ -2,4 +2,4 @@ bmi-topography >=0.5,!=0.8.1
dask[array]
holoviews
jupyter
-mesa >1
+mesa[network] >1
diff --git a/notebooks/welcome.ipynb b/notebooks/welcome.ipynb
index 0701a9ef2e..2122d4ecc6 100644
--- a/notebooks/welcome.ipynb
+++ b/notebooks/welcome.ipynb
@@ -20,9 +20,9 @@
"- [the Landlab teaching notebooks](teaching/welcome_teaching.ipynb) if you are an educator looking for tutorials to use in the classroom. \n",
"\n",
"## Other useful links\n",
- "- [The Landlab Documentation](https://landlab.readthedocs.io/en/latest/)\n",
+ "- [The Landlab Documentation](https://landlab.csdms.io/)\n",
"- [The Landlab code base](https://github.com/landlab/landlab)\n",
- "- [The Landlab user guide](https://landlab.readthedocs.io/en/latest/user_guide/)\n",
+ "- [The Landlab user guide](https://landlab.csdms.io/user_guide/)\n",
"\n",
"## Notebooks by topic\n",
"\n",
diff --git a/noxfile.py b/noxfile.py
index f96b7f534f..c5518951fd 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -20,69 +20,68 @@
}
-@nox.session(python=PYTHON_VERSION, venv_backend="conda")
-def build(session: nox.Session) -> None:
+@nox.session(python=PYTHON_VERSION)
+def build(session: nox.Session) -> str:
"""Build sdist and wheel dists."""
+ outdir = str(PATH["build"] / "wheelhouse")
+
os.environ["WITH_OPENMP"] = "1"
session.log(f"CC = {os.environ.get('CC', 'NOT FOUND')}")
- if session.virtualenv.venv_backend != "none":
- session.install(
- "build",
- *("-r", PATH["requirements"] / "required.txt"),
- )
+ session.install(
+ "build",
+ *("-r", PATH["requirements"] / "required.txt"),
+ )
- session.run("python", "-m", "build", "--outdir", "./build/wheelhouse")
+ session.run("python", "-m", "build", "--outdir", outdir)
+ return outdir
-@nox.session(python=PYTHON_VERSION, venv_backend="conda")
-def test(session: nox.Session) -> None:
- """Run the tests."""
- path_args, pytest_args = pop_option(session.posargs, "--path")
- if session.virtualenv.venv_backend != "none":
- os.environ["WITH_OPENMP"] = "1"
- session.log(f"CC = {os.environ.get('CC', 'NOT FOUND')}")
- session.install(
- *("-r", PATH["requirements"] / "required.txt"),
- *("-r", PATH["requirements"] / "testing.txt"),
- )
- session.conda_install("richdem", channel=["nodefaults", "conda-forge"])
-
- arg = path_args[0] if path_args else None
- if arg is None:
- session.install(".", "--no-deps")
- elif os.path.isdir(arg):
- session.install("landlab", f"--find-links={arg}", "--no-deps", "--no-index")
- elif os.path.isfile(arg):
- session.install(arg, "--no-deps")
- else:
- session.error("--path must be either a wheel for a wheelhouse folder")
+@nox.session(python=PYTHON_VERSION)
+def install(session: nox.Session) -> None:
+ arg = session.posargs[0] if session.posargs else build(session)
- check_package_versions(session, files=["required.txt", "testing.txt"])
+ session.install("-r", PATH["requirements"] / "required.txt")
- args = [
- "pytest",
- *("-n", "auto"),
- *("--cov", PROJECT),
- "-vvv",
- # *("--dist", "worksteal"),
- ] + pytest_args
+ if os.path.isdir(arg):
+ session.install("landlab", f"--find-links={arg}", "--no-deps", "--no-index")
+ elif os.path.isfile(arg):
+ session.install(arg, "--no-deps")
+ else:
+ session.error("first argument must be either a wheel or a wheelhouse folder")
- if "CI" in os.environ:
- args.append(f"--cov-report=xml:{ROOT.absolute()!s}/coverage.xml")
- session.run(*args)
- if "CI" not in os.environ:
- session.run("coverage", "report", "--ignore-errors", "--show-missing")
+@nox.session(python=PYTHON_VERSION)
+def test(session: nox.Session) -> None:
+ """Run the tests."""
+ session.install("-r", PATH["requirements"] / "testing.txt")
+ install(session)
+
+ session.run(
+ "coverage",
+ "run",
+ "--source=landlab,tests",
+ "--branch",
+ "--module",
+ "pytest",
+ env={"PYTEST_ADDOPTS": os.environ.get("PYTEST_ADDOPTS", "-m 'not richdem'")},
+ )
+ session.run("coverage", "report", "--ignore-errors", "--show-missing")
+ session.run("coverage", "xml", "-o", "coverage.xml")
-@nox.session(name="test-notebooks", python=PYTHON_VERSION, venv_backend="conda")
+@nox.session(name="test-notebooks", python=PYTHON_VERSION)
def test_notebooks(session: nox.Session) -> None:
"""Run the notebooks."""
- path_args, pytest_args = pop_option(session.posargs, "--path")
+ session.install(
+ "git+https://github.com/mcflugen/nbmake.git@v1.5.4-markers",
+ *("-r", PATH["requirements"] / "testing.txt"),
+ *("-r", PATH["requirements"] / "notebooks.txt"),
+ )
+ install(session)
- args = [
+ session.run(
"pytest",
"notebooks",
"--nbmake",
@@ -90,51 +89,45 @@ def test_notebooks(session: nox.Session) -> None:
"--nbmake-timeout=3000",
*("-n", "auto"),
"-vvv",
- ] + pytest_args
-
- if session.virtualenv.venv_backend != "none":
- os.environ["WITH_OPENMP"] = "1"
- session.conda_install("richdem", channel=["nodefaults", "conda-forge"])
- session.install(
- "git+https://github.com/mcflugen/nbmake.git@v1.5.4-markers",
- *("-r", PATH["requirements"] / "required.txt"),
- *("-r", PATH["requirements"] / "testing.txt"),
- *("-r", PATH["requirements"] / "notebooks.txt"),
- )
-
- arg = path_args[0] if path_args else "."
- if arg is None:
- session.install(".", "--no-deps")
- elif os.path.isdir(arg):
- session.install("landlab", f"--find-links={arg}", "--no-deps", "--no-index")
- elif os.path.isfile(arg):
- session.install(arg, "--no-deps")
- else:
- session.error("--path must be either a wheel for a wheelhouse folder")
-
- check_package_versions(
- session, files=["required.txt", "testing.txt", "notebooks.txt"]
+ env={"PYTEST_ADDOPTS": os.environ.get("PYTEST_ADDOPTS", "-m 'not richdem'")},
)
- session.run(*args)
+@nox.session(name="test-richdem", venv_backend="conda")
+def test_richdem(session: nox.Session) -> None:
+ """Run richdem tests."""
+ session.conda_install("richdem", channel=["nodefaults", "conda-forge"])
+ session.install(
+ "git+https://github.com/mcflugen/nbmake.git@v1.5.4-markers",
+ *("-r", PATH["requirements"] / "testing.txt"),
+ *("-r", PATH["requirements"] / "notebooks.txt"),
+ )
+ install(session)
-def pop_option(args: list[str], opt: str):
- the_rest = []
- opts = []
- for arg in args:
- if arg.startswith(f"{opt}="):
- _, value = arg.split("=", maxsplit=1)
- opts += glob.glob(value)
- else:
- the_rest.append(arg)
- return opts, the_rest
+ session.run(
+ "coverage",
+ "run",
+ "--source=landlab,tests",
+ "--branch",
+ "--module",
+ "pytest",
+ "tests",
+ "notebooks",
+ "--nbmake",
+ "--nbmake-kernel=python3",
+ "--nbmake-timeout=3000",
+ *("-m", "richdem"),
+ *("-n", "auto"),
+ "-vvv",
+ )
+ session.run("coverage", "report", "--ignore-errors", "--show-missing")
+ session.run("coverage", "xml", "-o", "coverage.xml")
@nox.session(name="test-cli")
def test_cli(session: nox.Session) -> None:
"""Test the command line interface."""
- session.install(".")
+ install(session)
session.run("landlab", "--help")
session.run("landlab", "--version")
session.run("landlab", "index", "--help")
@@ -189,10 +182,7 @@ def docs_build(session: nox.Session) -> None:
docs_build_api(session)
docs_build_notebook_index(session)
- if session.virtualenv.venv_backend != "none":
- session.install("-r", PATH["requirements"] / "docs.txt")
-
- check_package_versions(session, files=["required.txt", "docs.txt"])
+ session.install("-r", PATH["requirements"] / "docs.txt")
PATH["build"].mkdir(exist_ok=True)
session.run(
@@ -207,6 +197,49 @@ def docs_build(session: nox.Session) -> None:
session.log(f"generated docs at {PATH['build'] / 'html'!s}")
+@nox.session(name="docs-check-links")
+def docs_check_links(session: nox.Session) -> None:
+ """Check for working links in the docs."""
+ docs_build_api(session)
+ docs_build_notebook_index(session)
+
+ session.install("-r", PATH["requirements"] / "docs.txt")
+
+ PATH["build"].mkdir(exist_ok=True)
+ session.run(
+ "sphinx-build",
+ *("-j", "auto"),
+ *("-b", "linkcheck"),
+ "--keep-going",
+ PATH["docs"] / "source",
+ PATH["build"] / "html",
+ success_codes=(0, 1),
+ )
+
+ output_json = PATH["build"] / "html" / "output.json"
+
+ broken_links = [
+ f"{entry['filename']}:{entry['lineno']}:{entry['uri']}"
+ for entry in load_linkcheck_output(output_json)
+ if entry["status"] == "broken" and not entry["info"].startswith("403")
+ ]
+
+ if broken_links:
+ print("\n".join(sorted(broken_links)))
+ session.error(
+ f"{len(broken_links)} broken links were found."
+ f" see {output_json} for a complete log"
+ )
+ else:
+ session.log("no broken links were found")
+
+
+def load_linkcheck_output(filepath):
+ with open(filepath) as stream:
+ entries = [json.loads(line) for line in stream.readlines()]
+ return entries
+
+
@nox.session(name="docs-build-api")
def docs_build_api(session: nox.Session) -> None:
docs_dir = PATH["docs"] / "source"
@@ -484,17 +517,21 @@ def list_wheels(session):
@nox.session(name="list-ci-matrix")
def list_ci_matrix(session):
+ """Create a matrix entry for a gha workflow that builds wheels"""
+
def _os_from_wheel(name):
if "linux" in name:
- return "linux"
+ return "ubuntu-" + ("24.04" if name.endswith("x86_64") else "24.04-arm")
elif "macos" in name:
- return "macos"
+ return "macos-" + ("13" if name.endswith("x86_64") else "14")
elif "win" in name:
- return "windows"
+ return "windows-2022"
- for wheel in _get_wheels(session):
- print(f"- cibw-only: {wheel}")
- print(f" os: {_os_from_wheel(wheel)}")
+ include_lines = [
+ f"- {{ os: {_os_from_wheel(wheel)}, cibw-only: {wheel} }}"
+ for wheel in _get_wheels(session)
+ ]
+ print("\n".join(sorted(include_lines)))
def _get_wheels(session):
diff --git a/pyproject.toml b/pyproject.toml
index 58d2084875..e28d7d13b5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -28,9 +28,9 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Cython",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
+ "Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Scientific/Engineering :: Physics",
]
@@ -56,17 +56,16 @@ text = "MIT"
[project.urls]
homepage = "https://github.com/landlab"
-documentation = "https://landlab.readthedocs.io"
+documentation = "https://landlab.csdms.io"
repository = "https://github.com/landlab"
changelog = "https://github.com/landlab/landlab/blob/develop/CHANGES.md"
[project.optional-dependencies]
dev = ["nox"]
testing = [
- "coveralls",
+ "coverage",
"hypothesis",
"pytest",
- "pytest-cov",
"pytest-datadir",
"pytest-xdist",
]
@@ -126,6 +125,7 @@ doctest_optionflags = [
]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
+ "richdem: marks tests that use richdem (deselect with '-m \"not richdem\"')",
"notebook: marks tests as notebook (deselect with '-m \"not notebook\"')"
]
diff --git a/requirements-testing.in b/requirements-testing.in
index a07ad8fc3c..de017910ad 100644
--- a/requirements-testing.in
+++ b/requirements-testing.in
@@ -1,10 +1,8 @@
# Requirements extracted from pyproject.toml
# [project.optional-dependencies] testing
-coveralls
+coverage
flaky
hypothesis
pytest
-pytest-benchmark
-pytest-cov
pytest-datadir
pytest-xdist
diff --git a/requirements/docs.txt b/requirements/docs.txt
index 1dada383b5..d0ff5255a0 100644
--- a/requirements/docs.txt
+++ b/requirements/docs.txt
@@ -1,13 +1,12 @@
-furo==2023.9.10
-ipython==8.17.1
-myst-parser==2.0.0
-nbsphinx==0.9.3
-numpy==2.0.0
-pandoc==2.3
+furo==2024.8.6
+ipython==8.29.0
+myst-parser==4.0.0
+nbsphinx==0.9.5
+numpy==2.1.3
sphinx-copybutton==0.5.2
sphinx-inline-tabs==2023.4.21
sphinx-jinja==2.0.2
-sphinx==7.2.6
-sphinxcontrib-towncrier==0.3.2a0
-tomli==2.0.1
+sphinx==8.1.3
+sphinx_design==0.6.1
+sphinxcontrib-towncrier==0.4.0a0
towncrier==23.11.0
diff --git a/requirements/notebooks.txt b/requirements/notebooks.txt
index c1486f5b79..a4eaf3ee6c 100644
--- a/requirements/notebooks.txt
+++ b/requirements/notebooks.txt
@@ -1,5 +1,5 @@
-bmi-topography==0.8.2
+bmi-topography==0.8.3
dask[array]==2024.6.2
-holoviews==1.18.0
-jupyter==1.0.0
-mesa==2.1.2
+holoviews==1.20.0
+jupyter==1.1.1
+mesa[network]==3.0.3
diff --git a/requirements/required.txt b/requirements/required.txt
index 1259c0c358..e949da4665 100644
--- a/requirements/required.txt
+++ b/requirements/required.txt
@@ -1,12 +1,12 @@
bmipy==2.0.1
importlib-resources==6.4.0; python_version < '3.12'
-matplotlib==3.9.0
-netcdf4==1.7.1.post1
-numpy==2.0.0
-pandas==2.2.2
+matplotlib==3.10.0
+netcdf4==1.7.2
+numpy==2.2.3
+pandas==2.2.3
pyshp==2.3.1
-pyyaml==6.0.1
-rich-click==1.7.0
-scipy==1.14.0
-statsmodels==0.14.0
-xarray==2024.6.0
+pyyaml==6.0.2
+rich-click==1.8.5
+scipy==1.15.1
+statsmodels==0.14.4
+xarray==2025.1.2
diff --git a/requirements/testing.txt b/requirements/testing.txt
index b0a966561b..7028fb02e0 100644
--- a/requirements/testing.txt
+++ b/requirements/testing.txt
@@ -1,8 +1,6 @@
-coveralls==3.3.1
+coverage==7.6.12
flaky==3.7.0
-hypothesis==6.88.1
-pytest==7.4.3
-pytest-benchmark==4.0.0
-pytest-cov==4.1.0
+hypothesis==6.125.3
+pytest==8.0.1
pytest-datadir==1.5.0
-pytest-xdist==3.3.1
+pytest-xdist==3.5.0
diff --git a/src/landlab/__init__.py b/src/landlab/__init__.py
index 91bb5874d5..a1d4e8df28 100644
--- a/src/landlab/__init__.py
+++ b/src/landlab/__init__.py
@@ -6,7 +6,7 @@
:Authors: Greg Tucker, Nicole Gasparini, Erkan Istanbulluoglu, Daniel Hobley,
Sai Nudurupati, Jordan Adams, Eric Hutton, Katherine Barnhart, Margaux
Mouchene, Nathon Lyons
-:URL: https://landlab.readthedocs.io/en/release/
+:URL: https://landlab.csdms.io/
:License: MIT
"""
from landlab._registry import registry
diff --git a/src/landlab/bmi/bmi_bridge.py b/src/landlab/bmi/bmi_bridge.py
index 239fa931b1..d0c664d717 100644
--- a/src/landlab/bmi/bmi_bridge.py
+++ b/src/landlab/bmi/bmi_bridge.py
@@ -5,7 +5,7 @@
.. autosummary::
- ~landlab.bmi.bmi_bridge.wrap_as_bmi
+ ~wrap_as_bmi
.. sectionauthor:: Eric Hutton
"""
diff --git a/src/landlab/bmi/standard_names.py b/src/landlab/bmi/standard_names.py
index 1aaba4f205..b8e8ea3c0c 100644
--- a/src/landlab/bmi/standard_names.py
+++ b/src/landlab/bmi/standard_names.py
@@ -31,9 +31,6 @@
"lithosphere_surface__elevation_increment": (
"lithosphere_top_surface__increment_of_elevation"
),
- "lithosphere_surface__elevation_increment": (
- "lithosphere_top_surface__increment_of_elevation"
- ),
"plant__age": "plant__age",
"plant__live_index": None,
"radiation__incoming_shortwave_flux": (
diff --git a/src/landlab/components/__init__.py b/src/landlab/components/__init__.py
index 87a734b70d..90b264c1d6 100644
--- a/src/landlab/components/__init__.py
+++ b/src/landlab/components/__init__.py
@@ -4,6 +4,7 @@
from .carbonate import CarbonateProducer
from .chi_index import ChiFinder
from .concentration_tracker import ConcentrationTrackerForDiffusion
+from .concentration_tracker import ConcentrationTrackerForSpace
from .depression_finder import DepressionFinderAndRouter
from .depth_dependent_diffusion import DepthDependentDiffuser
from .depth_dependent_taylor_soil_creep import DepthDependentTaylorDiffuser
@@ -71,6 +72,7 @@
from .profiler import Profiler
from .profiler import TrickleDownProfiler
from .radiation import Radiation
+from .river_flow_dynamics import RiverFlowDynamics
from .sink_fill import SinkFiller
from .sink_fill import SinkFillerBarnes
from .soil_moisture import SoilInfiltrationGreenAmpt
@@ -102,6 +104,7 @@
ChannelProfiler,
ChiFinder,
ConcentrationTrackerForDiffusion,
+ ConcentrationTrackerForSpace,
DepressionFinderAndRouter,
DepthDependentDiffuser,
DepthDependentTaylorDiffuser,
@@ -153,6 +156,7 @@
PrecipitationDistribution,
Profiler,
Radiation,
+ RiverFlowDynamics,
SedDepEroder,
SedimentPulserAtLinks,
SedimentPulserEachParcel,
diff --git a/src/landlab/components/concentration_tracker/__init__.py b/src/landlab/components/concentration_tracker/__init__.py
index 1e60a69fe9..1ef2f1856b 100644
--- a/src/landlab/components/concentration_tracker/__init__.py
+++ b/src/landlab/components/concentration_tracker/__init__.py
@@ -1,14 +1,7 @@
-"""
-Created on Tue Jun 6 15:21:55 2023
-
-@author: LaurentRoberge
-"""
-
from .concentration_tracker_for_diffusion import ConcentrationTrackerForDiffusion
-
-# from .concentration_tracker_for_space import ConcentrationTrackerForSpace
+from .concentration_tracker_for_space import ConcentrationTrackerForSpace
__all__ = [
"ConcentrationTrackerForDiffusion",
- # "ConcentrationTrackerForSpace",
+ "ConcentrationTrackerForSpace",
]
diff --git a/src/landlab/components/concentration_tracker/concentration_tracker_for_space.py b/src/landlab/components/concentration_tracker/concentration_tracker_for_space.py
new file mode 100644
index 0000000000..8482888ee0
--- /dev/null
+++ b/src/landlab/components/concentration_tracker/concentration_tracker_for_space.py
@@ -0,0 +1,547 @@
+"""
+Created on Fri Jun 16 15:06:50 2023
+
+@author: LaurentRoberge
+"""
+
+import numpy as np
+
+from landlab import Component
+from landlab import NodeStatus
+from landlab.utils.return_array import return_array_at_node
+
+
+class ConcentrationTrackerForSpace(Component):
+ """This component tracks the concentration of any user-defined property of
+ sediment using a mass balance approach in which concentration :math:`C_s`
+ is calculated as:
+
+ .. math::
+
+ ∂C_sH/∂t = C_s_w*D_s_w + C_s*E_s
+
+ where :math:`H` is sediment depth, :math:`C_s_w` is concentration in
+ sediment suspended in the water column, :math:`D_s_w` is volumetric
+ depositional flux of sediment from the water column per unit bed area, and
+ :math:`E_s` is volumetric erosional flux of sediment from the bed per unit
+ bed area.
+
+ .. note::
+
+ This component requires the "sediment__outflux", "bedrock__erosion_flux"
+ "sediment__erosion_flux", and "sediment__deposition_flux" fields
+ calculated by the :class:`~.SpaceLargeScaleEroder` component. This
+ component does not use the typical run_one_step(dt) method. Instead,
+ a start_tracking() method is implemented immediately before every
+ :class:`~.SpaceLargeScaleEroder` step and a stop_tracking(dt) method
+ immediately after every :class:`~.SpaceLargeScaleEroder` step.
+ See the docstring examples below.
+
+ The required inputs "phi", "fraction_fines", and "settling_velocity"
+ must have the same value as those used for the instance of
+ :class:`~.SpaceLargeScaleEroder`.
+
+ Examples
+ --------
+
+ A 1-D stream channel:
+
+ >>> import numpy as np
+ >>> from landlab import NodeStatus, RasterModelGrid
+ >>> from landlab.components import PriorityFloodFlowRouter
+ >>> from landlab.components import SpaceLargeScaleEroder
+ >>> from landlab.components import ConcentrationTrackerForSpace
+
+ >>> mg = RasterModelGrid((3, 5), xy_spacing=10.0)
+
+ >>> mg.set_status_at_node_on_edges(
+ ... right=NodeStatus.CLOSED,
+ ... top=NodeStatus.CLOSED,
+ ... left=NodeStatus.CLOSED,
+ ... bottom=NodeStatus.CLOSED,
+ ... )
+ >>> mg.status_at_node[5] = mg.BC_NODE_IS_FIXED_VALUE
+ >>> mg.status_at_node.reshape(mg.shape)
+ array([[4, 4, 4, 4, 4],
+ [1, 0, 0, 0, 4],
+ [4, 4, 4, 4, 4]], dtype=uint8)
+
+ >>> mg.at_node["sediment_property__concentration"] = [
+ ... [0.0, 0.0, 0.0, 0.0, 0.0],
+ ... [0.0, 0.0, 0.0, 1.0, 0.0],
+ ... [0.0, 0.0, 0.0, 0.0, 0.0],
+ ... ]
+ >>> mg.at_node["soil__depth"] = [
+ ... [1.0, 1.0, 1.0, 1.0, 1.0],
+ ... [1.0, 1.0, 1.0, 1.0, 1.0],
+ ... [1.0, 1.0, 1.0, 1.0, 1.0],
+ ... ]
+ >>> mg.at_node["bedrock__elevation"] = mg.node_x / 100
+ >>> mg.at_node["topographic__elevation"] = (
+ ... mg.at_node["soil__depth"] + mg.at_node["bedrock__elevation"]
+ ... )
+
+ >>> fr = PriorityFloodFlowRouter(mg)
+ >>> fr.run_one_step()
+ >>> sp = SpaceLargeScaleEroder(mg, phi=0, F_f=0, v_s=1)
+ >>> ct = ConcentrationTrackerForSpace(
+ ... mg,
+ ... phi=0,
+ ... fraction_fines=0,
+ ... settling_velocity=1,
+ ... )
+
+ >>> for i in range(40):
+ ... fr.run_one_step()
+ ... ct.start_tracking()
+ ... sp.run_one_step(10.0)
+ ... ct.stop_tracking(10.0)
+ ...
+
+ Erosion has lowered the topography and reduced channel bed sediment depth.
+ >>> np.allclose(
+ ... mg.at_node["topographic__elevation"][mg.core_nodes],
+ ... np.array([1.00292211, 1.00902572, 1.0258774]),
+ ... )
+ True
+ >>> np.allclose(
+ ... mg.at_node["soil__depth"][mg.core_nodes],
+ ... np.array([0.90294696, 0.80909071, 0.72601329]),
+ ... )
+ True
+
+ Some high-concentration sediment has been transported from upstream to be
+ deposited on the channel bed further downstream.
+ >>> np.allclose(
+ ... mg.at_node["sediment_property__concentration"][mg.core_nodes],
+ ... np.array([0.0496547, 0.0997232, 0.9999151]),
+ ... )
+ True
+
+
+ Now, a 2-D landscape with stream channels. All boundaries are closed except
+ for Node 0, which is the outlet of the catchment.
+
+ >>> mg = RasterModelGrid((6, 6), xy_spacing=10.0)
+
+ >>> mg.set_status_at_node_on_edges(
+ ... right=NodeStatus.CLOSED,
+ ... top=NodeStatus.CLOSED,
+ ... left=NodeStatus.CLOSED,
+ ... bottom=NodeStatus.CLOSED,
+ ... )
+ >>> mg.status_at_node[0] = mg.BC_NODE_IS_FIXED_VALUE
+ >>> mg.status_at_node.reshape(mg.shape)
+ array([[4, 4, 4, 4, 4, 4],
+ [4, 0, 0, 0, 0, 4],
+ [4, 0, 0, 0, 0, 4],
+ [4, 0, 0, 0, 0, 4],
+ [4, 0, 0, 0, 0, 4],
+ [1, 4, 4, 4, 4, 4]], dtype=uint8)
+
+
+ >>> mg.at_node["sediment_property__concentration"] = [
+ ... [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
+ ... [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
+ ... [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
+ ... [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
+ ... [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
+ ... [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
+ ... ]
+ >>> mg.at_node["soil__depth"] = [
+ ... [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
+ ... [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
+ ... [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
+ ... [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
+ ... [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
+ ... [0.0, 1.0, 1.0, 1.0, 1.0, 1.0],
+ ... ]
+
+ # Add noise to the bedrock to create some topographic structure.
+ >>> np.random.seed(5)
+ >>> mg.add_zeros("bedrock__elevation", at="node")
+ >>> mg.at_node["bedrock__elevation"] += np.random.rand(mg.number_of_nodes) / 100
+ >>> mg.at_node["bedrock__elevation"][0] = 0
+
+ >>> mg.at_node["topographic__elevation"] = (
+ ... mg.at_node["soil__depth"] + mg.at_node["bedrock__elevation"]
+ ... )
+
+ # Instantiate components.
+ >>> fr = PriorityFloodFlowRouter(mg)
+ >>> fr.run_one_step()
+ >>> sp = SpaceLargeScaleEroder(mg, phi=0, F_f=0, v_s=1)
+ >>> ct = ConcentrationTrackerForSpace(
+ ... mg,
+ ... phi=0,
+ ... fraction_fines=0,
+ ... settling_velocity=1,
+ ... )
+
+ # Run SPACE for 1,000 years to generate a fluvial network.
+ >>> for i in range(1000):
+ ... mg.at_node["bedrock__elevation"][mg.core_nodes] += 0.001
+ ... mg.at_node["topographic__elevation"][:] = (
+ ... mg.at_node["soil__depth"] + mg.at_node["bedrock__elevation"]
+ ... )
+ ... fr.run_one_step()
+ ... sp.run_one_step(1.0)
+ ...
+
+ # Set high concentration at a headwater node to trace sediment downstream.
+ >>> mg.at_node["sediment_property__concentration"][22] += 1
+
+ >>> for i in range(100):
+ ... mg.at_node["bedrock__elevation"][mg.core_nodes] += 0.001
+ ... mg.at_node["topographic__elevation"][:] = (
+ ... mg.at_node["soil__depth"] + mg.at_node["bedrock__elevation"]
+ ... )
+ ... fr.run_one_step()
+ ... ct.start_tracking()
+ ... sp.run_one_step(1.0)
+ ... ct.stop_tracking(1.0)
+ ...
+
+ Some high-concentration sediment has been transported from the headwaters
+ to be deposited on the channel bed further downstream. We can trace this
+ sediment and see where the channel lies within the landscape.
+ >>> np.allclose(
+ ... mg.at_node["sediment_property__concentration"][mg.core_nodes],
+ ... np.array(
+ ... [
+ ... [0.0288311, 0.0447778, 0.0, 0.0],
+ ... [0.0, 0.0, 0.0598574, 0.0],
+ ... [0.0, 0.0, 0.0, 0.9548471],
+ ... [0.0, 0.0, 0.0, 0.0],
+ ... ]
+ ... ).flatten(),
+ ... )
+ True
+
+ References
+ ----------
+ **Required Software Citation(s) Specific to this Component**
+
+ CITATION
+
+ """
+
+ _name = "ConcentrationTrackerForSpace"
+
+ _unit_agnostic = True
+
+ _cite_as = """
+ CITATION
+ """
+
+ _info = {
+ "soil__depth": {
+ "dtype": float,
+ "intent": "in",
+ "optional": False,
+ "units": "m",
+ "mapping": "node",
+ "doc": "Depth of soil or weathered bedrock",
+ },
+ "sediment__outflux": {
+ "dtype": float,
+ "intent": "in",
+ "optional": False,
+ "units": "m^3/yr",
+ "mapping": "node",
+ "doc": "Sediment flux (volume per unit time of sediment leaving each node)",
+ },
+ "bedrock__erosion_flux": {
+ "dtype": float,
+ "intent": "in",
+ "optional": False,
+ "units": "m/yr",
+ "mapping": "node",
+ "doc": (
+ "Bedrock erosion flux from bedrock to water column (depth eroded per"
+ " unit time)"
+ ),
+ },
+ "sediment__erosion_flux": {
+ "dtype": float,
+ "intent": "in",
+ "optional": False,
+ "units": "m/yr",
+ "mapping": "node",
+ "doc": (
+ "Sediment erosion flux from bed to water column (depth eroded per"
+ " unit time)"
+ ),
+ },
+ "sediment__deposition_flux": {
+ "dtype": float,
+ "intent": "in",
+ "optional": False,
+ "units": "m/yr",
+ "mapping": "node",
+ "doc": (
+ "Sediment deposition flux from water column to bed (depth deposited"
+ " per unit time)"
+ ),
+ },
+ "topographic__elevation": {
+ "dtype": float,
+ "intent": "in",
+ "optional": False,
+ "units": "m",
+ "mapping": "node",
+ "doc": "Land surface topographic elevation",
+ },
+ "sediment_property__concentration": {
+ "dtype": float,
+ "intent": "out",
+ "optional": False,
+ "units": "-/m^3",
+ "mapping": "node",
+ "doc": "Mass concentration of property per unit volume of sediment",
+ },
+ "bedrock_property__concentration": {
+ "dtype": float,
+ "intent": "out",
+ "optional": False,
+ "units": "-/m^3",
+ "mapping": "node",
+ "doc": "Mass concentration of property per unit volume of bedrock",
+ },
+ }
+
+ def __init__(
+ self,
+ grid,
+ phi: float | None = None,
+ fraction_fines: float | None = None,
+ settling_velocity: float | None = None,
+ concentration_initial=0,
+ concentration_in_bedrock=0,
+ ):
+ """
+ Parameters
+ ----------
+ grid: ModelGrid
+ Landlab ModelGrid object
+ phi: float
+ Sediment porosity, [-]
+ fraction_fines: float
+ Fraction of permanently suspendable fines in bedrock, [-].
+ settling_velocity: float
+ Net effective settling velocity for chosen grain size metric, [L/T]
+ concentration_initial: positive float, array, or field name (optional)
+ Initial concentration in soil/sediment, [-/L^3]
+ concentration_in_bedrock: positive float, array, or field name (optional)
+ Concentration in bedrock, [-/L^3]
+ """
+
+ if phi is None:
+ raise ValueError(
+ "`phi` is a required input parameter. "
+ "It must have the same value as the `phi` input "
+ "parameter used for the `SpaceLargeScaleEroder` "
+ "instance to which this component is coupled. "
+ "See the docstring in each component for details."
+ )
+ if fraction_fines is None:
+ raise ValueError(
+ "`fraction_fines` is a required input parameter. "
+ "It must have the same value as the same input "
+ "parameter used for the `SpaceLargeScaleEroder` "
+ "instance to which this component is coupled. "
+ "The parameter is named `F_f` in SpaceLargeScaleEroder. "
+ "See the docstring in each component for details."
+ )
+ if settling_velocity is None:
+ raise ValueError(
+ "`settling_velocity` is a required input parameter. "
+ "It must have the same value as the same input "
+ "parameter used for the `SpaceLargeScaleEroder` "
+ "instance to which this component is coupled. "
+ "It is named `v_s` in SpaceLargeScaleEroder. "
+ "See the docstring in each component for details."
+ )
+
+ super().__init__(grid)
+ # Store grid and parameters
+
+ # use setters for C_init, C_br defined below
+ self.C_init = concentration_initial
+ self.C_br = concentration_in_bedrock
+
+ # get reference to inputs
+ self._phi = phi
+ self._fraction_fines = fraction_fines
+ self._settling_velocity = settling_velocity
+ self._soil__depth = self._grid.at_node["soil__depth"]
+ self._soil__depth_old = self._soil__depth.copy()
+ self._Qs_out = self._grid.at_node["sediment__outflux"]
+
+ # Define variables used for internal calculations
+ self._cell_area = self._grid.cell_area_at_node
+ self._C_sw = np.zeros(self._grid.number_of_nodes)
+ self._QsCsw_in = np.zeros(self._grid.number_of_nodes)
+ self._QsCsw_out = np.zeros(self._grid.number_of_nodes)
+ self._BED_ero_depo_term = np.zeros(self._grid.number_of_nodes)
+
+ # create outputs if necessary and get reference.
+ self.initialize_output_fields()
+
+ # Define concentration field (if all zeros, then add C_init)
+ if np.allclose(self._grid.at_node["sediment_property__concentration"], 0.0):
+ self._grid.at_node["sediment_property__concentration"] += self.C_init
+ self._concentration = self._grid.at_node["sediment_property__concentration"]
+
+ if np.allclose(self._grid.at_node["bedrock_property__concentration"], 0.0):
+ self._grid.at_node["bedrock_property__concentration"] += self.C_br
+ self.C_br = self._grid.at_node["bedrock_property__concentration"]
+
+ if phi >= 1.0:
+ raise ValueError("Porosity must be < 1.0")
+
+ if fraction_fines > 1.0:
+ raise ValueError("Fraction of fines must be <= 1.0")
+
+ if phi < 0.0:
+ raise ValueError("Porosity must be > 0.0")
+
+ if fraction_fines < 0.0:
+ raise ValueError("Fraction of fines must be > 0.0")
+
+ @property
+ def C_init(self):
+ """Initial concentration in soil/sediment (kg/m^3)."""
+ return self._C_init
+
+ @property
+ def C_br(self):
+ """Concentration in bedrock (kg/m^3)."""
+ return self._C_br
+
+ @C_init.setter
+ def C_init(self, new_val):
+ if np.any(new_val < 0.0):
+ raise ValueError("Concentration in sediment cannot be negative")
+ self._C_init = return_array_at_node(self._grid, new_val)
+
+ @C_br.setter
+ def C_br(self, new_val):
+ if np.any(new_val < 0.0):
+ raise ValueError("Concentration in bedrock cannot be negative")
+ self._C_br = return_array_at_node(self._grid, new_val)
+
+ def _copy_old_soil_depth(self):
+ """Store a copy of soil depth. This is used as the old soil depth when
+ calculating changes in concentration.
+ """
+
+ self._soil__depth_old = self._soil__depth.copy()
+
+ def _calc_concentration_watercolumn_and_bed(self, dt):
+ """Calculate change in concentration within sediment transported in
+ the water column and within sediment on the bed for a time period 'dt'.
+
+ Parameters
+ ----------
+
+ dt: float (time)
+ The imposed timestep.
+ """
+ # Define values generated by SPACE/SpaceLargeScaleEroder
+ flow_receivers = self._grid.at_node["flow__receiver_node"]
+ q = self._grid.at_node["surface_water__discharge"]
+ Er = self._grid.at_node["bedrock__erosion_flux"]
+ Es = self._grid.at_node["sediment__erosion_flux"]
+ D_sw = self._grid.at_node["sediment__deposition_flux"]
+
+ # Calculate portions of equation that have soil depth as denominator
+ is_soil = self._soil__depth > 0.0
+
+ old_depth_over_new = np.divide(
+ self._soil__depth_old, self._soil__depth, where=is_soil
+ )
+ old_depth_over_new[~is_soil] = 0.0
+
+ dt_over_depth = np.divide(dt, self._soil__depth, where=is_soil)
+ dt_over_depth[~is_soil] = 0.0
+
+ # Calculate mass balance terms that don't need downstream iteration
+ WC_Es_term = Es * self._cell_area
+ WC_Er_term = (1 - self._fraction_fines) * Er * self._cell_area
+ WC_denominator_term = np.ones(np.shape(q))
+ WC_denominator_term[q != 0] = (
+ 1 + self._settling_velocity * self._cell_area[q != 0] / q[q != 0]
+ )
+ BED_C_local_term = self._concentration * old_depth_over_new
+
+ # Get stack of node ids from top to bottom of channel network
+ node_status = self._grid.status_at_node
+ stack_flip_ud = np.flipud(self._grid.at_node["flow__upstream_node_order"])
+ # Select core nodes where qs >0
+ stack_flip_ud_sel = stack_flip_ud[
+ (node_status[stack_flip_ud] == NodeStatus.CORE) & (q[stack_flip_ud] > 0.0)
+ ]
+
+ # zero out array values that were updated in the old stack
+ self._C_sw[:] = 0
+ self._QsCsw_in[:] = 0
+ self._BED_ero_depo_term[:] = 0
+
+ # Iterate concentration calc (first BED, then WC) at each node
+ for node_id in stack_flip_ud_sel:
+ # Calculate QsCsw_out (i.e., QsCs in the water column)
+ self._QsCsw_out[node_id] = (
+ self._QsCsw_in[node_id]
+ + self._concentration[node_id] * WC_Es_term[node_id]
+ + self.C_br[node_id] * WC_Er_term[node_id]
+ ) / WC_denominator_term[node_id]
+
+ # Send QsCsw_out values to flow receiver nodes
+ self._QsCsw_in[flow_receivers[node_id]] += self._QsCsw_out[node_id]
+
+ # Divide QsCsw_out (from above) by Qs_out to get C_sw
+ if self._Qs_out[node_id] > 0:
+ self._C_sw[node_id] = self._QsCsw_out[node_id] / self._Qs_out[node_id]
+ else:
+ self._C_sw[node_id] = 0.0
+
+ # Calculate BED erosion/deposition term (requires C_sw from above)
+ self._BED_ero_depo_term[node_id] = (
+ self._C_sw[node_id] * D_sw[node_id]
+ - self._concentration[node_id] * Es[node_id]
+ ) / (1 - self._phi)
+
+ # Calculate BED concentration
+ self._concentration[node_id] = (
+ BED_C_local_term[node_id]
+ + dt_over_depth[node_id] * self._BED_ero_depo_term[node_id]
+ )
+
+ self._concentration[~is_soil] = 0.0
+
+ def start_tracking(self):
+ """Stores values necessary for calculating changes in concentration.
+ This method must be called prior to running the sediment flux component
+ that changes physical properties of bedrock, soil, and/or topography.
+ """
+
+ self._copy_old_soil_depth()
+
+ def stop_tracking(self, dt):
+ """Calculate changes in concentration that have occurred in the timestep
+ since tracking was started. This method must be called after running the
+ sediment flux component that changes physical properties of bedrock,
+ soil, and/or topography.
+
+ Parameters
+ ----------
+ dt: float (time)
+ The imposed timestep.
+ """
+
+ self._calc_concentration_watercolumn_and_bed(dt)
+
+ def run_one_step(self):
+ """run_one_step is not implemented for this component."""
+ raise NotImplementedError("run_one_step()")
diff --git a/src/landlab/components/depth_dependent_taylor_soil_creep/hillslope_depth_dependent_taylor_flux.py b/src/landlab/components/depth_dependent_taylor_soil_creep/hillslope_depth_dependent_taylor_flux.py
index aa07281377..3828a6451c 100644
--- a/src/landlab/components/depth_dependent_taylor_soil_creep/hillslope_depth_dependent_taylor_flux.py
+++ b/src/landlab/components/depth_dependent_taylor_soil_creep/hillslope_depth_dependent_taylor_flux.py
@@ -416,9 +416,9 @@ def soilflux(self, dt):
)
raise RuntimeError(message)
# Calculate De Max
- De_max = self._K * (courant_slope_term)
+ de_max = self._K * self._soil_transport_decay_depth * courant_slope_term
# Calculate longest stable timestep
- self._dt_max = self._courant_factor * (self._shortest_link**2) / De_max
+ self._dt_max = self._courant_factor * self._shortest_link**2 / de_max
# Test for the Courant condition and print warning if user intended
# for it to be printed.
diff --git a/src/landlab/components/flow_accum/lossy_flow_accumulator.py b/src/landlab/components/flow_accum/lossy_flow_accumulator.py
index cf365ffc00..642586fab4 100644
--- a/src/landlab/components/flow_accum/lossy_flow_accumulator.py
+++ b/src/landlab/components/flow_accum/lossy_flow_accumulator.py
@@ -4,15 +4,12 @@
DEJH, late 2018
"""
-import sys
+from inspect import signature
from landlab.components.flow_accum import FlowAccumulator
from landlab.components.flow_accum import flow_accum_bw
from landlab.components.flow_accum import flow_accum_to_n
-if sys.version_info[0] >= 3:
- from inspect import signature
-
class LossyFlowAccumulator(FlowAccumulator):
"""Component to calculate drainage area and accumulate flow, while
@@ -393,11 +390,9 @@ def __init__(
)
if loss_function is not None:
- if sys.version_info[0] >= 3:
- sig = signature(loss_function)
- num_params = len(sig.parameters)
- else: # Python 2
- num_params = loss_function.func_code.co_argcount
+ sig = signature(loss_function)
+ num_params = len(sig.parameters)
+
# save the func for loss, and do a quick test on its inputs:
if num_params == 1:
# check the func takes a single value and turns it into a new
diff --git a/src/landlab/components/groundwater/README.md b/src/landlab/components/groundwater/README.md
index ce86c970da..269b71be88 100644
--- a/src/landlab/components/groundwater/README.md
+++ b/src/landlab/components/groundwater/README.md
@@ -9,28 +9,28 @@ summarize installation, documentation, tutorials, tests, and getting help with
this component.
As this component lives within the larger Landlab package ecosystem, most of the
-information below provides links into the [main Landlab documentation](https://landlab.readthedocs.io/).
+information below provides links into the [main Landlab documentation](https://landlab.csdms.io/).
### Installation
To use this component, you will need to install Landlab. Two options for
installation are available:
-[a pre-packaged binary](https://landlab.readthedocs.io/en/master/install/index.html)
+[a pre-packaged binary](https://landlab.csdms.io/installation.html)
distributed through PyPI or conda-forge and a
-[source code installation](https://landlab.readthedocs.io/en/master/development/install/index.html#developer-install).
+[source code installation](https://landlab.csdms.io/install/).
-The dependencies of the Landlab package are described [here](https://landlab.readthedocs.io/en/master/development/practices/dependencies.html).
+The dependencies of the Landlab package are described [here](https://landlab.csdms.io/development/practices/dependencies.html).
### Documentation
The documentation specific to this component is housed within the Landlab
documentation. There are two pages in the documentation that are most relevant
to this component:
-- [The component API](https://landlab.readthedocs.io/en/master/reference/components/groundwater.html).
-- [A page](https://landlab.readthedocs.io/en/master/reference/components/dupuit_theory.html#dupuit-theory)
+- [The component API](https://landlab.csdms.io/generated/api/landlab.components.groundwater.dupuit_percolator.html).
+- [A page](https://landlab.csdms.io/user_guide/dupuit_theory.html)
describing the theory and numerical implementation of this component.
If you are new to Landlab and components, we recommend that you also look at the
-[User Guide](https://landlab.readthedocs.io/en/master/user_guide/index.html),
-in particular, the page on the [model grid](https://landlab.readthedocs.io/en/master/user_guide/grid.html), and [components](https://landlab.readthedocs.io/en/master/user_guide/components.html).
+[User Guide](https://landlab.csdms.io/user_guide/),
+in particular, the page on the [model grid](https://landlab.csdms.io/user_guide/grid.html), and [components](https://landlab.csdms.io/user_guide/components.html).
### Tutorials
There is a [Jupyter notebook in the Landlab Tutorials repository](https://mybinder.org/v2/gh/landlab/landlab/release?filepath=notebooks/tutorials/groundwater/groundwater_flow.ipynb)
@@ -44,10 +44,10 @@ A directory of all Landlab notebooks can be found (as a binder instance) [here](
Along with the rest of the Landlab package, this component uses
[`pytest`](https://docs.pytest.org/en/latest/)
to discover and run its tests. General information about running the Landlab
-tests can be found [here](https://landlab.readthedocs.io/en/master/development/install/test.html#testing).
+tests can be found [here](https://landlab.csdms.io/development/practices/writing_tests.html).
If you want to run the tests locally, you will need to use a
-[source code installation](https://landlab.readthedocs.io/en/master/development/install/index.html#developer-install).
+[source code installation](https://landlab.csdms.io/install/).
### Getting Help
If you have any questions, comments, issues, or bugs related to this submodule,
diff --git a/src/landlab/components/network_sediment_transporter/README.md b/src/landlab/components/network_sediment_transporter/README.md
index 075789a0a5..58975e504a 100644
--- a/src/landlab/components/network_sediment_transporter/README.md
+++ b/src/landlab/components/network_sediment_transporter/README.md
@@ -4,11 +4,11 @@ The NetworkSedimentTransporter is a lagrangian model for sediment transport on a
## Documentation and installation
-Landlab documentation is hosted on this [ReadTheDocs page](https://landlab.readthedocs.io/en/release),
+Landlab documentation is hosted on this [ReadTheDocs page](https://landlab.csdms.io/),
including instructions to install Landlab. NetworkSedimentTransporter is installed with
Landlab.
-NetworkSedimentTransporter documentation is located [here](https://landlab.readthedocs.io/en/master/reference/components/network_sediment_transporter.html).
+NetworkSedimentTransporter documentation is located [here](https://landlab.csdms.io/generated/api/landlab.components.network_sediment_transporter.network_sediment_transporter.html).
## NetworkSedimentTransporter tutorial
diff --git a/src/landlab/components/network_sediment_transporter/sediment_pulser_at_links.py b/src/landlab/components/network_sediment_transporter/sediment_pulser_at_links.py
index 04c60645bf..05bec65cbc 100644
--- a/src/landlab/components/network_sediment_transporter/sediment_pulser_at_links.py
+++ b/src/landlab/components/network_sediment_transporter/sediment_pulser_at_links.py
@@ -1,343 +1,343 @@
-import numpy as np
-
-from landlab.components.network_sediment_transporter.sediment_pulser_base import (
- SedimentPulserBase,
-)
-from landlab.data_record.data_record import DataRecord
-
-_OUT_OF_NETWORK = -2
-
-
-class SedimentPulserAtLinks(SedimentPulserBase):
- """Send a pulse of parcels to specific links in a channel network
-
- :class:`~.SedimentPulserAtLinks` is instantiated by specifying the
- :class:`~.NetworkModelGrid` it will pulse the parcels into and the time(s) when
- a pulse is allowed to occur. It inherits attributes and functions from the
- :class:`~.SedimentPulserBase`.
-
- :class:`~.SedimentPulserAtLinks` is run (adds parcels to ``DataRecord``) by
- calling the instance with a list of links and a list of the number of parcels
- added to each link.
-
- If parcel attributes are constant with time and uniform
- across the basin, these constant-uniform-attributes can be defined
- when :class:`~.SedimentPulserAtLinks` is instantiated. If parcel attributes vary
- with location and time, the user specifies the varying parcel attributes
- each time the instance is called with a list for each attribute of length
- equal to the number of links included in the pulse.
-
-
- .. codeauthor:: Jeff Keck, Allison Pfeiffer, Shelby Ahrendt
- (with help from Eric Hutton and Katy Barnhart)
-
-
- Examples
- --------
- >>> import numpy as np
- >>> from landlab import NetworkModelGrid
-
- Create the network model grid the parcels will be added to.
-
- >>> y_of_node = (0, 100, 200, 200, 300, 400, 400, 125)
- >>> x_of_node = (0, 0, 100, -50, -100, 50, -150, -100)
- >>> nodes_at_link = ((1, 0), (2, 1), (1, 7), (3, 1), (3, 4), (4, 5), (4, 6))
- >>> grid = NetworkModelGrid((y_of_node, x_of_node), nodes_at_link)
- >>> grid.at_link["channel_width"] = np.full(grid.number_of_links, 1.0) # m
- >>> grid.at_link["channel_slope"] = np.full(grid.number_of_links, 0.01) # m / m
- >>> grid.at_link["reach_length"] = np.full(grid.number_of_links, 100.0) # m
-
- Define a function that contains which times a pulse is allowed to occur.
- This function says a pulse can occur at any time
-
- >>> def time_to_pulse(time):
- ... return True
- ...
-
- Instantiate :class:`~.SedimentPulserAtLinks`
-
- >>> make_pulse = SedimentPulserAtLinks(grid, time_to_pulse=time_to_pulse)
-
- Run the instance with inputs for the time, link location and number of
- parcels. Other attributes will use the default values in the base class
-
- >>> time = 11
- >>> links = [2, 6]
- >>> n_parcels_at_link = [2, 3]
- >>> parcels = make_pulse(
- ... time=time, links=links, n_parcels_at_link=n_parcels_at_link
- ... )
-
- Check the element_id of each parcel
-
- >>> print(parcels.dataset["element_id"].values)
- [[2]
- [2]
- [6]
- [6]
- [6]]
- """
-
- _name = "SedimentPulserAtLinks"
-
- _unit_agnostic = False
-
- _info = {} # works with the DataRecord
-
- def __init__(
- self,
- grid,
- time_to_pulse=None,
- parcels=None,
- D50=0.05,
- D84_D50=2.1,
- rho_sediment=2650.0,
- parcel_volume=0.5,
- abrasion_rate=0.0,
- rng=None,
- ):
- """Create :class:`~.SedimentPulserAtLinks`.
-
- Parameters
- ----------
-
- grid : ModelGrid
- landlab :class:`~.ModelGrid` to place sediment parcels on.
- time_to_pulse: function, optional
- The condition when a pulse occurs using the ``_pulse_characteristics``
- method. If not specified, a pulse occurs whenever the instance is run
- parcels: landlab DataRecord
- Tracks parcel location and variables.
- D50: float, optional
- Median grain size [m].
- D84_D50: float, optional
- Ratio of 84th percentile grain size to the median grain size.
- rho_sediment : float, optional
- Sediment grain density [kg / m^3].
- parcel_volume : float
- Parcel volume [m^3]
- abrasion_rate: float
- Volumetric abrasion exponent [1 / m]
- """
- if rng is None:
- rng = np.random.default_rng()
- elif isinstance(rng, int):
- rng = np.random.default_rng(seed=rng)
- self._rng = rng
-
- SedimentPulserBase.__init__(
- self,
- grid,
- parcels=parcels,
- D50=D50,
- D84_D50=D84_D50,
- rho_sediment=rho_sediment,
- parcel_volume=parcel_volume,
- abrasion_rate=abrasion_rate,
- )
-
- # set time_to_pulse to True if not specified
- if time_to_pulse is None:
- self._time_to_pulse = lambda time: True
- else:
- self._time_to_pulse = time_to_pulse
-
- def __call__(
- self,
- time,
- links=None,
- n_parcels_at_link=None,
- D50=None,
- D84_D50=None,
- rho_sediment=None,
- parcel_volume=None,
- abrasion_rate=None,
- ):
- """
- specify the time, link(s) and attributes of pulses added to a
- :class:`~.NetworkModelGrid` at stochastically determined locations within the
- link(s).
-
- Parameters
- ----------
- time : integer or datetime64
- Time that the pulse is occurs.
- links : list of int
- Link ID # that parcels are added to.
- n_parcels_at_link: list of int
- Number of parcels added to each link listed in links
- D50 : list of float, optional
- Median grain size of parcels added to each link listed in links [m].
- D84_D50 : list of float, optional
- Ratio of 84th percentile grain size to the median grain size.
- rho_sediment: list of float, optional
- Density of grains [kg / m^3].
- parcel_volume : list of float, optional
- Volume of each parcel added to link listed in links [m^3].
- abrasion_rate: list of float, optional
- Rate that grain size decreases with distance along channel [mm / km?].
-
- Returns
- -------
- parcels
- :class:`~.DataRecord` containing all information on each individual parcel.
-
- """
-
- # check user provided links and number of parcels sent to each link
- assert (
- links is not None and n_parcels_at_link is not None
- ), "must provide links and number of parcels entered into each link"
-
- links = np.array(links)
- n_parcels_at_link = np.array(n_parcels_at_link)
-
- # any parameters not specified with __Call__ method use default values
- # specified in the base class
- if D50 is None:
- D50 = np.full_like(links, self._D50, dtype=float)
- else:
- D50 = np.array(D50)
-
- if D84_D50 is None:
- D84_D50 = np.full_like(links, self._D84_D50, dtype=float)
- else:
- D84_D50 = np.array(D84_D50)
-
- if rho_sediment is None:
- rho_sediment = np.full_like(links, self._rho_sediment, dtype=float)
- else:
- rho_sediment = np.array(rho_sediment)
-
- if parcel_volume is None:
- parcel_volume = np.full_like(links, self._parcel_volume, dtype=float)
- else:
- parcel_volume = np.array(parcel_volume)
-
- if abrasion_rate is None:
- abrasion_rate = np.full_like(links, self._abrasion_rate, dtype=float)
- else:
- abrasion_rate = np.array(abrasion_rate)
-
- # before running, check that no inputs < 0
- # check for negative inputs
- if (
- np.array([D50, D84_D50, rho_sediment, parcel_volume, abrasion_rate]) < 0
- ).any():
- raise AssertionError("parcel attributes cannot be less than zero")
- # before running, check if time to pulse
- if not self._time_to_pulse(time):
- # if not time to pulse, return the existing parcels
- print("user provided time not a time-to-pulse, parcels have not changed")
-
- return self._parcels
-
- # create items and variables for DataRecord
- variables, items = self._sediment_pulse_stochastic(
- time,
- links,
- n_parcels_at_link,
- parcel_volume,
- D50,
- D84_D50,
- abrasion_rate,
- rho_sediment,
- )
-
- # if DataRecord does not exist, create one
- if self._parcels is None:
- self._parcels = DataRecord(
- self._grid,
- items=items,
- time=[time],
- data_vars=variables,
- dummy_elements={"link": [_OUT_OF_NETWORK]},
- )
- # else, add parcels to existing DataRecrod
- else:
- self._parcels.add_item(time=[time], new_item=items, new_item_spec=variables)
-
- return self._parcels
-
- def _sediment_pulse_stochastic(
- self,
- time,
- links,
- n_parcels_at_link,
- parcel_volume,
- D50,
- D84_D50,
- abrasion_rate,
- rho_sediment,
- ):
- """Convert lists of link ids and link parcel parameters to a dataset
- that describes the network location and attributes of each individual parcel
-
- Returns
- -------
- dict
- Dictionary with keys and data in format for :class:`~.DataRecord`.
-
- """
-
- # Create np array for each paracel attribute. Length of array is equal
- # to the number of parcels
-
- # link id, D50 and volume
- element_id = np.empty(np.sum(n_parcels_at_link), dtype=int)
- grain_size = np.empty(np.sum(n_parcels_at_link))
- volume = np.empty(np.sum(n_parcels_at_link))
- offset = 0
- for link, n_parcels in enumerate(n_parcels_at_link):
- element_id[offset : offset + n_parcels] = links[link]
- grain_size[offset : offset + n_parcels] = self._rng.lognormal(
- np.log(D50[link]), np.log(D84_D50[link]), n_parcels
- )
- volume[offset : offset + n_parcels] = parcel_volume[link] % n_parcels
- offset += n_parcels
- starting_link = element_id.copy()
-
- # abrasion rate and density
- abrasion_rate_L = []
- density_L = []
- for c, ei in enumerate(np.unique(element_id)):
- element_id_subset = element_id[element_id == ei]
- abrasion_rate_L = abrasion_rate_L + list(
- np.full_like(element_id_subset, abrasion_rate[c], dtype=float)
- )
- density_L = density_L + list(
- np.full_like(element_id_subset, rho_sediment[c], dtype=float)
- )
- abrasion_rate = np.array(abrasion_rate_L)
- density = np.array(density_L)
-
- element_id = np.expand_dims(element_id, axis=1)
- grain_size = np.expand_dims(grain_size, axis=1)
- volume = np.expand_dims(volume, axis=1)
-
- # time of arrivial (time instance called)
- time_arrival_in_link = np.full(np.shape(element_id), time, dtype=float)
-
- # link location (distance from link inlet / link length) is stochastically
- # determined
- location_in_link = np.expand_dims(
- self._rng.uniform(size=np.sum(n_parcels_at_link)), axis=1
- )
-
- # All parcels in pulse are in the active layer (1) rather than subsurface (0)
- active_layer = np.ones(np.shape(element_id))
-
- # specify that parcels are in the links of the network model grid
- grid_element = ["link"] * np.size(element_id)
- grid_element = np.expand_dims(grid_element, axis=1)
-
- return {
- "starting_link": (["item_id"], starting_link),
- "abrasion_rate": (["item_id"], abrasion_rate),
- "density": (["item_id"], density),
- "time_arrival_in_link": (["item_id", "time"], time_arrival_in_link),
- "active_layer": (["item_id", "time"], active_layer),
- "location_in_link": (["item_id", "time"], location_in_link),
- "D": (["item_id", "time"], grain_size),
- "volume": (["item_id", "time"], volume),
- }, {"grid_element": grid_element, "element_id": element_id}
+import numpy as np
+
+from landlab.components.network_sediment_transporter.sediment_pulser_base import (
+ SedimentPulserBase,
+)
+from landlab.data_record.data_record import DataRecord
+
+_OUT_OF_NETWORK = -2
+
+
+class SedimentPulserAtLinks(SedimentPulserBase):
+ """Send a pulse of parcels to specific links in a channel network
+
+ :class:`~.SedimentPulserAtLinks` is instantiated by specifying the
+ :class:`~.NetworkModelGrid` it will pulse the parcels into and the time(s) when
+ a pulse is allowed to occur. It inherits attributes and functions from the
+ :class:`~.SedimentPulserBase`.
+
+ :class:`~.SedimentPulserAtLinks` is run (adds parcels to ``DataRecord``) by
+ calling the instance with a list of links and a list of the number of parcels
+ added to each link.
+
+ If parcel attributes are constant with time and uniform
+ across the basin, these constant-uniform-attributes can be defined
+ when :class:`~.SedimentPulserAtLinks` is instantiated. If parcel attributes vary
+ with location and time, the user specifies the varying parcel attributes
+ each time the instance is called with a list for each attribute of length
+ equal to the number of links included in the pulse.
+
+
+ .. codeauthor:: Jeff Keck, Allison Pfeiffer, Shelby Ahrendt
+ (with help from Eric Hutton and Katy Barnhart)
+
+
+ Examples
+ --------
+ >>> import numpy as np
+ >>> from landlab import NetworkModelGrid
+
+ Create the network model grid the parcels will be added to.
+
+ >>> y_of_node = (0, 100, 200, 200, 300, 400, 400, 125)
+ >>> x_of_node = (0, 0, 100, -50, -100, 50, -150, -100)
+ >>> nodes_at_link = ((1, 0), (2, 1), (1, 7), (3, 1), (3, 4), (4, 5), (4, 6))
+ >>> grid = NetworkModelGrid((y_of_node, x_of_node), nodes_at_link)
+ >>> grid.at_link["channel_width"] = np.full(grid.number_of_links, 1.0) # m
+ >>> grid.at_link["channel_slope"] = np.full(grid.number_of_links, 0.01) # m / m
+ >>> grid.at_link["reach_length"] = np.full(grid.number_of_links, 100.0) # m
+
+ Define a function that contains which times a pulse is allowed to occur.
+ This function says a pulse can occur at any time
+
+ >>> def time_to_pulse(time):
+ ... return True
+ ...
+
+ Instantiate :class:`~.SedimentPulserAtLinks`
+
+ >>> make_pulse = SedimentPulserAtLinks(grid, time_to_pulse=time_to_pulse)
+
+ Run the instance with inputs for the time, link location and number of
+ parcels. Other attributes will use the default values in the base class
+
+ >>> time = 11
+ >>> links = [2, 6]
+ >>> n_parcels_at_link = [2, 3]
+ >>> parcels = make_pulse(
+ ... time=time, links=links, n_parcels_at_link=n_parcels_at_link
+ ... )
+
+ Check the element_id of each parcel
+
+ >>> print(parcels.dataset["element_id"].values)
+ [[2]
+ [2]
+ [6]
+ [6]
+ [6]]
+ """
+
+ _name = "SedimentPulserAtLinks"
+
+ _unit_agnostic = False
+
+ _info = {} # works with the DataRecord
+
+ def __init__(
+ self,
+ grid,
+ time_to_pulse=None,
+ parcels=None,
+ D50=0.05,
+ D84_D50=2.1,
+ rho_sediment=2650.0,
+ parcel_volume=0.5,
+ abrasion_rate=0.0,
+ rng=None,
+ ):
+ """Create :class:`~.SedimentPulserAtLinks`.
+
+ Parameters
+ ----------
+
+ grid : ModelGrid
+ landlab :class:`~.ModelGrid` to place sediment parcels on.
+ time_to_pulse: function, optional
+ The condition when a pulse occurs using the ``_pulse_characteristics``
+ method. If not specified, a pulse occurs whenever the instance is run
+ parcels: landlab DataRecord
+ Tracks parcel location and variables.
+ D50: float, optional
+ Median grain size [m].
+ D84_D50: float, optional
+ Ratio of 84th percentile grain size to the median grain size.
+ rho_sediment : float, optional
+ Sediment grain density [kg / m^3].
+ parcel_volume : float
+ Parcel volume [m^3]
+ abrasion_rate: float
+ Volumetric abrasion exponent [1 / m]
+ """
+ if rng is None:
+ rng = np.random.default_rng()
+ elif isinstance(rng, int):
+ rng = np.random.default_rng(seed=rng)
+ self._rng = rng
+
+ SedimentPulserBase.__init__(
+ self,
+ grid,
+ parcels=parcels,
+ D50=D50,
+ D84_D50=D84_D50,
+ rho_sediment=rho_sediment,
+ parcel_volume=parcel_volume,
+ abrasion_rate=abrasion_rate,
+ )
+
+ # set time_to_pulse to True if not specified
+ if time_to_pulse is None:
+ self._time_to_pulse = lambda time: True
+ else:
+ self._time_to_pulse = time_to_pulse
+
+ def __call__(
+ self,
+ time,
+ links=None,
+ n_parcels_at_link=None,
+ D50=None,
+ D84_D50=None,
+ rho_sediment=None,
+ parcel_volume=None,
+ abrasion_rate=None,
+ ):
+ """
+ specify the time, link(s) and attributes of pulses added to a
+ :class:`~.NetworkModelGrid` at stochastically determined locations within the
+ link(s).
+
+ Parameters
+ ----------
+ time : integer or datetime64
+ Time that the pulse is occurs.
+ links : list of int
+ Link ID # that parcels are added to.
+ n_parcels_at_link: list of int
+ Number of parcels added to each link listed in links
+ D50 : list of float, optional
+ Median grain size of parcels added to each link listed in links [m].
+ D84_D50 : list of float, optional
+ Ratio of 84th percentile grain size to the median grain size.
+ rho_sediment: list of float, optional
+ Density of grains [kg / m^3].
+ parcel_volume : list of float, optional
+ Volume of each parcel added to link listed in links [m^3].
+ abrasion_rate: list of float, optional
+ Rate that grain size decreases with distance along channel [mm / km?].
+
+ Returns
+ -------
+ parcels
+ :class:`~.DataRecord` containing all information on each individual parcel.
+
+ """
+
+ # check user provided links and number of parcels sent to each link
+ assert (
+ links is not None and n_parcels_at_link is not None
+ ), "must provide links and number of parcels entered into each link"
+
+ links = np.array(links)
+ n_parcels_at_link = np.array(n_parcels_at_link)
+
+ # any parameters not specified with __Call__ method use default values
+ # specified in the base class
+ if D50 is None:
+ D50 = np.full_like(links, self._D50, dtype=float)
+ else:
+ D50 = np.array(D50)
+
+ if D84_D50 is None:
+ D84_D50 = np.full_like(links, self._D84_D50, dtype=float)
+ else:
+ D84_D50 = np.array(D84_D50)
+
+ if rho_sediment is None:
+ rho_sediment = np.full_like(links, self._rho_sediment, dtype=float)
+ else:
+ rho_sediment = np.array(rho_sediment)
+
+ if parcel_volume is None:
+ parcel_volume = np.full_like(links, self._parcel_volume, dtype=float)
+ else:
+ parcel_volume = np.array(parcel_volume)
+
+ if abrasion_rate is None:
+ abrasion_rate = np.full_like(links, self._abrasion_rate, dtype=float)
+ else:
+ abrasion_rate = np.array(abrasion_rate)
+
+ # before running, check that no inputs < 0
+ # check for negative inputs
+ if (
+ np.array([D50, D84_D50, rho_sediment, parcel_volume, abrasion_rate]) < 0
+ ).any():
+ raise AssertionError("parcel attributes cannot be less than zero")
+ # before running, check if time to pulse
+ if not self._time_to_pulse(time):
+ # if not time to pulse, return the existing parcels
+ print("user provided time not a time-to-pulse, parcels have not changed")
+
+ return self._parcels
+
+ # create items and variables for DataRecord
+ variables, items = self._sediment_pulse_stochastic(
+ time,
+ links,
+ n_parcels_at_link,
+ parcel_volume,
+ D50,
+ D84_D50,
+ abrasion_rate,
+ rho_sediment,
+ )
+
+ # if DataRecord does not exist, create one
+ if self._parcels is None:
+ self._parcels = DataRecord(
+ self._grid,
+ items=items,
+ time=[time],
+ data_vars=variables,
+ dummy_elements={"link": [_OUT_OF_NETWORK]},
+ )
+ # else, add parcels to existing DataRecrod
+ else:
+ self._parcels.add_item(time=[time], new_item=items, new_item_spec=variables)
+
+ return self._parcels
+
+ def _sediment_pulse_stochastic(
+ self,
+ time,
+ links,
+ n_parcels_at_link,
+ parcel_volume,
+ D50,
+ D84_D50,
+ abrasion_rate,
+ rho_sediment,
+ ):
+ """Convert lists of link ids and link parcel parameters to a dataset
+ that describes the network location and attributes of each individual parcel
+
+ Returns
+ -------
+ dict
+ Dictionary with keys and data in format for :class:`~.DataRecord`.
+
+ """
+
+ # Create np array for each paracel attribute. Length of array is equal
+ # to the number of parcels
+
+ # link id, D50 and volume
+ element_id = np.empty(np.sum(n_parcels_at_link), dtype=int)
+ grain_size = np.empty(np.sum(n_parcels_at_link))
+ volume = np.empty(np.sum(n_parcels_at_link))
+ offset = 0
+ for link, n_parcels in enumerate(n_parcels_at_link):
+ element_id[offset : offset + n_parcels] = links[link]
+ grain_size[offset : offset + n_parcels] = self._rng.lognormal(
+ np.log(D50[link]), np.log(D84_D50[link]), n_parcels
+ )
+ volume[offset : offset + n_parcels] = parcel_volume[link] % n_parcels
+ offset += n_parcels
+ starting_link = element_id.copy()
+
+ # abrasion rate and density
+ abrasion_rate_L = []
+ density_L = []
+ for c, ei in enumerate(np.unique(element_id)):
+ element_id_subset = element_id[element_id == ei]
+ abrasion_rate_L = abrasion_rate_L + list(
+ np.full_like(element_id_subset, abrasion_rate[c], dtype=float)
+ )
+ density_L = density_L + list(
+ np.full_like(element_id_subset, rho_sediment[c], dtype=float)
+ )
+ abrasion_rate = np.array(abrasion_rate_L)
+ density = np.array(density_L)
+
+ element_id = np.expand_dims(element_id, axis=1)
+ grain_size = np.expand_dims(grain_size, axis=1)
+ volume = np.expand_dims(volume, axis=1)
+
+ # time of arrivial (time instance called)
+ time_arrival_in_link = np.full(np.shape(element_id), time, dtype=float)
+
+ # link location (distance from link inlet / link length) is stochastically
+ # determined
+ location_in_link = np.expand_dims(
+ self._rng.uniform(size=np.sum(n_parcels_at_link)), axis=1
+ )
+
+ # All parcels in pulse are in the active layer (1) rather than subsurface (0)
+ active_layer = np.ones(np.shape(element_id))
+
+ # specify that parcels are in the links of the network model grid
+ grid_element = ["link"] * np.size(element_id)
+ grid_element = np.expand_dims(grid_element, axis=1)
+
+ return {
+ "starting_link": (["item_id"], starting_link),
+ "abrasion_rate": (["item_id"], abrasion_rate),
+ "density": (["item_id"], density),
+ "time_arrival_in_link": (["item_id", "time"], time_arrival_in_link),
+ "active_layer": (["item_id", "time"], active_layer),
+ "location_in_link": (["item_id", "time"], location_in_link),
+ "D": (["item_id", "time"], grain_size),
+ "volume": (["item_id", "time"], volume),
+ }, {"grid_element": grid_element, "element_id": element_id}
diff --git a/src/landlab/components/network_sediment_transporter/sediment_pulser_base.py b/src/landlab/components/network_sediment_transporter/sediment_pulser_base.py
index b2ef93c6df..7fa46e0d37 100644
--- a/src/landlab/components/network_sediment_transporter/sediment_pulser_base.py
+++ b/src/landlab/components/network_sediment_transporter/sediment_pulser_base.py
@@ -1,88 +1,88 @@
-from landlab.core.model_component import Component
-from landlab.grid.network import NetworkModelGrid
-
-
-class SedimentPulserBase(Component):
- """Base class of :class:`~.SedimentPulserAtLinks` and :class:`~.SedimentPulserEachParcel`.
-
- :class:`~.SedimentPulserAtLinks` and :class:`~.SedimentPulserEachParcel` run the
- landlab :class:`~.DataRecord` :meth:`~.DataRecord.add_item` method on a
- :class:`~.DataRecord` configured for :class:`~.NetworkSedimentTransporter`.
-
-
- .. codeauthor: Jeff Keck, Allison Pfeiffer, Shelby Ahrendt
- (with help from Eric Hutton and Katy Barnhart)
-
- Parameters
- ----------
- grid : ModelGrid
- landlab *ModelGrid* to place sediment parcels on.
- parcels: landlab DataRecord
- Tracks parcel location and variables
- D50: float, optional
- median grain size [m]
- D84_D50: float, optional
- ratio of 84th percentile grain size to the median grain size
- rho_sediment : float, optional
- Sediment grain density [kg / m^3].
- parcel_volume : float, optional
- parcel volume used for all parcels that do not have a specified volume
- abrasion_rate: float, optional
- volumetric abrasion exponent [1/m]
-
-
- Examples
- --------
- >>> import numpy as np
- >>> from landlab import NetworkModelGrid
-
- >>> y_of_node = (0, 100, 200, 200, 300, 400, 400, 125)
- >>> x_of_node = (0, 0, 100, -50, -100, 50, -150, -100)
- >>> nodes_at_link = ((1, 0), (2, 1), (1, 7), (3, 1), (3, 4), (4, 5), (4, 6))
- >>> grid = NetworkModelGrid((y_of_node, x_of_node), nodes_at_link)
- >>> grid.at_link["channel_width"] = np.full(grid.number_of_links, 1.0) # m
- >>> grid.at_link["channel_slope"] = np.full(grid.number_of_links, 0.01) # m / m
- >>> grid.at_link["reach_length"] = np.full(grid.number_of_links, 100.0) # m
- >>> make_pulse_base = SedimentPulserBase(grid)
- >>> make_pulse_base._parcels
-
- SedimentPulserBase does not have any methods for adding a pulse
-
- >>> a_pulse = make_pulse_base()
- Traceback (most recent call last):
- ...
- NotImplementedError: the base component has no call method
- """
-
- _name = "SedimentPulserBase"
-
- _unit_agnostic = False
-
- _info = {} # works with the DataRecord
-
- def __init__(
- self,
- grid,
- parcels=None,
- D50=0.05,
- D84_D50=2.1,
- rho_sediment=2650.0,
- parcel_volume=0.5,
- abrasion_rate=0.0,
- ):
- self._grid = grid
- self._parcels = parcels
- self._D50 = D50
- self._D84_D50 = D84_D50
- self._rho_sediment = rho_sediment
- self._parcel_volume = parcel_volume
- self._abrasion_rate = abrasion_rate
-
- if not isinstance(grid, NetworkModelGrid):
- raise ValueError(
- "NetworkSedimentTransporter: grid must be NetworkModelGrid"
- )
-
- def __call__(self):
- """__call__ is not implemented for this component."""
- raise NotImplementedError("the base component has no call method")
+from landlab.core.model_component import Component
+from landlab.grid.network import NetworkModelGrid
+
+
+class SedimentPulserBase(Component):
+ """Base class of :class:`~.SedimentPulserAtLinks` and :class:`~.SedimentPulserEachParcel`.
+
+ :class:`~.SedimentPulserAtLinks` and :class:`~.SedimentPulserEachParcel` run the
+ landlab :class:`~.DataRecord` :meth:`~.DataRecord.add_item` method on a
+ :class:`~.DataRecord` configured for :class:`~.NetworkSedimentTransporter`.
+
+
+ .. codeauthor: Jeff Keck, Allison Pfeiffer, Shelby Ahrendt
+ (with help from Eric Hutton and Katy Barnhart)
+
+ Parameters
+ ----------
+ grid : ModelGrid
+ landlab *ModelGrid* to place sediment parcels on.
+ parcels: landlab DataRecord
+ Tracks parcel location and variables
+ D50: float, optional
+ median grain size [m]
+ D84_D50: float, optional
+ ratio of 84th percentile grain size to the median grain size
+ rho_sediment : float, optional
+ Sediment grain density [kg / m^3].
+ parcel_volume : float, optional
+ parcel volume used for all parcels that do not have a specified volume
+ abrasion_rate: float, optional
+ volumetric abrasion exponent [1/m]
+
+
+ Examples
+ --------
+ >>> import numpy as np
+ >>> from landlab import NetworkModelGrid
+
+ >>> y_of_node = (0, 100, 200, 200, 300, 400, 400, 125)
+ >>> x_of_node = (0, 0, 100, -50, -100, 50, -150, -100)
+ >>> nodes_at_link = ((1, 0), (2, 1), (1, 7), (3, 1), (3, 4), (4, 5), (4, 6))
+ >>> grid = NetworkModelGrid((y_of_node, x_of_node), nodes_at_link)
+ >>> grid.at_link["channel_width"] = np.full(grid.number_of_links, 1.0) # m
+ >>> grid.at_link["channel_slope"] = np.full(grid.number_of_links, 0.01) # m / m
+ >>> grid.at_link["reach_length"] = np.full(grid.number_of_links, 100.0) # m
+ >>> make_pulse_base = SedimentPulserBase(grid)
+ >>> make_pulse_base._parcels
+
+ SedimentPulserBase does not have any methods for adding a pulse
+
+ >>> a_pulse = make_pulse_base()
+ Traceback (most recent call last):
+ ...
+ NotImplementedError: the base component has no call method
+ """
+
+ _name = "SedimentPulserBase"
+
+ _unit_agnostic = False
+
+ _info = {} # works with the DataRecord
+
+ def __init__(
+ self,
+ grid,
+ parcels=None,
+ D50=0.05,
+ D84_D50=2.1,
+ rho_sediment=2650.0,
+ parcel_volume=0.5,
+ abrasion_rate=0.0,
+ ):
+ self._grid = grid
+ self._parcels = parcels
+ self._D50 = D50
+ self._D84_D50 = D84_D50
+ self._rho_sediment = rho_sediment
+ self._parcel_volume = parcel_volume
+ self._abrasion_rate = abrasion_rate
+
+ if not isinstance(grid, NetworkModelGrid):
+ raise ValueError(
+ "NetworkSedimentTransporter: grid must be NetworkModelGrid"
+ )
+
+ def __call__(self):
+ """__call__ is not implemented for this component."""
+ raise NotImplementedError("the base component has no call method")
diff --git a/src/landlab/components/network_sediment_transporter/sediment_pulser_each_parcel.py b/src/landlab/components/network_sediment_transporter/sediment_pulser_each_parcel.py
index 772bde1b96..0e5668bff0 100644
--- a/src/landlab/components/network_sediment_transporter/sediment_pulser_each_parcel.py
+++ b/src/landlab/components/network_sediment_transporter/sediment_pulser_each_parcel.py
@@ -1,340 +1,340 @@
-import warnings
-
-import numpy as np
-
-from landlab.components.network_sediment_transporter.sediment_pulser_base import (
- SedimentPulserBase,
-)
-from landlab.data_record.data_record import DataRecord
-
-_OUT_OF_NETWORK = -2
-
-
-class SedimentPulserEachParcel(SedimentPulserBase):
- """Send pulses of sediment to specific point locations within the channel
- network and divide the pulses into parcels. Pulses may be any volume.
- Parcels must be less than or equal to a user specified maximum volume.
-
- SedimentPulserEachParcel is instantiated by specifying the network model grid
- it will pulse the parcels into
-
- SedimentPulserEachParcel is run (adds parcels to DataRecrod) by calling the
- SedimentPulserEachParcel instance with the time that pulses are added to
- the channel network and a sediment pulse table (PulseDF)
-
- PulseDF is a pandas dataframe. At a minimum, the dataframe must have columns 'Link#'
- 'normalized_downstream_distance' and 'pulse_volume'. Optionally, the parcel
- volume that the pulse is divided into and grain characteristics of each pulse
- can also be specified in PulseDF.
-
-
- .. codeauthor: Jeff Keck, Allison Pfeiffer, Shelby Ahrendt
- (with help from Eric Hutton and Katy Barnhart)
-
-
- Examples
- --------
- >>> import numpy as np
- >>> import pandas as pd
- >>> from landlab import NetworkModelGrid
-
- Create the network model grid. Pulses are added to the links of the network
- model grid.
-
- >>> y_of_node = (0, 100, 200, 200, 300, 400, 400, 125)
- >>> x_of_node = (0, 0, 100, -50, -100, 50, -150, -100)
- >>> nodes_at_link = ((1, 0), (2, 1), (1, 7), (3, 1), (3, 4), (4, 5), (4, 6))
- >>> grid = NetworkModelGrid((y_of_node, x_of_node), nodes_at_link)
- >>> grid.at_link["channel_width"] = np.full(grid.number_of_links, 1.0) # m
- >>> grid.at_link["channel_slope"] = np.full(grid.number_of_links, 0.01) # m / m
- >>> grid.at_link["reach_length"] = np.full(grid.number_of_links, 100.0) # m
-
-
- Instantiate 'SedimentPulserEachParcel'
-
- >>> make_pulse = SedimentPulserEachParcel(grid)
-
- Define the PulseDF and time of the pulse
-
- >>> PulseDF = pd.DataFrame(
- ... {
- ... "pulse_volume": [0.2, 1, 1.1, 0.5],
- ... "link_#": [1, 3, 5, 2],
- ... "normalized_downstream_distance": [0.8, 0.7, 0.5, 0.2],
- ... }
- ... )
- >>> time = 7
-
- Run the instance
-
- >>> parcels = make_pulse(time, PulseDF)
-
- This should yield a UserWarning: Parcels not provided, created a new DataRecord
-
- check element_id of each parcel
-
- >>> print(parcels.dataset["element_id"].values)
- [[1]
- [3]
- [3]
- [5]
- [5]
- [5]
- [2]]
-
- """
-
- _name = "SedimentPulserEachParcel"
-
- _unit_agnostic = False
-
- _info = {} # works with the DataRecord
-
- def __init__(
- self,
- grid,
- parcels=None,
- D50=0.05,
- D84_D50=2.1,
- rho_sediment=2650.0,
- parcel_volume=0.5,
- abrasion_rate=0.0,
- rng=None,
- ):
- """
- instantiate SedimentPulserEachParcel
-
- Parameters
- ----------
- grid : ModelGrid
- landlab *ModelGrid* to place sediment parcels on.
- parcels: landlab DataRecord, optional
- Tracks parcel location and attributes
- D50: float, optional
- median grain size [m]
- D84_D50: float, optional
- ratio of 84th percentile grain size to the median grain size
- rho_sediment : float, optional
- Sediment grain density [kg/m^3].
- parcel_volume : float, optional
- parcel volume [m^3]
- abrasion_rate: float, optional
- volumetric abrasion exponent [1/m]
- """
- if rng is None:
- rng = np.random.default_rng()
- elif isinstance(rng, int):
- rng = np.random.default_rng(seed=rng)
- self._rng = rng
-
- SedimentPulserBase.__init__(
- self,
- grid,
- parcels=parcels,
- D50=D50,
- D84_D50=D84_D50,
- rho_sediment=rho_sediment,
- parcel_volume=parcel_volume,
- abrasion_rate=abrasion_rate,
- )
-
- def __call__(self, time, PulseDF=None):
- """specify the location and attributes of each pulse of material added to
- a Network Model Grid DataRecord
-
- Parameters
- ----------
- time : integer or datetime64 value equal to nst.time
- time that the pulse is triggered in the network sediment transporter
- PulseDF : pandas dataframe
- each row contains information on the deposition location and volume of
- a single pulse of sediment. The pulse is divided into 'n' number of
- parcels, where 'n' equals the np.ceil(pulse volume / parcel volume)
- For details on the format of the DataFrame, see the docstring for
- function _sediment_pulse_dataframe
-
-
- Returns
- -------
- self._parcels
- a DataRecord containing all information on each individual parcel
- """
- # If no PulseDF provided, raise error. Should at least provide an empty PulseDF
- if PulseDF is None:
- raise ValueError("PulseDF was not specified")
-
- if (
- PulseDF.empty is True
- ): # if empty, pulser stops, returns the existing parcels, call stops
- warnings.warn("Pulse DataFrame is EMPTY", stacklevel=2)
- return self._parcels
-
- variables, items = self._sediment_pulse_dataframe(
- time, # create variabels and and items needed to create the data record
- PulseDF,
- )
-
- if self._parcels is None: # if no parcels, create parcels
- self._parcels = DataRecord(
- self._grid,
- items=items,
- time=[time],
- data_vars=variables,
- dummy_elements={"link": [_OUT_OF_NETWORK]},
- )
-
- warnings.warn(
- "Parcels not provided, created a new DataRecord", stacklevel=2
- )
-
- else: # else use the add item method to add parcels
- self._parcels.add_item(time=[time], new_item=items, new_item_spec=variables)
-
- return self._parcels
-
- def _sediment_pulse_dataframe(self, time, PulseDF):
- """Convert PulseDF to a :class:`~.DataRecord` formatted for the
- :class:`~.NetworkSedimentTransporter`.
-
- Parameters
- ----------
- time : integer or datetime64
-
- PulseDF : pandas dataframe
-
- The PulseDF must include the following columns:
- 'link_#', 'pulse_volume', 'normalized_downstream_distance'
-
- Optionally, PulseDF can include the following columns:
- 'D50', 'D84_D50', 'abrasion_rate', 'rho_sediment', 'parcel_volume'
-
- Values in each columne are defined as follows:
-
- 'link_#': int - link number pulse enters the channel network
- 'pulse_volume: float - total volume of the pulse [m^3]
- 'normalized_downstream_distance': float - distance from link inlet
- divided by link length
- 'D50': float - median grain size [m]
- 'D84_D50': float - grain-size standard deviation [m]
- 'abrasion_rate': float - rate that grain size decreases with
- distance along channel [mm/km?]
- 'rho_sediment': float - density grains [kg/m^3]
- 'parcel_volume': float - maximum volume of one parcel [m^3]
-
-
- if the optional columns are not included in PulseDF, those parameters
- are assumed uniform across the basin, constant with time and equal
- to the corrisponding class variables.
-
- Returns
- -------
- tuple: (variables, items)
- variables: dictionary, attribute values for all new parcels
- item_id: dictionary, model grid element and index of element of each parcel
-
- """
- # split pulse into parcels.
- p_np = [] # list of number of parcels in each pulse
- volume = np.array([]) # list of parcel volumes from all pulses
- for _index, row in PulseDF.iterrows():
- # set the maximum allowable parcel volume using either
- # the default value or value in PulseDF
- if "parcel_volume" in PulseDF:
- mpv = row["parcel_volume"]
- else:
- mpv = self._parcel_volume
-
- # split the pulse into parcels
- if row["pulse_volume"] < mpv:
- # only one partial parcel volume
- v_p = np.array([row["pulse_volume"]])
- else:
- # number of whole parcels
- n_wp = int(np.floor(row["pulse_volume"] / mpv))
- # array of volumes, whole parcels
- v_wp = np.ones(n_wp) * mpv
- # volume of last parcel, a partial parcel
- v_pp = np.array([row["pulse_volume"] % mpv])
- # array of all parcel volumes
- # partial parcel included if volume > 0
- if v_pp > 0:
- v_p = np.concatenate((v_wp, v_pp))
- else:
- v_p = v_wp
- volume = np.concatenate((volume, v_p))
- p_np.append(len(v_p))
- volume = np.expand_dims(volume, axis=1)
-
- # link location
- link_distance_ratio = np.array([])
- for i, val in enumerate(PulseDF["normalized_downstream_distance"].values):
- # parcels from the same pulse enter channel at the same point
- link_distance_ratio = np.concatenate(
- (link_distance_ratio, np.ones(p_np[i]) * val)
- )
- location_in_link = np.expand_dims(link_distance_ratio, axis=1)
-
- # element id and starting link
- element_id = np.array([])
- for i, row in PulseDF.iterrows():
- element_id = np.concatenate((element_id, np.ones(p_np[i]) * row["link_#"]))
- starting_link = element_id.copy()
- element_id = np.expand_dims(element_id.astype(int), axis=1)
-
- # specify that parcels are in the links of the network model grid
- grid_element = ["link"] * np.size(element_id)
- grid_element = np.expand_dims(grid_element, axis=1)
-
- # time of arrivial (time instance called)
- time_arrival_in_link = np.full(np.shape(element_id), time, dtype=float)
-
- # All parcels in pulse are in the active layer (1) rather than subsurface (0)
- active_layer = np.ones(np.shape(element_id))
-
- if "rho_sediment" in PulseDF.columns:
- density = np.array([])
- for i, row in PulseDF.iterrows():
- density = np.concatenate(
- (density, np.ones(p_np[i]) * row["rho_sediment"])
- )
- else:
- density = self._rho_sediment * np.ones(np.shape(starting_link))
-
- if "abrasion_rate" in PulseDF.columns:
- abrasion_rate = np.array([])
- for i, row in PulseDF.iterrows():
- abrasion_rate = np.concatenate(
- (abrasion_rate, np.ones(p_np[i]) * row["abrasion_rate"])
- )
- else:
- abrasion_rate = self._abrasion_rate * np.ones(np.shape(starting_link))
-
- if "D50" in PulseDF.columns and "D84_D50" in PulseDF.columns:
- grain_size = np.array([])
- for i, row in PulseDF.iterrows():
- # det D50 and D84_D50
- n_parcels = p_np[i]
- D50 = row["D50"]
- D84_D50 = row["D84_D50"]
- grain_size_pulse = self._rng.lognormal(
- np.log(D50), np.log(D84_D50), n_parcels
- )
- grain_size = np.concatenate((grain_size, grain_size_pulse))
- else:
- n_parcels = sum(p_np)
- D50 = self._D50
- D84_D50 = self._D84_D50
- grain_size = self._rng.lognormal(np.log(D50), np.log(D84_D50), n_parcels)
-
- grain_size = np.expand_dims(grain_size, axis=1)
-
- return {
- "starting_link": (["item_id"], starting_link),
- "abrasion_rate": (["item_id"], abrasion_rate),
- "density": (["item_id"], density),
- "time_arrival_in_link": (["item_id", "time"], time_arrival_in_link),
- "active_layer": (["item_id", "time"], active_layer),
- "location_in_link": (["item_id", "time"], location_in_link),
- "D": (["item_id", "time"], grain_size),
- "volume": (["item_id", "time"], volume),
- }, {"grid_element": grid_element, "element_id": element_id}
+import warnings
+
+import numpy as np
+
+from landlab.components.network_sediment_transporter.sediment_pulser_base import (
+ SedimentPulserBase,
+)
+from landlab.data_record.data_record import DataRecord
+
+_OUT_OF_NETWORK = -2
+
+
+class SedimentPulserEachParcel(SedimentPulserBase):
+ """Send pulses of sediment to specific point locations within the channel
+ network and divide the pulses into parcels. Pulses may be any volume.
+ Parcels must be less than or equal to a user specified maximum volume.
+
+ SedimentPulserEachParcel is instantiated by specifying the network model grid
+ it will pulse the parcels into
+
+ SedimentPulserEachParcel is run (adds parcels to DataRecrod) by calling the
+ SedimentPulserEachParcel instance with the time that pulses are added to
+ the channel network and a sediment pulse table (PulseDF)
+
+ PulseDF is a pandas dataframe. At a minimum, the dataframe must have columns 'Link#'
+ 'normalized_downstream_distance' and 'pulse_volume'. Optionally, the parcel
+ volume that the pulse is divided into and grain characteristics of each pulse
+ can also be specified in PulseDF.
+
+
+ .. codeauthor: Jeff Keck, Allison Pfeiffer, Shelby Ahrendt
+ (with help from Eric Hutton and Katy Barnhart)
+
+
+ Examples
+ --------
+ >>> import numpy as np
+ >>> import pandas as pd
+ >>> from landlab import NetworkModelGrid
+
+ Create the network model grid. Pulses are added to the links of the network
+ model grid.
+
+ >>> y_of_node = (0, 100, 200, 200, 300, 400, 400, 125)
+ >>> x_of_node = (0, 0, 100, -50, -100, 50, -150, -100)
+ >>> nodes_at_link = ((1, 0), (2, 1), (1, 7), (3, 1), (3, 4), (4, 5), (4, 6))
+ >>> grid = NetworkModelGrid((y_of_node, x_of_node), nodes_at_link)
+ >>> grid.at_link["channel_width"] = np.full(grid.number_of_links, 1.0) # m
+ >>> grid.at_link["channel_slope"] = np.full(grid.number_of_links, 0.01) # m / m
+ >>> grid.at_link["reach_length"] = np.full(grid.number_of_links, 100.0) # m
+
+
+ Instantiate 'SedimentPulserEachParcel'
+
+ >>> make_pulse = SedimentPulserEachParcel(grid)
+
+ Define the PulseDF and time of the pulse
+
+ >>> PulseDF = pd.DataFrame(
+ ... {
+ ... "pulse_volume": [0.2, 1, 1.1, 0.5],
+ ... "link_#": [1, 3, 5, 2],
+ ... "normalized_downstream_distance": [0.8, 0.7, 0.5, 0.2],
+ ... }
+ ... )
+ >>> time = 7
+
+ Run the instance
+
+ >>> parcels = make_pulse(time, PulseDF)
+
+ This should yield a UserWarning: Parcels not provided, created a new DataRecord
+
+ check element_id of each parcel
+
+ >>> print(parcels.dataset["element_id"].values)
+ [[1]
+ [3]
+ [3]
+ [5]
+ [5]
+ [5]
+ [2]]
+
+ """
+
+ _name = "SedimentPulserEachParcel"
+
+ _unit_agnostic = False
+
+ _info = {} # works with the DataRecord
+
+ def __init__(
+ self,
+ grid,
+ parcels=None,
+ D50=0.05,
+ D84_D50=2.1,
+ rho_sediment=2650.0,
+ parcel_volume=0.5,
+ abrasion_rate=0.0,
+ rng=None,
+ ):
+ """
+ instantiate SedimentPulserEachParcel
+
+ Parameters
+ ----------
+ grid : ModelGrid
+ landlab *ModelGrid* to place sediment parcels on.
+ parcels: landlab DataRecord, optional
+ Tracks parcel location and attributes
+ D50: float, optional
+ median grain size [m]
+ D84_D50: float, optional
+ ratio of 84th percentile grain size to the median grain size
+ rho_sediment : float, optional
+ Sediment grain density [kg/m^3].
+ parcel_volume : float, optional
+ parcel volume [m^3]
+ abrasion_rate: float, optional
+ volumetric abrasion exponent [1/m]
+ """
+ if rng is None:
+ rng = np.random.default_rng()
+ elif isinstance(rng, int):
+ rng = np.random.default_rng(seed=rng)
+ self._rng = rng
+
+ SedimentPulserBase.__init__(
+ self,
+ grid,
+ parcels=parcels,
+ D50=D50,
+ D84_D50=D84_D50,
+ rho_sediment=rho_sediment,
+ parcel_volume=parcel_volume,
+ abrasion_rate=abrasion_rate,
+ )
+
+ def __call__(self, time, PulseDF=None):
+ """specify the location and attributes of each pulse of material added to
+ a Network Model Grid DataRecord
+
+ Parameters
+ ----------
+ time : integer or datetime64 value equal to nst.time
+ time that the pulse is triggered in the network sediment transporter
+ PulseDF : pandas dataframe
+ each row contains information on the deposition location and volume of
+ a single pulse of sediment. The pulse is divided into 'n' number of
+ parcels, where 'n' equals the np.ceil(pulse volume / parcel volume)
+ For details on the format of the DataFrame, see the docstring for
+ function _sediment_pulse_dataframe
+
+
+ Returns
+ -------
+ self._parcels
+ a DataRecord containing all information on each individual parcel
+ """
+ # If no PulseDF provided, raise error. Should at least provide an empty PulseDF
+ if PulseDF is None:
+ raise ValueError("PulseDF was not specified")
+
+ if (
+ PulseDF.empty is True
+ ): # if empty, pulser stops, returns the existing parcels, call stops
+ warnings.warn("Pulse DataFrame is EMPTY", stacklevel=2)
+ return self._parcels
+
+ variables, items = self._sediment_pulse_dataframe(
+ time, # create variabels and and items needed to create the data record
+ PulseDF,
+ )
+
+ if self._parcels is None: # if no parcels, create parcels
+ self._parcels = DataRecord(
+ self._grid,
+ items=items,
+ time=[time],
+ data_vars=variables,
+ dummy_elements={"link": [_OUT_OF_NETWORK]},
+ )
+
+ warnings.warn(
+ "Parcels not provided, created a new DataRecord", stacklevel=2
+ )
+
+ else: # else use the add item method to add parcels
+ self._parcels.add_item(time=[time], new_item=items, new_item_spec=variables)
+
+ return self._parcels
+
+ def _sediment_pulse_dataframe(self, time, PulseDF):
+ """Convert PulseDF to a :class:`~.DataRecord` formatted for the
+ :class:`~.NetworkSedimentTransporter`.
+
+ Parameters
+ ----------
+ time : integer or datetime64
+
+ PulseDF : pandas dataframe
+
+ The PulseDF must include the following columns:
+ 'link_#', 'pulse_volume', 'normalized_downstream_distance'
+
+ Optionally, PulseDF can include the following columns:
+ 'D50', 'D84_D50', 'abrasion_rate', 'rho_sediment', 'parcel_volume'
+
+ Values in each columne are defined as follows:
+
+ 'link_#': int - link number pulse enters the channel network
+ 'pulse_volume: float - total volume of the pulse [m^3]
+ 'normalized_downstream_distance': float - distance from link inlet
+ divided by link length
+ 'D50': float - median grain size [m]
+ 'D84_D50': float - grain-size standard deviation [m]
+ 'abrasion_rate': float - rate that grain size decreases with
+ distance along channel [mm/km?]
+ 'rho_sediment': float - density grains [kg/m^3]
+ 'parcel_volume': float - maximum volume of one parcel [m^3]
+
+
+ if the optional columns are not included in PulseDF, those parameters
+ are assumed uniform across the basin, constant with time and equal
+ to the corrisponding class variables.
+
+ Returns
+ -------
+ tuple: (variables, items)
+ variables: dictionary, attribute values for all new parcels
+ item_id: dictionary, model grid element and index of element of each parcel
+
+ """
+ # split pulse into parcels.
+ p_np = [] # list of number of parcels in each pulse
+ volume = np.array([]) # list of parcel volumes from all pulses
+ for _index, row in PulseDF.iterrows():
+ # set the maximum allowable parcel volume using either
+ # the default value or value in PulseDF
+ if "parcel_volume" in PulseDF:
+ mpv = row["parcel_volume"]
+ else:
+ mpv = self._parcel_volume
+
+ # split the pulse into parcels
+ if row["pulse_volume"] < mpv:
+ # only one partial parcel volume
+ v_p = np.array([row["pulse_volume"]])
+ else:
+ # number of whole parcels
+ n_wp = int(np.floor(row["pulse_volume"] / mpv))
+ # array of volumes, whole parcels
+ v_wp = np.ones(n_wp) * mpv
+ # volume of last parcel, a partial parcel
+ v_pp = np.array([row["pulse_volume"] % mpv])
+ # array of all parcel volumes
+ # partial parcel included if volume > 0
+ if v_pp > 0:
+ v_p = np.concatenate((v_wp, v_pp))
+ else:
+ v_p = v_wp
+ volume = np.concatenate((volume, v_p))
+ p_np.append(len(v_p))
+ volume = np.expand_dims(volume, axis=1)
+
+ # link location
+ link_distance_ratio = np.array([])
+ for i, val in enumerate(PulseDF["normalized_downstream_distance"].values):
+ # parcels from the same pulse enter channel at the same point
+ link_distance_ratio = np.concatenate(
+ (link_distance_ratio, np.ones(p_np[i]) * val)
+ )
+ location_in_link = np.expand_dims(link_distance_ratio, axis=1)
+
+ # element id and starting link
+ element_id = np.array([])
+ for i, row in PulseDF.iterrows():
+ element_id = np.concatenate((element_id, np.ones(p_np[i]) * row["link_#"]))
+ starting_link = element_id.copy()
+ element_id = np.expand_dims(element_id.astype(int), axis=1)
+
+ # specify that parcels are in the links of the network model grid
+ grid_element = ["link"] * np.size(element_id)
+ grid_element = np.expand_dims(grid_element, axis=1)
+
+ # time of arrivial (time instance called)
+ time_arrival_in_link = np.full(np.shape(element_id), time, dtype=float)
+
+ # All parcels in pulse are in the active layer (1) rather than subsurface (0)
+ active_layer = np.ones(np.shape(element_id))
+
+ if "rho_sediment" in PulseDF.columns:
+ density = np.array([])
+ for i, row in PulseDF.iterrows():
+ density = np.concatenate(
+ (density, np.ones(p_np[i]) * row["rho_sediment"])
+ )
+ else:
+ density = self._rho_sediment * np.ones(np.shape(starting_link))
+
+ if "abrasion_rate" in PulseDF.columns:
+ abrasion_rate = np.array([])
+ for i, row in PulseDF.iterrows():
+ abrasion_rate = np.concatenate(
+ (abrasion_rate, np.ones(p_np[i]) * row["abrasion_rate"])
+ )
+ else:
+ abrasion_rate = self._abrasion_rate * np.ones(np.shape(starting_link))
+
+ if "D50" in PulseDF.columns and "D84_D50" in PulseDF.columns:
+ grain_size = np.array([])
+ for i, row in PulseDF.iterrows():
+ # det D50 and D84_D50
+ n_parcels = p_np[i]
+ D50 = row["D50"]
+ D84_D50 = row["D84_D50"]
+ grain_size_pulse = self._rng.lognormal(
+ np.log(D50), np.log(D84_D50), n_parcels
+ )
+ grain_size = np.concatenate((grain_size, grain_size_pulse))
+ else:
+ n_parcels = sum(p_np)
+ D50 = self._D50
+ D84_D50 = self._D84_D50
+ grain_size = self._rng.lognormal(np.log(D50), np.log(D84_D50), n_parcels)
+
+ grain_size = np.expand_dims(grain_size, axis=1)
+
+ return {
+ "starting_link": (["item_id"], starting_link),
+ "abrasion_rate": (["item_id"], abrasion_rate),
+ "density": (["item_id"], density),
+ "time_arrival_in_link": (["item_id", "time"], time_arrival_in_link),
+ "active_layer": (["item_id", "time"], active_layer),
+ "location_in_link": (["item_id", "time"], location_in_link),
+ "D": (["item_id", "time"], grain_size),
+ "volume": (["item_id", "time"], volume),
+ }, {"grid_element": grid_element, "element_id": element_id}
diff --git a/src/landlab/components/normal_fault/normal_fault.py b/src/landlab/components/normal_fault/normal_fault.py
index 2e05bd2977..8d4d7e2d30 100644
--- a/src/landlab/components/normal_fault/normal_fault.py
+++ b/src/landlab/components/normal_fault/normal_fault.py
@@ -1,460 +1,460 @@
-#!/usr/bin/env python
-"""Rock uplift along a normal fault.
-
-Landlab component that implements rock uplift by a normal fault. Note
-that this component does not make any attempt to advect topography
-laterally.
-"""
-
-import numpy as np
-
-from landlab import Component
-from landlab import FieldError
-
-TWO_PI = 2.0 * np.pi
-
-
-class NormalFault(Component):
- """NormalFault implements relative rock motion due to a normal fault.
-
- The fault can have an arbitrary trace given by two points (x1, y1) and
- (x2, y2) in the `fault_trace` input parameter. These value of these points
- is in model-space coordinates and is not based on node id values or number
- of rows and columns.
-
- This NormalFault component permits two primary methods for enacting fault
- motion.
-
- 1. **run_one_step**: The throw rate is provided through the
- ``fault_throw_rate_through_time`` parameter. This rate can be constant or
- arbitrary. See the NormalFault tutorial in the landlab tutorials repository
- for an extensive example. In this case, the NormalFault component will keep
- track of the cumulative amount of model-run-time and set the rate based on
- interpolating the provided rate-time history. *NOTE: this means that the
- model run timesteps must align with the time-rate relationship provided to
- NormalFault*. Improving this is on the developers todo list but is of low
- priority.
-
- 2. **run_one_earthquake**: A single uplift event of size dz can be
- specified by this method. If NormalFault is used in this way, any
- specifications provided in the ``fault_throw_rate_through_time`` keyword
- argument will be ignored.
-
- Note that the NormalFault component does not prevent a user from combining
- the **run_one_step** and **run_one_earthquake** methods. It is encumbent
- upon the user, however, to ensure that these two methods are used in
- combination correctly for their specific use case.
-
- References
- ----------
- **Required Software Citation(s) Specific to this Component**
-
- None Listed
-
- **Additional References**
-
- None Listed
- """
-
- _name = "NormalFault"
-
- _unit_agnostic = True
-
- _info = {
- "topographic__elevation": {
- "dtype": float,
- "intent": "inout",
- "optional": True,
- "units": "m",
- "mapping": "node",
- "doc": "Land surface topographic elevation",
- }
- }
-
- def __init__(
- self,
- grid,
- faulted_surface="topographic__elevation",
- fault_throw_rate_through_time=(("time", [0]), ("rate", [0.001])),
- fault_dip_angle=90.0,
- fault_trace=(("x1", 0), ("y1", 0), ("x2", 1), ("y2", 1)),
- include_boundaries=False,
- ):
- """Instantiation of a NormalFault.
-
- Parameters
- ----------
- grid : ModelGrid
- faulted_surface : str or list of str
- Surface that is modified by the NormalFault component. Must be a
- field name or a list of field names if the fault should uplift more
- than one field. Default value is `topographic__elevation`.
- If the faulted surface does not yet exist, it will be ingored. The
- ``run_one_step`` method will check to see an ignored field has been
- added and if it has been, it will modify it.
- fault_throw_rate_through_time : dict, optional
- Dictionary that specifies the time varying throw rate on the fault.
- Expected format is:
- `fault_throw_rate_through_time = {'time': array, 'rate': array}`
- Default value is a constant rate of 0.001 (units not specified).
- This is acomplished by providing the dictionary
- `{'time': [0], 'rate': [0.001]}`. NormalFault uses numpy.interp
- to interpolate the time and rate pattern to the current model time.
- This function uses the first value for all values less than the
- first, and the last value for all values greater than the last, and
- thus providing only one number results in all times getting a rate
- of that value.
- fault_dip_angle : float, optional
- Dip angle of the fault in degrees. Default value is 90 degrees.
- fault_trace : dictionary, optional
- Dictionary that specifies the coordinates of two locations on the
- fault trace. Expected format is
-
- .. code-block:: python
-
- fault_trace = {"x1": float, "y1": float, "x2": float, "y2": float}
-
- where the vector from `(x1, y1)` to `(x2, y2)` defines the
- strike of the fault trace. The orientation of the fault dip relative
- to the strike follows the right hand rule.
- Default is for the fault to strike NE.
- include_boundaries : boolean, optional
- Flag to indicate if model grid boundaries should be uplifted. If
- set to `True` uplifted model grid boundaries will be set to the
- average value of their upstream nodes. Default value is False.
-
- Examples
- --------
- Create a grid on which we will run the NormalFault component.
-
- >>> from landlab import RasterModelGrid
- >>> from landlab.components import NormalFault
- >>> grid = RasterModelGrid((6, 6), xy_spacing=10)
-
- Add an elevation field.
-
- >>> z = grid.add_zeros("topographic__elevation", at="node")
-
- Set the parameter values for the NormalFault component.
-
- >>> param_dict = {
- ... "faulted_surface": "topographic__elevation",
- ... "fault_dip_angle": 90.0,
- ... "fault_throw_rate_through_time": {
- ... "time": [0, 9, 10],
- ... "rate": [0, 0, 0.05],
- ... },
- ... "fault_trace": {"y1": 0, "x1": 0, "y2": 30, "x2": 60},
- ... "include_boundaries": False,
- ... }
-
- Instantiate a NormalFault component.
-
- >>> nf = NormalFault(grid, **param_dict)
- >>> nf.faulted_nodes.reshape(grid.shape)
- array([[False, False, False, False, False, False],
- [False, True, False, False, False, False],
- [False, True, True, True, False, False],
- [False, True, True, True, True, False],
- [False, True, True, True, True, False],
- [False, False, False, False, False, False]])
-
- As we can see, only a subset of the nodes have been identified as
- *faulted nodes*. Because we have set include_boundaries' to False none
- of the boundary nodes are faulted nodes.
-
- Next we will run the NormalFault for 30 1-year timesteps.
-
- >>> dt = 1.0
- >>> for i in range(30):
- ... nf.run_one_step(dt)
- ...
- >>> z.reshape(grid.shape)
- array([[0., 0., 0., 0., 0., 0.],
- [0., 1., 0., 0., 0., 0.],
- [0., 1., 1., 1., 0., 0.],
- [0., 1., 1., 1., 1., 0.],
- [0., 1., 1., 1., 1., 0.],
- [0., 0., 0., 0., 0., 0.]])
-
- This results in uplift of the faulted nodes, as we would expect.
-
- If the user knows how much uplift (dz) they want to occur in an event,
- they can use the **run_one_earthquake** function with a specified dz.
- In this case fault_throw_rate_through_time will be ignored.
-
- >>> nf.run_one_earthquake(dz=100)
- >>> z.reshape(grid.shape)
- array([[ 0., 0., 0., 0., 0., 0.],
- [ 0., 101., 0., 0., 0., 0.],
- [ 0., 101., 101., 101., 0., 0.],
- [ 0., 101., 101., 101., 101., 0.],
- [ 0., 101., 101., 101., 101., 0.],
- [ 0., 0., 0., 0., 0., 0.]])
-
- Next, we make a very simple landscape model. We need a few components
- and we will set include_boundaries to True.
-
- >>> from landlab.components import FastscapeEroder, FlowAccumulator
- >>> grid = RasterModelGrid((6, 6), xy_spacing=10)
- >>> z = grid.add_zeros("topographic__elevation", at="node")
- >>> param_dict = {
- ... "faulted_surface": "topographic__elevation",
- ... "fault_dip_angle": 90.0,
- ... "fault_throw_rate_through_time": {
- ... "time": [0, 900, 1000],
- ... "rate": [0, 0, 0.05],
- ... },
- ... "fault_trace": {"y1": 0, "x1": 0, "y2": 30, "x2": 60},
- ... "include_boundaries": True,
- ... }
-
- >>> nf = NormalFault(grid, **param_dict)
- >>> fr = FlowAccumulator(grid)
- >>> fs = FastscapeEroder(grid, K_sp=0.01)
-
- Run this model for 300 100-year timesteps.
-
- >>> dt = 100.0
- >>> for i in range(300):
- ... nf.run_one_step(dt)
- ... fr.run_one_step()
- ... fs.run_one_step(dt)
- ...
- >>> z.reshape(grid.shape).round(decimals=2)
- array([[ 0. , 0. , 0. , 0. , 0. , 0. ],
- [ 5. , 5. , 0. , 0. , 0. , 0. ],
- [ 7.39, 7.38, 2.38, 2.89, 0. , 0. ],
- [ 9.36, 11.43, 5.51, 6.42, 3.54, 3.54],
- [15.06, 15.75, 10.6 , 11.42, 8.54, 8.54],
- [15.06, 15.06, 10.7 , 11.42, 8.54, 8.54]])
-
- The faulted nodes have been uplifted and eroded! Note that here the
- boundary nodes are also uplifted.
-
- NormalFault keeps track of internal time.
-
- For example, if a user wanted to only run NormalFault every tenth
- timestep (or some more seismogenically reasonable set of times).
-
- >>> grid = RasterModelGrid((6, 6), xy_spacing=10)
- >>> z = grid.add_zeros("topographic__elevation", at="node")
- >>> nf = NormalFault(grid, **param_dict)
- >>> fr = FlowAccumulator(grid)
- >>> fs = FastscapeEroder(grid, K_sp=0.01)
- >>> model_time = 0.0
- >>> dt = 100.0
- >>> for i in range(300):
- ... if i % 10 == 0:
- ... nf.run_one_step(dt * 10)
- ... fr.run_one_step()
- ... fs.run_one_step(dt)
- ... model_time += dt
- ...
- >>> model_time
- 30000.0
- >>> nf.current_time
- 30000.0
- """
- fault_throw_rate_through_time = dict(fault_throw_rate_through_time)
- fault_trace = dict(fault_trace)
-
- super().__init__(grid)
-
- # save a reference to the grid
-
- # get the surface to be faulted
- self._surfaces = {}
- self._not_yet_instantiated = []
- if isinstance(faulted_surface, list):
- # if faulted surface is a list, then itterate through multiple
- # surfaces and save
- for surf in faulted_surface:
- try:
- self._surfaces[surf] = grid.at_node[surf]
- except FieldError:
- self._not_yet_instantiated.append(surf)
- else:
- self._surfaces[faulted_surface] = grid.at_node[faulted_surface]
-
- if fault_dip_angle > 90.0:
- raise ValueError(
- "NormaFault fault_dip_angle must be less than 90 " "degrees."
- )
-
- # get the fault throw parameter values from the parameter dictionary
- self._throw_time = np.array(fault_throw_rate_through_time["time"])
- self._throw_rate = np.array(fault_throw_rate_through_time["rate"])
- self._fault_dip = np.deg2rad(fault_dip_angle)
- self._uplift = self._throw_rate * np.sin(self._fault_dip)
-
- # Identify in current boundaries will be included
- self._include_boundaries = include_boundaries
-
- # Instantiate record of current time.
- self._current_time = 0.0
-
- # get the fault trace dictionary and use to to calculate where the
- # faulted nodes are located.
- self._fault_trace = fault_trace
- dx = self._fault_trace["x2"] - self._fault_trace["x1"]
- dy = self._fault_trace["y2"] - self._fault_trace["y1"]
- self._fault_azimuth = np.mod(np.arctan2(dy, dx), TWO_PI)
- self._fault_anti_azimuth = self._fault_azimuth + np.pi
- # deal with the edge case in which dx == 0
- if dx == 0:
- self._dy_over_dx = 0.0
- self._fault_trace_y_intercept = 0.0
- self._fault_trace_x_intercept = self._fault_trace["x2"]
- else:
- self._dy_over_dx = dy / dx
- self._fault_trace_y_intercept = self._fault_trace["y1"] - (
- self._dy_over_dx * self._fault_trace["x1"]
- )
- self._fault_trace_x_intercept = 0.0
-
- # set the considered nodes based on whether the boundaries will be
- # included in the faulted terrain.
- if self._include_boundaries:
- potential_nodes = np.arange(self._grid.size("node"))
- else:
- potential_nodes = self._grid.core_nodes
-
- # select those nodes that are on the correct side of the fault
- dx_pn = self._grid.x_of_node[potential_nodes] - self._fault_trace_x_intercept
- dy_pn = self._grid.y_of_node[potential_nodes] - self._fault_trace_y_intercept
- potential_angles = np.mod(np.arctan2(dy_pn, dx_pn), TWO_PI)
- if self._fault_anti_azimuth <= TWO_PI:
- faulted_node_ids = potential_nodes[
- (
- (potential_angles > self._fault_azimuth)
- & (potential_angles <= (self._fault_anti_azimuth))
- )
- ]
- else:
- faulted_node_ids = potential_nodes[
- (
- (potential_angles > self._fault_azimuth)
- | (potential_angles <= np.mod(self._fault_anti_azimuth, TWO_PI))
- )
- ]
-
- # save a n-node array of boolean identifing faulted nodes.
- self._faulted_nodes = np.zeros(self._grid.size("node"), dtype=bool)
- self._faulted_nodes[faulted_node_ids] = True
-
- @property
- def faulted_nodes(self):
- """At node array indicating which nodes are on the upthrown block."""
- return self._faulted_nodes
-
- def _check_surfaces(self):
- if len(self._not_yet_instantiated) > 0:
- still_not_instantiated = []
- for surf in self._not_yet_instantiated:
- if surf in self._grid.at_node:
- self._surfaces[surf] = self._grid.at_node[surf]
- else:
- still_not_instantiated.append(surf)
- self._not_yet_instantiated = still_not_instantiated
-
- def run_one_earthquake(self, dz):
- """Run one earthquake with uplift of magnitude ``dz``."""
- self._check_surfaces()
-
- # save z before uplift only if using include boundaries.
- if self._include_boundaries:
- surfs_before_uplift = {}
- for surf_name in self._surfaces:
- surfs_before_uplift[surf_name] = self._surfaces[surf_name].copy()
-
- # uplift the faulted_nodes
- for surf_name in self._surfaces:
- self._surfaces[surf_name][self._faulted_nodes] += dz
-
- # if faulted nodes includes boundaries we must do some extra work because
- # landlab components will typically not erode these boundaries. This means
- # they will be uplifted but not eroded.
-
- if self._include_boundaries:
- # here our goal is to set faulted boundaries to average of open
- # node faulted neighbors
-
- # create boolean of the faulted boundary nodes
- faulted_boundaries = self._faulted_nodes.copy()
- faulted_boundaries[self._grid.core_nodes] = False
-
- core_nodes = np.zeros(self._grid.size("node"), dtype=bool)
- core_nodes[self._grid.core_nodes] = True
-
- neighbor_is_core = core_nodes[self._grid.adjacent_nodes_at_node]
- neighbor_is_faulted = self._faulted_nodes[self._grid.adjacent_nodes_at_node]
-
- neighbor_for_averaging = neighbor_is_faulted & neighbor_is_core
-
- # Identify nodes that have at least one adjacent node that is both
- # faulted and not a boundary node.
- # average the pre-uplift topography on those adjacent nodes and assign
- # to the boundary node.
- # here we use the pre-uplift elevation because other steps in the model
- # may diminish this topography.
-
- averaged = neighbor_for_averaging[faulted_boundaries].sum(axis=1) == 1
- if any(averaged):
- averaged_nodes = np.where(faulted_boundaries)[0][np.where(averaged)[0]]
- for surf_name in self._surfaces:
- elevations_to_average = surfs_before_uplift[surf_name][
- self._grid.adjacent_nodes_at_node
- ]
- elevations_to_average[self._grid.adjacent_nodes_at_node == -1] = (
- np.nan
- )
- elevations_to_average[~neighbor_for_averaging] = np.nan
- self._surfaces[surf_name][averaged_nodes] = np.nanmean(
- elevations_to_average[averaged_nodes], axis=1
- )
-
- # identify any boundary nodes that are not being averaged. This will
- # happen at the corners on RasterModelGrids. Average over adjacent
- # nodes that are faulted. These nodes will be boundary nodes.
- # here we use the current topography as we will have just updated the
- # adjacent nodes in the prior block.
- if any(~averaged):
- un_averaged_nodes = np.where(faulted_boundaries)[0][
- np.where(~averaged)[0]
- ]
- for surf_name in self._surfaces:
- elevations_to_average = self._surfaces[surf_name][
- self._grid.adjacent_nodes_at_node
- ]
- elevations_to_average[self._grid.adjacent_nodes_at_node == -1] = (
- np.nan
- )
- elevations_to_average[~neighbor_is_faulted] = np.nan
- self._surfaces[surf_name][un_averaged_nodes] = np.nanmean(
- elevations_to_average[un_averaged_nodes], axis=1
- )
-
- def run_one_step(self, dt):
- """Run_one_step method for NormalFault.
-
- Parameters
- ----------
- dt : float
- Time increment used to advance the NormalFault component.
- current_time : float, optional
- If NormalFault is not being advanced by dt every timestep with all
- components, its internal time may be incorrect, this can be remedied
- by providing a value for current time. Default value is None which
- results in the internal timekeeping not being changed.
- """
- # calculate the current uplift rate
- current_uplift_rate = np.interp(
- self._current_time, self._throw_time, self._throw_rate
- )
-
- # run one earthquake of size current_uplift_rate * dt
- self.run_one_earthquake(current_uplift_rate * dt)
-
- # increment time
- self._current_time += dt
+#!/usr/bin/env python
+"""Rock uplift along a normal fault.
+
+Landlab component that implements rock uplift by a normal fault. Note
+that this component does not make any attempt to advect topography
+laterally.
+"""
+
+import numpy as np
+
+from landlab import Component
+from landlab import FieldError
+
+TWO_PI = 2.0 * np.pi
+
+
+class NormalFault(Component):
+ """NormalFault implements relative rock motion due to a normal fault.
+
+ The fault can have an arbitrary trace given by two points (x1, y1) and
+ (x2, y2) in the `fault_trace` input parameter. These value of these points
+ is in model-space coordinates and is not based on node id values or number
+ of rows and columns.
+
+ This NormalFault component permits two primary methods for enacting fault
+ motion.
+
+ 1. **run_one_step**: The throw rate is provided through the
+ ``fault_throw_rate_through_time`` parameter. This rate can be constant or
+ arbitrary. See the NormalFault tutorial in the landlab tutorials repository
+ for an extensive example. In this case, the NormalFault component will keep
+ track of the cumulative amount of model-run-time and set the rate based on
+ interpolating the provided rate-time history. *NOTE: this means that the
+ model run timesteps must align with the time-rate relationship provided to
+ NormalFault*. Improving this is on the developers todo list but is of low
+ priority.
+
+ 2. **run_one_earthquake**: A single uplift event of size dz can be
+ specified by this method. If NormalFault is used in this way, any
+ specifications provided in the ``fault_throw_rate_through_time`` keyword
+ argument will be ignored.
+
+ Note that the NormalFault component does not prevent a user from combining
+ the **run_one_step** and **run_one_earthquake** methods. It is encumbent
+ upon the user, however, to ensure that these two methods are used in
+ combination correctly for their specific use case.
+
+ References
+ ----------
+ **Required Software Citation(s) Specific to this Component**
+
+ None Listed
+
+ **Additional References**
+
+ None Listed
+ """
+
+ _name = "NormalFault"
+
+ _unit_agnostic = True
+
+ _info = {
+ "topographic__elevation": {
+ "dtype": float,
+ "intent": "inout",
+ "optional": True,
+ "units": "m",
+ "mapping": "node",
+ "doc": "Land surface topographic elevation",
+ }
+ }
+
+ def __init__(
+ self,
+ grid,
+ faulted_surface="topographic__elevation",
+ fault_throw_rate_through_time=(("time", [0]), ("rate", [0.001])),
+ fault_dip_angle=90.0,
+ fault_trace=(("x1", 0), ("y1", 0), ("x2", 1), ("y2", 1)),
+ include_boundaries=False,
+ ):
+ """Instantiation of a NormalFault.
+
+ Parameters
+ ----------
+ grid : ModelGrid
+ faulted_surface : str or list of str
+ Surface that is modified by the NormalFault component. Must be a
+ field name or a list of field names if the fault should uplift more
+ than one field. Default value is `topographic__elevation`.
+ If the faulted surface does not yet exist, it will be ingored. The
+ ``run_one_step`` method will check to see an ignored field has been
+ added and if it has been, it will modify it.
+ fault_throw_rate_through_time : dict, optional
+ Dictionary that specifies the time varying throw rate on the fault.
+ Expected format is:
+ `fault_throw_rate_through_time = {'time': array, 'rate': array}`
+ Default value is a constant rate of 0.001 (units not specified).
+ This is acomplished by providing the dictionary
+ `{'time': [0], 'rate': [0.001]}`. NormalFault uses numpy.interp
+ to interpolate the time and rate pattern to the current model time.
+ This function uses the first value for all values less than the
+ first, and the last value for all values greater than the last, and
+ thus providing only one number results in all times getting a rate
+ of that value.
+ fault_dip_angle : float, optional
+ Dip angle of the fault in degrees. Default value is 90 degrees.
+ fault_trace : dictionary, optional
+ Dictionary that specifies the coordinates of two locations on the
+ fault trace. Expected format is
+
+ .. code-block:: python
+
+ fault_trace = {"x1": float, "y1": float, "x2": float, "y2": float}
+
+ where the vector from `(x1, y1)` to `(x2, y2)` defines the
+ strike of the fault trace. The orientation of the fault dip relative
+ to the strike follows the right hand rule.
+ Default is for the fault to strike NE.
+ include_boundaries : boolean, optional
+ Flag to indicate if model grid boundaries should be uplifted. If
+ set to `True` uplifted model grid boundaries will be set to the
+ average value of their upstream nodes. Default value is False.
+
+ Examples
+ --------
+ Create a grid on which we will run the NormalFault component.
+
+ >>> from landlab import RasterModelGrid
+ >>> from landlab.components import NormalFault
+ >>> grid = RasterModelGrid((6, 6), xy_spacing=10)
+
+ Add an elevation field.
+
+ >>> z = grid.add_zeros("topographic__elevation", at="node")
+
+ Set the parameter values for the NormalFault component.
+
+ >>> param_dict = {
+ ... "faulted_surface": "topographic__elevation",
+ ... "fault_dip_angle": 90.0,
+ ... "fault_throw_rate_through_time": {
+ ... "time": [0, 9, 10],
+ ... "rate": [0, 0, 0.05],
+ ... },
+ ... "fault_trace": {"y1": 0, "x1": 0, "y2": 30, "x2": 60},
+ ... "include_boundaries": False,
+ ... }
+
+ Instantiate a NormalFault component.
+
+ >>> nf = NormalFault(grid, **param_dict)
+ >>> nf.faulted_nodes.reshape(grid.shape)
+ array([[False, False, False, False, False, False],
+ [False, True, False, False, False, False],
+ [False, True, True, True, False, False],
+ [False, True, True, True, True, False],
+ [False, True, True, True, True, False],
+ [False, False, False, False, False, False]])
+
+ As we can see, only a subset of the nodes have been identified as
+ *faulted nodes*. Because we have set include_boundaries' to False none
+ of the boundary nodes are faulted nodes.
+
+ Next we will run the NormalFault for 30 1-year timesteps.
+
+ >>> dt = 1.0
+ >>> for i in range(30):
+ ... nf.run_one_step(dt)
+ ...
+ >>> z.reshape(grid.shape)
+ array([[0., 0., 0., 0., 0., 0.],
+ [0., 1., 0., 0., 0., 0.],
+ [0., 1., 1., 1., 0., 0.],
+ [0., 1., 1., 1., 1., 0.],
+ [0., 1., 1., 1., 1., 0.],
+ [0., 0., 0., 0., 0., 0.]])
+
+ This results in uplift of the faulted nodes, as we would expect.
+
+ If the user knows how much uplift (dz) they want to occur in an event,
+ they can use the **run_one_earthquake** function with a specified dz.
+ In this case fault_throw_rate_through_time will be ignored.
+
+ >>> nf.run_one_earthquake(dz=100)
+ >>> z.reshape(grid.shape)
+ array([[ 0., 0., 0., 0., 0., 0.],
+ [ 0., 101., 0., 0., 0., 0.],
+ [ 0., 101., 101., 101., 0., 0.],
+ [ 0., 101., 101., 101., 101., 0.],
+ [ 0., 101., 101., 101., 101., 0.],
+ [ 0., 0., 0., 0., 0., 0.]])
+
+ Next, we make a very simple landscape model. We need a few components
+ and we will set include_boundaries to True.
+
+ >>> from landlab.components import FastscapeEroder, FlowAccumulator
+ >>> grid = RasterModelGrid((6, 6), xy_spacing=10)
+ >>> z = grid.add_zeros("topographic__elevation", at="node")
+ >>> param_dict = {
+ ... "faulted_surface": "topographic__elevation",
+ ... "fault_dip_angle": 90.0,
+ ... "fault_throw_rate_through_time": {
+ ... "time": [0, 900, 1000],
+ ... "rate": [0, 0, 0.05],
+ ... },
+ ... "fault_trace": {"y1": 0, "x1": 0, "y2": 30, "x2": 60},
+ ... "include_boundaries": True,
+ ... }
+
+ >>> nf = NormalFault(grid, **param_dict)
+ >>> fr = FlowAccumulator(grid)
+ >>> fs = FastscapeEroder(grid, K_sp=0.01)
+
+ Run this model for 300 100-year timesteps.
+
+ >>> dt = 100.0
+ >>> for i in range(300):
+ ... nf.run_one_step(dt)
+ ... fr.run_one_step()
+ ... fs.run_one_step(dt)
+ ...
+ >>> z.reshape(grid.shape).round(decimals=2)
+ array([[ 0. , 0. , 0. , 0. , 0. , 0. ],
+ [ 5. , 5. , 0. , 0. , 0. , 0. ],
+ [ 7.39, 7.38, 2.38, 2.89, 0. , 0. ],
+ [ 9.36, 11.43, 5.51, 6.42, 3.54, 3.54],
+ [15.06, 15.75, 10.6 , 11.42, 8.54, 8.54],
+ [15.06, 15.06, 10.7 , 11.42, 8.54, 8.54]])
+
+ The faulted nodes have been uplifted and eroded! Note that here the
+ boundary nodes are also uplifted.
+
+ NormalFault keeps track of internal time.
+
+ For example, if a user wanted to only run NormalFault every tenth
+ timestep (or some more seismogenically reasonable set of times).
+
+ >>> grid = RasterModelGrid((6, 6), xy_spacing=10)
+ >>> z = grid.add_zeros("topographic__elevation", at="node")
+ >>> nf = NormalFault(grid, **param_dict)
+ >>> fr = FlowAccumulator(grid)
+ >>> fs = FastscapeEroder(grid, K_sp=0.01)
+ >>> model_time = 0.0
+ >>> dt = 100.0
+ >>> for i in range(300):
+ ... if i % 10 == 0:
+ ... nf.run_one_step(dt * 10)
+ ... fr.run_one_step()
+ ... fs.run_one_step(dt)
+ ... model_time += dt
+ ...
+ >>> model_time
+ 30000.0
+ >>> nf.current_time
+ 30000.0
+ """
+ fault_throw_rate_through_time = dict(fault_throw_rate_through_time)
+ fault_trace = dict(fault_trace)
+
+ super().__init__(grid)
+
+ # save a reference to the grid
+
+ # get the surface to be faulted
+ self._surfaces = {}
+ self._not_yet_instantiated = []
+ if isinstance(faulted_surface, list):
+ # if faulted surface is a list, then itterate through multiple
+ # surfaces and save
+ for surf in faulted_surface:
+ try:
+ self._surfaces[surf] = grid.at_node[surf]
+ except FieldError:
+ self._not_yet_instantiated.append(surf)
+ else:
+ self._surfaces[faulted_surface] = grid.at_node[faulted_surface]
+
+ if fault_dip_angle > 90.0:
+ raise ValueError(
+ "NormaFault fault_dip_angle must be less than 90 " "degrees."
+ )
+
+ # get the fault throw parameter values from the parameter dictionary
+ self._throw_time = np.array(fault_throw_rate_through_time["time"])
+ self._throw_rate = np.array(fault_throw_rate_through_time["rate"])
+ self._fault_dip = np.deg2rad(fault_dip_angle)
+ self._uplift = self._throw_rate * np.sin(self._fault_dip)
+
+ # Identify in current boundaries will be included
+ self._include_boundaries = include_boundaries
+
+ # Instantiate record of current time.
+ self._current_time = 0.0
+
+ # get the fault trace dictionary and use to to calculate where the
+ # faulted nodes are located.
+ self._fault_trace = fault_trace
+ dx = self._fault_trace["x2"] - self._fault_trace["x1"]
+ dy = self._fault_trace["y2"] - self._fault_trace["y1"]
+ self._fault_azimuth = np.mod(np.arctan2(dy, dx), TWO_PI)
+ self._fault_anti_azimuth = self._fault_azimuth + np.pi
+ # deal with the edge case in which dx == 0
+ if dx == 0:
+ self._dy_over_dx = 0.0
+ self._fault_trace_y_intercept = 0.0
+ self._fault_trace_x_intercept = self._fault_trace["x2"]
+ else:
+ self._dy_over_dx = dy / dx
+ self._fault_trace_y_intercept = self._fault_trace["y1"] - (
+ self._dy_over_dx * self._fault_trace["x1"]
+ )
+ self._fault_trace_x_intercept = 0.0
+
+ # set the considered nodes based on whether the boundaries will be
+ # included in the faulted terrain.
+ if self._include_boundaries:
+ potential_nodes = np.arange(self._grid.size("node"))
+ else:
+ potential_nodes = self._grid.core_nodes
+
+ # select those nodes that are on the correct side of the fault
+ dx_pn = self._grid.x_of_node[potential_nodes] - self._fault_trace_x_intercept
+ dy_pn = self._grid.y_of_node[potential_nodes] - self._fault_trace_y_intercept
+ potential_angles = np.mod(np.arctan2(dy_pn, dx_pn), TWO_PI)
+ if self._fault_anti_azimuth <= TWO_PI:
+ faulted_node_ids = potential_nodes[
+ (
+ (potential_angles > self._fault_azimuth)
+ & (potential_angles <= (self._fault_anti_azimuth))
+ )
+ ]
+ else:
+ faulted_node_ids = potential_nodes[
+ (
+ (potential_angles > self._fault_azimuth)
+ | (potential_angles <= np.mod(self._fault_anti_azimuth, TWO_PI))
+ )
+ ]
+
+ # save a n-node array of boolean identifing faulted nodes.
+ self._faulted_nodes = np.zeros(self._grid.size("node"), dtype=bool)
+ self._faulted_nodes[faulted_node_ids] = True
+
+ @property
+ def faulted_nodes(self):
+ """At node array indicating which nodes are on the upthrown block."""
+ return self._faulted_nodes
+
+ def _check_surfaces(self):
+ if len(self._not_yet_instantiated) > 0:
+ still_not_instantiated = []
+ for surf in self._not_yet_instantiated:
+ if surf in self._grid.at_node:
+ self._surfaces[surf] = self._grid.at_node[surf]
+ else:
+ still_not_instantiated.append(surf)
+ self._not_yet_instantiated = still_not_instantiated
+
+ def run_one_earthquake(self, dz):
+ """Run one earthquake with uplift of magnitude ``dz``."""
+ self._check_surfaces()
+
+ # save z before uplift only if using include boundaries.
+ if self._include_boundaries:
+ surfs_before_uplift = {}
+ for surf_name in self._surfaces:
+ surfs_before_uplift[surf_name] = self._surfaces[surf_name].copy()
+
+ # uplift the faulted_nodes
+ for surf_name in self._surfaces:
+ self._surfaces[surf_name][self._faulted_nodes] += dz
+
+ # if faulted nodes includes boundaries we must do some extra work because
+ # landlab components will typically not erode these boundaries. This means
+ # they will be uplifted but not eroded.
+
+ if self._include_boundaries:
+ # here our goal is to set faulted boundaries to average of open
+ # node faulted neighbors
+
+ # create boolean of the faulted boundary nodes
+ faulted_boundaries = self._faulted_nodes.copy()
+ faulted_boundaries[self._grid.core_nodes] = False
+
+ core_nodes = np.zeros(self._grid.size("node"), dtype=bool)
+ core_nodes[self._grid.core_nodes] = True
+
+ neighbor_is_core = core_nodes[self._grid.adjacent_nodes_at_node]
+ neighbor_is_faulted = self._faulted_nodes[self._grid.adjacent_nodes_at_node]
+
+ neighbor_for_averaging = neighbor_is_faulted & neighbor_is_core
+
+ # Identify nodes that have at least one adjacent node that is both
+ # faulted and not a boundary node.
+ # average the pre-uplift topography on those adjacent nodes and assign
+ # to the boundary node.
+ # here we use the pre-uplift elevation because other steps in the model
+ # may diminish this topography.
+
+ averaged = neighbor_for_averaging[faulted_boundaries].sum(axis=1) == 1
+ if any(averaged):
+ averaged_nodes = np.where(faulted_boundaries)[0][np.where(averaged)[0]]
+ for surf_name in self._surfaces:
+ elevations_to_average = surfs_before_uplift[surf_name][
+ self._grid.adjacent_nodes_at_node
+ ]
+ elevations_to_average[self._grid.adjacent_nodes_at_node == -1] = (
+ np.nan
+ )
+ elevations_to_average[~neighbor_for_averaging] = np.nan
+ self._surfaces[surf_name][averaged_nodes] = np.nanmean(
+ elevations_to_average[averaged_nodes], axis=1
+ )
+
+ # identify any boundary nodes that are not being averaged. This will
+ # happen at the corners on RasterModelGrids. Average over adjacent
+ # nodes that are faulted. These nodes will be boundary nodes.
+ # here we use the current topography as we will have just updated the
+ # adjacent nodes in the prior block.
+ if any(~averaged):
+ un_averaged_nodes = np.where(faulted_boundaries)[0][
+ np.where(~averaged)[0]
+ ]
+ for surf_name in self._surfaces:
+ elevations_to_average = self._surfaces[surf_name][
+ self._grid.adjacent_nodes_at_node
+ ]
+ elevations_to_average[self._grid.adjacent_nodes_at_node == -1] = (
+ np.nan
+ )
+ elevations_to_average[~neighbor_is_faulted] = np.nan
+ self._surfaces[surf_name][un_averaged_nodes] = np.nanmean(
+ elevations_to_average[un_averaged_nodes], axis=1
+ )
+
+ def run_one_step(self, dt):
+ """Run_one_step method for NormalFault.
+
+ Parameters
+ ----------
+ dt : float
+ Time increment used to advance the NormalFault component.
+ current_time : float, optional
+ If NormalFault is not being advanced by dt every timestep with all
+ components, its internal time may be incorrect, this can be remedied
+ by providing a value for current time. Default value is None which
+ results in the internal timekeeping not being changed.
+ """
+ # calculate the current uplift rate
+ current_uplift_rate = np.interp(
+ self._current_time, self._throw_time, self._throw_rate
+ )
+
+ # run one earthquake of size current_uplift_rate * dt
+ self.run_one_earthquake(current_uplift_rate * dt)
+
+ # increment time
+ self._current_time += dt
diff --git a/src/landlab/components/overland_flow/generate_overland_flow_implicit_kinwave.py b/src/landlab/components/overland_flow/generate_overland_flow_implicit_kinwave.py
index ee993e1246..3c36f3bdc5 100644
--- a/src/landlab/components/overland_flow/generate_overland_flow_implicit_kinwave.py
+++ b/src/landlab/components/overland_flow/generate_overland_flow_implicit_kinwave.py
@@ -138,10 +138,10 @@ class KinwaveImplicitOverlandFlow(Component):
>>> rg = RasterModelGrid((4, 5), xy_spacing=10.0)
>>> z = rg.add_zeros("topographic__elevation", at="node")
>>> kw = KinwaveImplicitOverlandFlow(rg)
- >>> round(kw.runoff_rate * 1.0e7, 2)
- 2.78
- >>> kw.vel_coef # default value
- 100.0
+ >>> kw.runoff_rate # default value
+ 1.0
+ >>> kw.roughness # default value
+ 0.01
>>> rg.at_node["surface_water__depth"][6:9]
array([0., 0., 0.])
@@ -211,25 +211,24 @@ def __init__(
----------
grid : ModelGrid
Landlab ModelGrid object
- runoff_rate : float, optional (defaults to 1 mm/hr)
- Precipitation rate, mm/hr. The value provided is divided by
- 3600000.0.
- roughness : float, defaults to 0.01
- Manning roughness coefficient; units depend on depth_exp.
- changing_topo : boolean, optional (defaults to False)
+ runoff_rate : array_like of float
+ Precipitation rate, mm/hr.
+ roughness : array_like of float
+ Manning's roughness coefficient(s); units depend on depth_exp.
+ changing_topo : boolean, optional
Flag indicating whether topography changes between time steps
- depth_exp : float (defaults to 1.5)
+ depth_exp : float
Exponent on water depth in velocity equation (3/2 for Darcy/Chezy,
5/3 for Manning)
- weight : float (defaults to 1.0)
+ weight : float
Weighting on depth at new time step versus old time step (1 = all
implicit; 0 = explicit)
"""
super().__init__(grid)
- # Store parameters and do unit conversion
- self._runoff_rate = runoff_rate / 3600000.0 # convert to m/s
- self._vel_coef = 1.0 / roughness # do division now to save time
+ # Store parameters
+ self.runoff_rate = runoff_rate
+ self.roughness = roughness
self._changing_topo = changing_topo
self._depth_exp = depth_exp
self._weight = weight
@@ -255,7 +254,7 @@ def __init__(
# Instantiate flow router
self._flow_accum = FlowAccumulator(
grid,
- "topographic__elevation",
+ surface="topographic__elevation",
flow_director="MFD",
partition_method="square_root_of_slope",
)
@@ -265,29 +264,41 @@ def __init__(
@property
def runoff_rate(self):
- """Runoff rate.
-
- Parameters
- ----------
- runoff_rate : float, optional (defaults to 1 mm/hr)
- Precipitation rate, mm/hr. The value provide is divided by
- 3600000.0.
-
- Returns
- -------
- The current value of the runoff rate.
- """
- return self._runoff_rate
+ """Runoff rate at nodes."""
+ # Return a read-only view of the runoff_rate array
+ read_only_runoff = self._runoff_rate.view()
+ read_only_runoff.flags["WRITEABLE"] = False
+ return read_only_runoff
@runoff_rate.setter
def runoff_rate(self, new_rate):
- assert new_rate > 0
- self._runoff_rate = new_rate / 3600000.0 # convert to m/s
+ new_rate = np.array(new_rate)
+ if new_rate.size == 1:
+ if new_rate < 0.0:
+ raise ValueError("runoff_rate must be positive")
+ else:
+ if np.any(new_rate[self._grid.core_nodes] < 0.0):
+ raise ValueError("runoff_rate must be positive")
+ self._runoff_rate = new_rate
@property
- def vel_coef(self):
- """Velocity coefficient."""
- return self._vel_coef
+ def roughness(self):
+ """Roughness at nodes."""
+ # Return a read-only view of the roughness array
+ read_only_roughness = self._roughness.view()
+ read_only_roughness.flags["WRITEABLE"] = False
+ return read_only_roughness
+
+ @roughness.setter
+ def roughness(self, new_rough):
+ new_rough = np.array(new_rough)
+ if new_rough.size == 1:
+ if new_rough < 0.0:
+ raise ValueError("roughness must be positive")
+ else:
+ if np.any(new_rough[self._grid.core_nodes] < 0.0):
+ raise ValueError("roughness must be positive")
+ self._roughness = new_rough
@property
def depth(self):
@@ -310,7 +321,7 @@ def run_one_step(self, dt):
# Re-route flow, which gives us the downstream-to-upstream
# ordering
- self._flow_accum.run_one_step()
+ self._flow_accum.accumulate_flow()
self._nodes_ordered = self._grid.at_node["flow__upstream_node_order"]
self._flow_lnks = self._grid.at_node["flow__link_to_receiver_node"]
@@ -328,11 +339,18 @@ def run_one_step(self, dt):
#
# $\alpha = \frac{\Sigma W S^{1/2} \Delta t}{A C_r}$
cores = self._grid.core_nodes
+
+ # Calculate alpha; try for roughness as a float, else as array of floats
+ if np.ndim(self._roughness) == 0:
+ roughness_at_core_nodes = self._roughness
+ else:
+ roughness_at_core_nodes = self._roughness[cores]
+
self._alpha[cores] = (
- self._vel_coef
- * self._grad_width_sum[cores]
+ self._grad_width_sum[cores]
* dt
/ (self._grid.area_of_cell[self._grid.cell_at_node[cores]])
+ / roughness_at_core_nodes
)
# Zero out inflow discharge
@@ -345,11 +363,20 @@ def run_one_step(self, dt):
# Solve for new water depth
aa = self._alpha[n]
cc = self._depth[n]
- ee = (dt * self._runoff_rate) + (
+
+ # Calculate parameter ee; try for runoff_rate as a float, else as
+ # array of floats
+ if np.ndim(self._runoff_rate) == 0:
+ runoff_at_nodes = self._runoff_rate / 3.6e6
+ else:
+ runoff_at_nodes = self._runoff_rate[n] / 3.6e6
+
+ ee = (dt * runoff_at_nodes) + (
dt
* self._disch_in[n]
/ self._grid.area_of_cell[self._grid.cell_at_node[n]]
)
+
self._depth[n] = newton(
water_fn,
self._depth[n],
@@ -358,8 +385,17 @@ def run_one_step(self, dt):
# Calc outflow
Heff = self._weight * self._depth[n] + (1.0 - self._weight) * cc
+
+ # Calculate outflow; try for roughness as a float, else as array of floats
+ if np.ndim(self._roughness) == 0:
+ roughness_at_nodes = self._roughness
+ else:
+ roughness_at_nodes = self._roughness[n]
+
outflow = (
- self._vel_coef * (Heff**self._depth_exp) * self._grad_width_sum[n]
+ (Heff**self._depth_exp)
+ * self._grad_width_sum[n]
+ / roughness_at_nodes
) # this is manning/chezy/darcy
# Send flow downstream. Here we take total inflow discharge
@@ -379,9 +415,3 @@ def run_one_step(self, dt):
# depth, but it does not provide any information about flow
# velocity or discharge on links. This could be added as an
# optional method, perhaps done just before output.
-
-
-if __name__ == "__main__":
- import doctest
-
- doctest.testmod()
diff --git a/src/landlab/components/priority_flood_flow_router/README.md b/src/landlab/components/priority_flood_flow_router/README.md
index 8374ab580e..89e1f83df8 100644
--- a/src/landlab/components/priority_flood_flow_router/README.md
+++ b/src/landlab/components/priority_flood_flow_router/README.md
@@ -11,13 +11,13 @@ FlowDirAccPf is introduced [in this paper]()
## Documentation and installation
-Landlab documentation is hosted on this [ReadTheDocs page](https://landlab.readthedocs.io/en/release),
+Landlab documentation is hosted on this [ReadTheDocs page](https://landlab.csdms.io/),
including instructions to install Landlab. ``FlowDirAccPf`` is installed with
Landlab.
#TODO
-``FlowDirAccPf`` documentation is located [here](https://landlab.readthedocs.io/en/release/reference/components/FlowDirAccPf.html).
+``FlowDirAccPf`` documentation is located [here](https://landlab.csdms.io/generated/api/landlab.components.priority_flood_flow_router.priority_flood_flow_router.html).
## FlowDirAccPf tutorial
@@ -29,7 +29,7 @@ through the following links:
- [Launch the tutorial](https://mybinder.org/v2/gh/BCampforts/landlab/blob/bc/priority_flood/notebooks/tutorials/PriorityFlood/PriorityFlood_realDEMs.ipynb)
as interactive notebook in your browser, with no need to install software,
launched using Binder.
-- [A static version of the same tutorial](https://nbviewer.jupyter.org/github/BCampforts/landlab/blob/bc/priority_flood/notebooks/tutorials/PriorityFlood/PriorityFlood_realDEMs.ipynb)
+- [A static version of the same tutorial](https://landlab.csdms.io/tutorials/flow_direction_and_accumulation/PriorityFlood_realDEMs.html)
- All Landlab tutorials can be launched from [this directory](https://mybinder.org/v2/gh/landlab/landlab/release?filepath=notebooks/welcome.ipynb) using Binder.
## Get or give help
diff --git a/src/landlab/components/river_flow_dynamics/__init__.py b/src/landlab/components/river_flow_dynamics/__init__.py
new file mode 100644
index 0000000000..a93c0924d0
--- /dev/null
+++ b/src/landlab/components/river_flow_dynamics/__init__.py
@@ -0,0 +1,3 @@
+from .river_flow_dynamics import RiverFlowDynamics
+
+__all__ = ["RiverFlowDynamics"]
diff --git a/src/landlab/components/river_flow_dynamics/river_flow_dynamics.py b/src/landlab/components/river_flow_dynamics/river_flow_dynamics.py
new file mode 100644
index 0000000000..a8a7c6b4fd
--- /dev/null
+++ b/src/landlab/components/river_flow_dynamics/river_flow_dynamics.py
@@ -0,0 +1,1743 @@
+"""Simulate surface fluid flow based on Casulli and Cheng (1992).
+
+This component implements a semi-implicit, semi-Lagrangian finite-volume approximation of
+the depth-averaged shallow water equations originally proposed by Casulli and Cheng in 1992,
+and subsequent related work.
+
+Written by Sebastian Bernal and Angel Monsalve.
+
+Examples
+--------
+
+This example demonstrates basic usage of the RiverFlowDynamics component to simulate
+a simple channel flow:
+
+>>> import numpy as np
+>>> from landlab import RasterModelGrid
+>>> from landlab.components import RiverFlowDynamics
+
+Create a small grid for demonstration purposes:
+
+>>> grid = RasterModelGrid((8, 6), xy_spacing=0.1)
+
+Set up a sloped channel with elevated sides (slope of 0.01).
+
+>>> z = grid.add_zeros("topographic__elevation", at="node")
+>>> z += 0.005 - 0.01 * grid.x_of_node
+>>> z[grid.y_of_node > 0.5] = 1.0
+>>> z[grid.y_of_node < 0.2] = 1.0
+
+Instantiating the Component. To check the names of the required inputs, use
+the 'input_var_names' class property.
+
+>>> RiverFlowDynamics.input_var_names
+('surface_water__depth',
+ 'surface_water__elevation',
+ 'surface_water__velocity',
+ 'topographic__elevation')
+
+Initialize required fields:
+
+>>> h = grid.add_zeros("surface_water__depth", at="node")
+>>> vel = grid.add_zeros("surface_water__velocity", at="link")
+>>> wse = grid.add_zeros("surface_water__elevation", at="node")
+>>> wse += h + z
+
+Set up inlet boundary conditions (left side of channel):
+Water flows from left to right at a depth of 0.5 meters with a velocity of 0.45 m/s.
+
+>>> fixed_entry_nodes = np.arange(12, 36, 6)
+>>> fixed_entry_links = grid.links_at_node[fixed_entry_nodes][:, 0]
+>>> entry_nodes_h_values = np.full(4, 0.5)
+>>> entry_links_vel_values = np.full(4, 0.45)
+
+Instantiate 'RiverFlowDynamics'
+
+>>> rfd = RiverFlowDynamics(
+... grid,
+... dt=0.1,
+... mannings_n=0.012,
+... fixed_entry_nodes=fixed_entry_nodes,
+... fixed_entry_links=fixed_entry_links,
+... entry_nodes_h_values=entry_nodes_h_values,
+... entry_links_vel_values=entry_links_vel_values,
+... )
+
+Run the simulation for 100 timesteps (equivalent to 10 seconds).
+
+>>> n_timesteps = 100
+>>> for timestep in range(n_timesteps):
+... rfd.run_one_step()
+...
+
+Examine the flow depth at the center of the channel after 10 seconds.
+
+>>> flow_depth = np.reshape(grid["node"]["surface_water__depth"], (8, 6))[3, :]
+>>> np.round(flow_depth, 3)
+array([0.5 , 0.5 , 0.5 , 0.501, 0.502, 0.502])
+
+And the velocity at links along the center of the channel.
+
+>>> linksAtCenter = grid.links_at_node[np.array(np.arange(24, 30))][:-1, 0]
+>>> flow_velocity = grid["link"]["surface_water__velocity"][linksAtCenter]
+>>> np.round(flow_velocity, 3)
+array([0.45 , 0.457, 0.455, 0.452, 0.453])
+
+"""
+
+import numpy as np
+import scipy as sp
+
+from landlab import Component
+
+
+class RiverFlowDynamics(Component):
+ """Simulate surface fluid flow based on Casulli and Cheng (1992).
+
+ This Landlab component simulates surface fluid flow using the approximations of the
+ 2D shallow water equations developed by Casulli and Cheng in 1992. It calculates water
+ depth and velocity across the raster grid, given a specific input discharge.
+
+ References
+ ----------
+ **Required Software Citation(s) Specific to this Component**
+
+ None Listed
+
+ **Additional References**
+
+ Casulli, V., Cheng, R.T. (1992). “Semi-implicit finite difference methods for
+ three-dimensional shallow water flow”. International Journal for Numerical Methods
+ in Fluids. 15: 629-648.
+ https://doi.org/10.1002/fld.1650150602
+ """
+
+ _name = "RiverFlowDynamics"
+
+ _unit_agnostic = False
+
+ _info = {
+ "surface_water__depth": {
+ "dtype": float,
+ "intent": "inout",
+ "optional": False,
+ "units": "m",
+ "mapping": "node",
+ "doc": "Depth of water on the surface",
+ },
+ "surface_water__velocity": {
+ "dtype": float,
+ "intent": "inout",
+ "optional": False,
+ "units": "m/s",
+ "mapping": "link",
+ "doc": "Speed of water flow above the surface",
+ },
+ "surface_water__elevation": {
+ "dtype": float,
+ "intent": "inout",
+ "optional": False,
+ "units": "m",
+ "mapping": "node",
+ "doc": "Water surface elevation at time N",
+ },
+ "topographic__elevation": {
+ "dtype": float,
+ "intent": "in",
+ "optional": False,
+ "units": "m",
+ "mapping": "node",
+ "doc": "Land surface topographic elevation",
+ },
+ }
+
+ def __init__(
+ self,
+ grid,
+ dt=0.01, # Sets the time step (s)
+ eddy_viscosity=1e-4, # ddy viscosity coefficient
+ mannings_n=0.012, # Manning's n
+ threshold_depth=0.01, # Sets the wet/dry threshold
+ theta=0.5, # Degree of 'implicitness' of the solution
+ fixed_entry_nodes=None, # Node IDs where flow enters the domain
+ fixed_entry_links=None, # Link IDs where flow enters the domain
+ entry_nodes_h_values=None, # Water depth at nodes where flow enters the domain
+ entry_links_vel_values=None, # Water velocity at links where flow enters the domain
+ pcg_tolerance=1e-05, # Preconditioned Conjugate Gradient convergence tolerance
+ pcg_max_iterations=None, # Preconditioned Conjugate Gradient max iterations
+ surface_water__elevation_at_N_1=0.0, # Surf water elev at prev. time
+ surface_water__elevation_at_N_2=0.0, # Surf water elev at prev prev time
+ surface_water__velocity_at_N_1=0.0, # Speed of water at prev time
+ ):
+ """Simulate the vertical-averaged surface fluid flow
+
+ Simulate vertical-averaged surface fluid flow using the Casulli and Cheng (1992)
+ approximations of the 2D shallow water equations. This Landlab component calculates
+ water depth and velocity across the raster grid based on a given input discharge.
+
+ Parameters
+ ----------
+ grid : RasterModelGrid
+ A grid.
+ dt : float, optional
+ Time step in seconds. If not provided, it is calculated from the CFL condition.
+ eddy_viscosity : float, optional
+ Eddy viscosity coefficient. Default = 1e-4 :math:`m^2 / s`
+ mannings_n : float or array_like, optional
+ Manning's roughness coefficient. Default = 0.012 :math:`s / m^1/3`
+ threshold_depth : float, optional
+ Threshold at which a cell is considered wet. Default = 0.01 m
+ theta : float, optional
+ Degree of 'implicitness' of the solution, ranging between 0.5 and 1.0.
+ Default: 0.5. When set to 0.5, the approximation is centered in time;
+ when set to 1.0, it is fully implicit.
+ fixed_entry_nodes : array_like or None, optional
+ Node IDs where flow enters the domain (Dirichlet boundary condition).
+ If not provided, existing water in the domain is not renewed.
+ fixed_entry_links : array_like or None, optional
+ Link IDs where flow enters the domain (Dirichlet boundary condition).
+ If not provided, existing water in the domain is not renewed.
+ entry_nodes_h_values : array_like, optional
+ Water depth values at nodes where flow enters the domain
+ (Dirichlet boundary condition).
+ If not provided, existing water in the domain is not renewed.
+ entry_links_vel_values : array_like, optional
+ Water velocity values at links where flow enters the domain
+ (Dirichlet boundary condition).
+ If not provided, existing water in the domain is not renewed.
+ pcg_tolerance : float, optional
+ Tolerance for convergence in the Preconditioned Conjugate Gradient
+ method. Default: 1e-05.
+ pcg_max_iterations : integer, optional
+ Maximum number of iterations for the Preconditioned Conjugate Gradient
+ method. Iteration stops after maxiter steps, even if the specified
+ tolerance is not achieved. Default: None.
+ surface_water__elevation_at_N_1: array_like of float, optional
+ Water surface elevation at nodes at time N-1 [m].
+ surface_water__elevation_at_N_2: array_like of float, optional
+ Water surface elevation at nodes at time N-2 [m].
+ surface_water__velocity_at_N_1: array_like of float, optional
+ Speed of water flow at links above the surface at time N-1 [m/s].
+ """
+ super().__init__(grid)
+
+ # User inputs
+ self._dt = dt
+ self._eddy_viscosity = eddy_viscosity
+ self._g = sp.constants.g
+ self._mannings_n = mannings_n
+ self._threshold_depth = threshold_depth
+ self._theta = theta
+ self._pcg_tolerance = pcg_tolerance
+ self._pcg_max_iterations = pcg_max_iterations
+
+ # Getting topography for further calculations
+ self._additional_z = 10 # To set the virtual reference elevation (z=0)
+ self._max_elevation = self._grid.at_node["topographic__elevation"].max()
+ self._z = (
+ self._max_elevation
+ + self._additional_z
+ - self._grid.at_node["topographic__elevation"]
+ )
+
+ self._fixed_entry_nodes = [] if fixed_entry_nodes is None else fixed_entry_nodes
+ self._fixed_entry_links = [] if fixed_entry_links is None else fixed_entry_links
+ self._entry_nodes_h_values = (
+ [] if entry_nodes_h_values is None else entry_nodes_h_values
+ )
+ self._entry_links_vel_values = (
+ [] if entry_links_vel_values is None else entry_links_vel_values
+ )
+
+ # Creating fields if they don't exist
+ if "surface_water__depth" not in self.grid.at_node:
+ grid.add_zeros(
+ "surface_water__depth",
+ at="node",
+ units=self._info["surface_water__depth"]["units"],
+ )
+
+ if "surface_water__velocity" not in self.grid.at_link:
+ grid.add_zeros(
+ "surface_water__velocity",
+ at="link",
+ units=self._info["surface_water__velocity"]["units"],
+ )
+
+ if "surface_water__elevation" not in self.grid.at_node:
+ grid.add_field(
+ "surface_water__elevation",
+ self.grid.at_node["surface_water__depth"] - self._z,
+ at="node",
+ units=self._info["surface_water__elevation"]["units"],
+ )
+
+ self._surface_water__elevation_at_N_1 = np.broadcast_to(
+ np.asarray(surface_water__elevation_at_N_1).flat, grid.number_of_nodes
+ )
+
+ self._surface_water__elevation_at_N_2 = np.broadcast_to(
+ np.asarray(surface_water__elevation_at_N_2).flat, grid.number_of_nodes
+ )
+
+ self._surface_water__velocity_at_N_1 = np.broadcast_to(
+ np.asarray(surface_water__velocity_at_N_1).flat, grid.number_of_links
+ )
+
+ # Assigning a class variable to the fields
+ self._h = self._grid.at_node["surface_water__depth"]
+ self._vel = self._grid.at_link["surface_water__velocity"]
+ self._vel_at_N_1 = self._surface_water__velocity_at_N_1
+ self._eta = self._grid.at_node["surface_water__elevation"] - (
+ self._max_elevation + self._additional_z
+ )
+ self._eta_at_N_1 = self._surface_water__elevation_at_N_1 - (
+ self._max_elevation + self._additional_z
+ )
+ self._eta_at_N_2 = self._surface_water__elevation_at_N_2 - (
+ self._max_elevation + self._additional_z
+ )
+
+ # Open boundary conditions
+ # water can leave the domain at everywhere, only limited by topography
+ self.grid.status_at_node[self.grid.nodes_at_left_edge] = (
+ self._grid.BC_NODE_IS_FIXED_VALUE
+ )
+ self.grid.status_at_node[self.grid.nodes_at_right_edge] = (
+ self._grid.BC_NODE_IS_FIXED_VALUE
+ )
+ self.grid.status_at_node[self.grid.nodes_at_bottom_edge] = (
+ self._grid.BC_NODE_IS_FIXED_VALUE
+ )
+ self.grid.status_at_node[self.grid.nodes_at_top_edge] = (
+ self._grid.BC_NODE_IS_FIXED_VALUE
+ )
+
+ self._adjacent_nodes_at_corner_nodes = np.array(
+ [
+ # Top right
+ [self.grid.nodes_at_top_edge[-2], self.grid.nodes_at_right_edge[-2]],
+ # Top left
+ [self.grid.nodes_at_top_edge[1], self.grid.nodes_at_left_edge[-2]],
+ # Bottom left
+ [self.grid.nodes_at_left_edge[1], self.grid.nodes_at_bottom_edge[1]],
+ # Bottom right
+ [self.grid.nodes_at_right_edge[1], self.grid.nodes_at_bottom_edge[-2]],
+ ]
+ )
+
+ # Updating open boundary nodes/links
+ self._open_boundary_nodes = self._grid.boundary_nodes
+ self._open_boundary_links = np.unique(
+ self._grid.links_at_node[self._open_boundary_nodes]
+ )
+
+ self._open_boundary_nodes = np.setdiff1d(
+ self._open_boundary_nodes, self._fixed_entry_nodes
+ )
+ self._open_boundary_links = np.setdiff1d(
+ self._open_boundary_links, self._fixed_entry_links
+ )
+
+ self._fixed_corner_nodes = np.setdiff1d(
+ self.grid.corner_nodes, self._open_boundary_nodes
+ )
+ self._open_corner_nodes = np.setdiff1d(
+ self.grid.corner_nodes, self._fixed_corner_nodes
+ )
+
+ self._open_boundary_nodes = np.setdiff1d(
+ self._open_boundary_nodes, self._open_corner_nodes
+ )
+
+ # Using fixed entry nodes/links only when they exist
+ self._fixed_nodes_exist = len(self._fixed_entry_nodes) > 0
+ self._fixed_links_exist = len(self._fixed_entry_links) > 0
+
+ # Updating grid fixed values according to the user input
+ if self._fixed_nodes_exist:
+ self._h[self._fixed_entry_nodes] = entry_nodes_h_values
+ self._eta[self._fixed_entry_nodes] = (
+ entry_nodes_h_values - self._z[self._fixed_entry_nodes]
+ )
+ if self._fixed_links_exist:
+ self._vel[self._fixed_entry_links] = entry_links_vel_values
+
+ # Mapping node values at links
+ self._z_at_links = self._grid.map_mean_of_link_nodes_to_link(self._z)
+ self._h_at_links = self._grid.map_mean_of_link_nodes_to_link(self._h)
+ self._eta_at_links = self._h_at_links - self._z_at_links
+
+ # Passing values to the time step N
+ self._h_at_N = self._h.copy()
+ self._h_at_N_at_links = self._grid.map_mean_of_link_nodes_to_link(self._h_at_N)
+
+ self._vel_at_N = self._vel.copy()
+ self._eta_at_N = self._eta.copy()
+
+ # Boolean for wet nodes/links
+ self._wet_nodes = np.where(self._h_at_N >= self._threshold_depth, True, False)
+ self._wet_links = np.where(
+ self._h_at_N_at_links >= self._threshold_depth, True, False
+ )
+
+ # Defining some functions
+ def find_nearest_link(self, x_coordinates, y_coordinates, objective_links="all"):
+ """Link nearest a point.
+
+ Find the index to the link nearest the given x, y coordinates.
+ Returns the indices of the links nearest the given coordinates.
+
+ """
+ # Defining the set of links that are going to be used
+ if objective_links == "all":
+ objective_links = np.arange(self._grid.number_of_links)
+ elif objective_links == "horizontal":
+ objective_links = self.grid.horizontal_links
+ elif objective_links == "vertical":
+ objective_links = self.grid.vertical_links
+ # if (objective_links == "all") END
+
+ # Coordinates of all the RasterModelGrid links
+ x_of_objective_links = np.unique(self._grid.xy_of_link[objective_links][:, 0])
+ y_of_objective_links = np.unique(self._grid.xy_of_link[objective_links][:, 1])
+
+ # Getting the closest link-coordinate to the exit point
+ tempCalc1 = np.repeat(x_coordinates, len(x_of_objective_links)).reshape(
+ len(x_coordinates), len(x_of_objective_links)
+ )
+ tempCalc2 = np.tile(x_of_objective_links, len(x_coordinates)).reshape(
+ len(x_coordinates), len(x_of_objective_links)
+ )
+ indices = abs(tempCalc2 - tempCalc1).argmin(axis=1)
+ nearest_x = x_of_objective_links[indices]
+
+ tempCalc1 = np.repeat(y_coordinates, len(y_of_objective_links)).reshape(
+ len(y_coordinates), len(y_of_objective_links)
+ )
+ tempCalc2 = np.tile(y_of_objective_links, len(y_coordinates)).reshape(
+ len(y_coordinates), len(y_of_objective_links)
+ )
+ indices = abs(tempCalc2 - tempCalc1).argmin(axis=1)
+ nearest_y = y_of_objective_links[indices]
+
+ # Getting the closest link to link
+ tempCalc1 = np.repeat(
+ nearest_x, len(self._grid.xy_of_link[objective_links][:, 0])
+ ).reshape(len(nearest_x), len(self._grid.xy_of_link[objective_links][:, 0]))
+ tempCalc2 = np.tile(
+ self._grid.xy_of_link[objective_links][:, 0], len(x_coordinates)
+ ).reshape(len(x_coordinates), len(self._grid.xy_of_link[objective_links][:, 0]))
+ tempB1 = tempCalc1 == tempCalc2
+
+ tempCalc1 = np.repeat(
+ nearest_y, len(self._grid.xy_of_link[objective_links][:, 1])
+ ).reshape(len(nearest_y), len(self._grid.xy_of_link[objective_links][:, 1]))
+ tempCalc2 = np.tile(
+ self._grid.xy_of_link[objective_links][:, 1], len(y_coordinates)
+ ).reshape(len(y_coordinates), len(self._grid.xy_of_link[objective_links][:, 1]))
+ tempB2 = tempCalc1 == tempCalc2
+
+ tempCalc3 = (
+ np.repeat(objective_links, len(x_coordinates))
+ .reshape((len(objective_links), len(y_coordinates)))
+ .T
+ )
+ nearest_link = tempCalc3[tempB1 * tempB2]
+
+ return nearest_link.astype(int)
+
+ def find_adjacent_links_at_link(self, current_link, objective_links="horizontal"):
+ """Get adjacent links to the link.
+
+ This function finds the links at right, above, left and below the given link.
+ Similar purpose to the "adjacent_nodes_at_node" function.
+ Return the adjacent links in as many rows as given links.
+ Link IDs are returned as columns in clock-wise order starting from East (E, N, W, S).
+
+ """
+
+ # Defining the set of links that are going to be used
+ if objective_links == "horizontal":
+ objective_links = self.grid.horizontal_links
+ reshape_pair = (self.grid.shape[0], self.grid.shape[1] - 1)
+ elif objective_links == "vertical":
+ objective_links = self.grid.vertical_links
+ reshape_pair = (self.grid.shape[0] - 1, self.grid.shape[1])
+ # if (objective_links == "horizontal") END
+
+ # Coordinates of the current link
+ x_of_current_links = self._grid.xy_of_link[current_link][:, 0]
+ y_of_current_links = self._grid.xy_of_link[current_link][:, 1]
+
+ # Coordinates of all the RasterModelGrid links
+ x_of_objective_links = np.unique(self._grid.xy_of_link[objective_links][:, 0])
+ y_of_objective_links = np.unique(self._grid.xy_of_link[objective_links][:, 1])
+
+ # Getting links that share the same y-coordinates
+ # The following matrices are built to be compared to each other.
+ # tempCalc1 repeats "y_of_current_links" for every x-coordinate in
+ # "objective_links": cols = "y_of_current_links"
+ # tempCalc2 repeats "y_of_objective_links" for every x-coordinate in
+ # the "current_link": rows = "y_of_objective_links"
+ # tempCalc3 give us the index to extract all the objective links that
+ # are located in the same row than the current link: rows = [0, 1, 2, ...]
+ tempCalc1 = np.repeat(y_of_current_links, len(y_of_objective_links)).reshape(
+ len(y_of_current_links), len(y_of_objective_links)
+ )
+ tempCalc2 = np.tile(y_of_objective_links, len(y_of_current_links)).reshape(
+ len(y_of_current_links), len(y_of_objective_links)
+ )
+ tempCalc3 = (
+ np.repeat(np.arange(len(y_of_objective_links)), len(y_of_current_links))
+ .reshape(len(y_of_objective_links), len(y_of_current_links))
+ .T
+ )
+
+ indices = tempCalc3[tempCalc1 == tempCalc2]
+ links_at_same_rows = objective_links.reshape(reshape_pair)[indices, :]
+ links_at_same_rows = np.append(
+ np.array([-np.ones_like(current_link)]).T, links_at_same_rows, axis=1
+ )
+ links_at_same_rows = np.append(
+ links_at_same_rows, np.array([-np.ones_like(current_link)]).T, axis=1
+ )
+
+ # Getting links that share the same x-coordinates
+ # The following matrices are built to be compared to each other.
+ # tempCalc1 repeats "x_of_current_links" for every x-coordinate in
+ # "objective_links": cols = "x_of_current_links"
+ # tempCalc2 repeats "x_of_objective_links" for every x-coordinate in
+ # the "current_link": rows = "x_of_objective_links"
+ # tempCalc3 give us the index to extract all the objective links that
+ # are located in the same row than the current link: rows = [0, 1, 2, ...]
+ tempCalc1 = np.repeat(x_of_current_links, len(x_of_objective_links)).reshape(
+ len(x_of_current_links), len(x_of_objective_links)
+ )
+ tempCalc2 = np.tile(x_of_objective_links, len(x_of_current_links)).reshape(
+ len(x_of_current_links), len(x_of_objective_links)
+ )
+ tempCalc3 = (
+ np.repeat(np.arange(len(x_of_objective_links)), len(x_of_current_links))
+ .reshape(len(x_of_objective_links), len(x_of_current_links))
+ .T
+ )
+
+ indices = tempCalc3[tempCalc1 == tempCalc2]
+ links_at_same_cols = objective_links.reshape(reshape_pair)[:, indices].T
+ links_at_same_cols = np.append(
+ np.array([-np.ones_like(current_link)]).T, links_at_same_cols, axis=1
+ )
+ links_at_same_cols = np.append(
+ links_at_same_cols, np.array([-np.ones_like(current_link)]).T, axis=1
+ )
+
+ # Extracing the adjacent links to current link (E,N,W,S)
+ adjacent_links_at_link = np.zeros((current_link.shape[0], 4))
+
+ # Rows (E,W)
+ tempCalc1 = np.repeat(current_link, links_at_same_rows.shape[1]).reshape(
+ current_link.shape[0], links_at_same_rows.shape[1]
+ )
+ tempCalc2 = (
+ np.repeat(np.arange(links_at_same_rows.shape[1]), current_link.shape[0])
+ .reshape(links_at_same_rows.shape[1], current_link.shape[0])
+ .T
+ )
+ tempCalc3 = tempCalc2[tempCalc1 == links_at_same_rows]
+
+ adjacent_links_at_link[:, 0] = links_at_same_rows[
+ (range(links_at_same_rows.shape[0])), (tempCalc3 + 1)
+ ]
+ adjacent_links_at_link[:, 2] = links_at_same_rows[
+ (range(links_at_same_rows.shape[0])), (tempCalc3 - 1)
+ ]
+
+ # Cols (N,S)
+ tempCalc1 = np.repeat(current_link, links_at_same_cols.shape[1]).reshape(
+ current_link.shape[0], links_at_same_cols.shape[1]
+ )
+ tempCalc2 = (
+ np.repeat(np.arange(links_at_same_cols.shape[1]), current_link.shape[0])
+ .reshape(links_at_same_cols.shape[1], current_link.shape[0])
+ .T
+ )
+ tempCalc3 = tempCalc2[tempCalc1 == links_at_same_cols]
+
+ adjacent_links_at_link[:, 1] = links_at_same_cols[
+ (range(links_at_same_cols.shape[0])), (tempCalc3 + 1)
+ ]
+ adjacent_links_at_link[:, 3] = links_at_same_cols[
+ (range(links_at_same_cols.shape[0])), (tempCalc3 - 1)
+ ]
+
+ return adjacent_links_at_link.astype(int)
+
+ def path_line_tracing(self):
+ """ " Path line tracing algorithm.
+
+ This function implements the semi-analytical path line tracing method
+ of Pollock (1988).
+
+ The semi-analytical path line tracing method was developed for particle
+ tracking in ground water flow models. The assumption that each directional
+ velocity component varies linearly in its coordinate directions within
+ each computational volume or cell underlies the method.
+ Linear variation allows the derivation of an analytical expression for
+ the path line of a particle across a volume.
+
+ Given an initial point located at each volume faces of the domain, particle
+ trayectories are traced backwards on time. Then, this function returns
+ the departure point of the particle at the beginning of the time step.
+ """
+ dx, dy = self.grid.dx, self.grid.dy
+
+ # Calculating the partial time-step TAUx, TAUy, dt - sum_partial_times
+ sum_partial_times = np.zeros_like(self._u_vel_of_particle)
+ remaining_time = self._dt - sum_partial_times
+ keep_tracing = np.where(remaining_time > 0, True, False)
+
+ while np.any(remaining_time > 0):
+ # Using the previous exit point as the new entry point
+ self._x_of_particle = np.where(
+ keep_tracing, self._x_at_exit_point, self._x_of_particle
+ )
+ self._y_of_particle = np.where(
+ keep_tracing, self._y_at_exit_point, self._y_of_particle
+ )
+
+ # Checking if the particles departs (backwards) from a link position (True)
+ tempBx = np.isin(
+ self._x_of_particle, self._grid.xy_of_link[self.grid.active_links][:, 0]
+ ) # Particles located on horizontal-links/vertical-faces
+ tempBy = np.isin(
+ self._y_of_particle, self._grid.xy_of_link[self.grid.active_links][:, 1]
+ ) # Particles located on vertical-links/horizontal-faces
+
+ # True, particles depart from link positions.
+ # False, particles depart from random locations inside a cell
+ tempBxy = tempBx + tempBy
+
+ # Getting surrounding links for particles located inside a cell
+ tempCalc1 = np.append(
+ np.array([self._x_of_particle]), np.array([self._y_of_particle]), axis=0
+ )
+ tempCalc2 = self._grid.find_nearest_node(tempCalc1, mode="raise")
+ temp_links_from_node = self._grid.links_at_node[tempCalc2]
+ nodes_from_particle = tempCalc2
+
+ # Getting surrounding links for particles located at link positions
+ tempCalc1 = np.where(
+ self._u_vel_of_particle >= 0,
+ np.array([self._x_of_particle]) - dx / 10,
+ np.array([self._x_of_particle]) + dx / 10,
+ )
+ tempCalc2 = np.where(
+ self._v_vel_of_particle >= 0,
+ np.array([self._y_of_particle]) - dy / 10,
+ np.array([self._y_of_particle]) + dy / 10,
+ )
+ tempCalc3 = np.append(tempCalc1, tempCalc2, axis=0)
+ tempCalc4 = self._grid.find_nearest_node(tempCalc3, mode="raise")
+ temp_links_from_link = self._grid.links_at_node[tempCalc4]
+ nodes_from_particle = np.where(tempBxy, tempCalc4, nodes_from_particle)
+
+ # Getting links around particle
+ tempBxy = np.tile(tempBxy, 4).reshape(4, len(tempBxy)).T
+ links_at_particle = np.where(
+ tempBxy, temp_links_from_link, temp_links_from_node
+ )
+
+ # Defining links based on velocity direction
+ link_at_x2 = np.where(
+ self._u_vel_of_particle >= 0,
+ links_at_particle[:, 0],
+ links_at_particle[:, 2],
+ )
+ link_at_x1 = np.where(
+ self._u_vel_of_particle >= 0,
+ links_at_particle[:, 2],
+ links_at_particle[:, 0],
+ )
+ link_at_y2 = np.where(
+ self._v_vel_of_particle >= 0,
+ links_at_particle[:, 1],
+ links_at_particle[:, 3],
+ )
+ link_at_y1 = np.where(
+ self._v_vel_of_particle >= 0,
+ links_at_particle[:, 3],
+ links_at_particle[:, 1],
+ )
+
+ x_at_x2 = np.where(
+ self._u_vel_of_particle >= 0,
+ self._grid.x_of_node[nodes_from_particle] + dx / 2,
+ self._grid.x_of_node[nodes_from_particle] - dx / 2,
+ )
+ x_at_x1 = np.where(
+ self._u_vel_of_particle >= 0,
+ self._grid.x_of_node[nodes_from_particle] - dx / 2,
+ self._grid.x_of_node[nodes_from_particle] + dx / 2,
+ )
+ y_at_y2 = np.where(
+ self._v_vel_of_particle >= 0,
+ self._grid.y_of_node[nodes_from_particle] + dy / 2,
+ self._grid.y_of_node[nodes_from_particle] - dy / 2,
+ )
+ y_at_y1 = np.where(
+ self._v_vel_of_particle >= 0,
+ self._grid.y_of_node[nodes_from_particle] - dy / 2,
+ self._grid.y_of_node[nodes_from_particle] + dy / 2,
+ )
+
+ # Getting velocity around the particle
+ u_vel_at_x2 = np.where(
+ link_at_x2 >= 0, self._vel_at_N[link_at_x2], self._vel_at_N[link_at_x1]
+ )
+ u_vel_at_x1 = np.where(
+ link_at_x1 >= 0, self._vel_at_N[link_at_x1], self._vel_at_N[link_at_x2]
+ )
+ v_vel_at_y2 = np.where(
+ link_at_y2 >= 0, self._vel_at_N[link_at_y2], self._vel_at_N[link_at_y1]
+ )
+ v_vel_at_y1 = np.where(
+ link_at_y1 >= 0, self._vel_at_N[link_at_y1], self._vel_at_N[link_at_y2]
+ )
+
+ # Calculating gradients for path line tracing
+ gradient_x_direction = (u_vel_at_x2 - u_vel_at_x1) / dx
+ gradient_y_direction = (v_vel_at_y2 - v_vel_at_y1) / dy
+
+ # Calculating entry velocity for each particle
+ self._u_vel_of_particle = u_vel_at_x2 - gradient_x_direction * (
+ x_at_x2 - self._x_of_particle
+ )
+ self._v_vel_of_particle = v_vel_at_y2 - gradient_y_direction * (
+ y_at_y2 - self._y_of_particle
+ )
+ self._u_vel_of_particle = np.where(
+ self._u_vel_of_particle < 1e-10, 0, self._u_vel_of_particle
+ )
+ self._v_vel_of_particle = np.where(
+ self._v_vel_of_particle < 1e-10, 0, self._v_vel_of_particle
+ )
+
+ ### Calculation accoss x-direction
+ # Avoiding divisions by zero
+ tempCalc1 = np.where(
+ self._u_vel_of_particle == 0, 9999, self._u_vel_of_particle
+ )
+ tempCalc2 = np.where(u_vel_at_x1 == 0, 9999, u_vel_at_x1)
+ tempCalc3 = np.where(gradient_x_direction == 0, 9999, gradient_x_direction)
+ TAUx = (1 / tempCalc3) * np.log(abs(tempCalc1 / tempCalc2))
+
+ # Calculation when gradient is equal to zero
+ tempCalc4 = abs((self._x_of_particle - x_at_x1) / tempCalc2)
+ TAUx = np.where(gradient_x_direction == 0, tempCalc4, TAUx)
+
+ # Calculation when:
+ # a) Uxp/Ux1 = 1,
+ # b) Uxp,Vyp = 0,
+ # c) Ux1,Vy1 = 0, and
+ # d) Uxp/Ux1, Vxp/Vy1 = -1
+ tempCalc5 = self._u_vel_of_particle / tempCalc2
+ TAUx = np.where(tempCalc5 == 1, tempCalc4, TAUx)
+ TAUx = np.where(self._u_vel_of_particle == 0, remaining_time, TAUx)
+ TAUx = np.where(u_vel_at_x1 == 0, remaining_time, TAUx)
+ TAUx = np.where(tempCalc5 < 0, remaining_time, TAUx)
+ TAUx = np.where(TAUx > self._dt, self._dt, TAUx)
+ TAUx = np.where(TAUx < 0, 0, TAUx)
+
+ ### Calculation across y-direction
+ # Avoiding divisions by zero
+ tempCalc1 = np.where(
+ self._v_vel_of_particle == 0, 9999, self._v_vel_of_particle
+ )
+ tempCalc2 = np.where(v_vel_at_y1 == 0, 9999, v_vel_at_y1)
+ tempCalc3 = np.where(gradient_y_direction == 0, 9999, gradient_y_direction)
+ TAUy = (1 / tempCalc3) * np.log(abs(tempCalc1 / tempCalc2))
+
+ # Calculation when gradient is equal to zero
+ tempCalc4 = abs((self._y_of_particle - y_at_y1) / tempCalc2)
+ TAUy = np.where(gradient_y_direction == 0, tempCalc4, TAUy)
+
+ # Calculation when
+ # a) Vyp/Vy1 = 1,
+ # b) Uxp,Vyp = 0,
+ # c) Ux1,Vy1 = 0, and
+ # d) Uxp/Ux1, Vxp/Vy1 = -1
+ tempCalc5 = self._v_vel_of_particle / tempCalc2
+ TAUy = np.where(tempCalc5 == 1, tempCalc4, TAUy)
+ TAUy = np.where(self._v_vel_of_particle == 0, remaining_time, TAUy)
+ TAUy = np.where(v_vel_at_y1 == 0, remaining_time, TAUy)
+ TAUy = np.where(tempCalc5 < 0, remaining_time, TAUy)
+ TAUy = np.where(TAUy > self._dt, self._dt, TAUy)
+ TAUy = np.where(TAUy < 0, 0, TAUy)
+
+ # Obtaining TAU = min(TAUx, TAUy, (dt - sum_partial_times))
+ TAUx = abs(TAUx)
+ TAUy = abs(TAUy)
+ TAU = np.array((TAUx, TAUy, remaining_time)).min(axis=0)
+ # TAU = np.where(TAU < 1e-10, 0, TAU)
+
+ # Calculating exit point Xe, Ye
+ tempCalc1 = np.where(gradient_x_direction == 0, 9999, gradient_x_direction)
+ tempCalc2 = np.where(gradient_y_direction == 0, 9999, gradient_y_direction)
+
+ # Exit point Xe (tempCalc3) and Ye (tempCalc4)
+ tempCalc3 = x_at_x2 - (1 / tempCalc1) * (
+ u_vel_at_x2
+ - self._u_vel_of_particle / np.exp(gradient_x_direction * TAU)
+ )
+ tempCalc4 = y_at_y2 - (1 / tempCalc2) * (
+ v_vel_at_y2
+ - self._v_vel_of_particle / np.exp(gradient_y_direction * TAU)
+ )
+
+ tempCalc3 = np.where(
+ gradient_x_direction == 0,
+ self._x_of_particle - u_vel_at_x2 * TAU,
+ tempCalc3,
+ )
+ tempCalc4 = np.where(
+ gradient_y_direction == 0,
+ self._y_of_particle - v_vel_at_y2 * TAU,
+ tempCalc4,
+ )
+
+ tempCalc3 = np.where(
+ self._u_vel_of_particle == 0, self._x_of_particle, tempCalc3
+ )
+ tempCalc4 = np.where(
+ self._v_vel_of_particle == 0, self._y_of_particle, tempCalc4
+ )
+
+ self._x_at_exit_point = np.where(
+ keep_tracing, tempCalc3, self._x_at_exit_point
+ )
+ self._y_at_exit_point = np.where(
+ keep_tracing, tempCalc4, self._y_at_exit_point
+ )
+
+ # Updating sum of partial time-steps, TAU
+ sum_partial_times = np.where(
+ keep_tracing, sum_partial_times + TAU, self._dt
+ )
+
+ # Checking remaining_time == 0 (dt = sum_partial_times)
+ remaining_time = np.where(
+ remaining_time == 0, 0, self._dt - sum_partial_times
+ )
+
+ # Correcting entry velocity
+ tempCalc1 = np.where(self._u_vel_of_particle == 0, 1, 0)
+ tempCalc2 = np.where(self._v_vel_of_particle == 0, 1, 0)
+ remaining_time = np.where((tempCalc1 * tempCalc2) == 1, 0, remaining_time)
+
+ # Correction for static particles
+ remaining_time = np.where(
+ abs(self._x_of_particle - self._x_at_exit_point) < 1e-7,
+ 0,
+ remaining_time,
+ )
+ remaining_time = np.where(
+ abs(self._y_of_particle - self._y_at_exit_point) < 1e-7,
+ 0,
+ remaining_time,
+ )
+
+ # Stop tracing if a particle hits the boundary
+ # Keep tracing for all particles
+ tempCalc1 = np.repeat(True, len(keep_tracing))
+ # Particle hits the left edge?
+ tempCalc2 = np.isin(
+ self._x_at_exit_point,
+ self._grid.x_of_node[self.grid.nodes_at_left_edge],
+ )
+ # If above True, stop tracing for that particle
+ tempCalc1 = np.where(tempCalc2, False, tempCalc1)
+ # Particle hits the right edge?
+ tempCalc2 = np.isin(
+ self._x_at_exit_point,
+ self._grid.x_of_node[self.grid.nodes_at_right_edge],
+ )
+ # If above True, stop tracing for that particle
+ tempCalc1 = np.where(tempCalc2, False, tempCalc1)
+ # Particle hits the top edge?
+ tempCalc2 = np.isin(
+ self._y_at_exit_point, self._grid.y_of_node[self.grid.nodes_at_top_edge]
+ )
+ # If above True, stop tracing for that particle
+ tempCalc1 = np.where(tempCalc2, False, tempCalc1)
+ # Particle hits the bottom edge?
+ tempCalc2 = np.isin(
+ self._y_at_exit_point,
+ self._grid.y_of_node[self.grid.nodes_at_bottom_edge],
+ )
+ # If above True, stop tracing for that particle
+ tempCalc1 = np.where(tempCalc2, False, tempCalc1)
+ # Where particles reach the boundary, remaining time is equal to zero
+ # remaining_time = np.where(not tempCalc1, 0, remaining_time)
+ remaining_time = np.where(~tempCalc1, 0, remaining_time)
+
+ # Updating on particles that need to traced backwards
+ keep_tracing = np.where(remaining_time > 0, True, False)
+
+ # WHILE "np.any(remaining_time > 0)" END
+ # DEF "path_line_tracing(self)" END
+
+ def run_one_step(self):
+ """Calculate water depth and water velocity for a time period dt."""
+ dx, dy = self.grid.dx, self.grid.dy
+
+ # Getting velocity as U,V components
+ self._u_vel = self._vel_at_N[self.grid.horizontal_links]
+ self._v_vel = self._vel_at_N[self.grid.vertical_links]
+
+ # Calculating Chezy coefficient
+ self._chezy_at_nodes = self._h_at_N ** (1 / 6) / self._mannings_n
+ self._chezy_at_links = self._h_at_N_at_links ** (1 / 6) / self._mannings_n
+
+ # Computing V-velocity (vertical links) at U-velocity positions (horizontal links)
+ tempCalc1 = self._grid.map_mean_of_horizontal_links_to_node(self._vel_at_N)
+ self._u_vel_at_v_links = np.mean(
+ tempCalc1[self._grid.nodes_at_link[self.grid.vertical_links]], axis=1
+ )
+
+ # Computing U-velocity (horizontal links) at V-velocity positions (vertical links)
+ tempCalc1 = self._grid.map_mean_of_vertical_links_to_node(self._vel_at_N)
+ self._v_vel_at_u_links = np.mean(
+ tempCalc1[self._grid.nodes_at_link[self.grid.horizontal_links]], axis=1
+ )
+
+ # Setting A-faces
+ self._a_links = np.zeros_like(self._vel_at_N)
+
+ # Setting dry links equal to 1 to avoid divisions by zero
+ tempCalc1 = np.where(self._wet_links, self._chezy_at_links, 1)
+
+ # Computing A-faces
+ self._a_links[self.grid.horizontal_links] = (
+ self._h_at_N_at_links[self.grid.horizontal_links]
+ + self._g
+ * self._dt
+ * (
+ self._vel_at_N[self.grid.horizontal_links] ** 2
+ + self._v_vel_at_u_links**2
+ )
+ ** (1 / 2)
+ / tempCalc1[self.grid.horizontal_links]
+ )
+ self._a_links[self.grid.vertical_links] = (
+ self._h_at_N_at_links[self.grid.vertical_links]
+ + self._g
+ * self._dt
+ * (
+ self._vel_at_N[self.grid.vertical_links] ** 2
+ + self._u_vel_at_v_links**2
+ )
+ ** (1 / 2)
+ / tempCalc1[self.grid.vertical_links]
+ )
+
+ # Using only wet-link values, and setting dry links equal to 1 to avoid
+ # divisions by zero
+ self._a_links = np.where(self._wet_links, self._a_links, 1)
+
+ # Path line tracing
+ # U-velocity, x-direction, horizontal links
+ # Getting the initial particle location at each volume faces
+ tempB1 = [i in self.grid.horizontal_links for i in self.grid.active_links]
+ self._x_of_particle = self._grid.xy_of_link[:, 0][self.grid.active_links][
+ tempB1
+ ]
+ self._y_of_particle = self._grid.xy_of_link[:, 1][self.grid.active_links][
+ tempB1
+ ]
+
+ # Getting the initial particle velocity
+ tempB2 = [i in self.grid.active_links for i in self.grid.horizontal_links]
+ self._u_vel_of_particle = self._u_vel[tempB2]
+ self._v_vel_of_particle = self._v_vel_at_u_links[tempB2]
+
+ # Getting a first 'exit' point to begin the loop
+ self._x_at_exit_point = self._x_of_particle
+ self._y_at_exit_point = self._y_of_particle
+
+ # Calculating path line backwards on time
+ self.path_line_tracing()
+
+ # Bicuatradic interpolation
+ # U-velocity, x-direction, around (p,q) location
+ self._UsL = np.zeros_like(self._u_vel)
+
+ # Getting V-velocity at U-links
+ temp_Vvel = np.zeros_like(self._vel_at_N)
+ temp_Vvel[self.grid.horizontal_links] = self._v_vel_at_u_links
+
+ # Getting links around the particle and defining downstream direction based on velocity
+ nearest_link_to_particle = self.find_nearest_link(
+ self._x_at_exit_point, self._y_at_exit_point, objective_links="horizontal"
+ )
+ adjacent_links_to_particle = self.find_adjacent_links_at_link(
+ nearest_link_to_particle, objective_links="horizontal"
+ )
+
+ link_at_B2 = nearest_link_to_particle
+ link_at_A2 = adjacent_links_to_particle[:, 1] # 1: N, top
+ link_at_C2 = adjacent_links_to_particle[:, 3] # 3: S, bottom
+ link_at_A2 = np.where(temp_Vvel[link_at_B2] >= 0, link_at_A2, link_at_C2)
+ link_at_C2 = np.where(temp_Vvel[link_at_B2] >= 0, link_at_C2, link_at_A2)
+ # We avoid "-1" links close to the boundary
+ link_at_A2 = np.where(link_at_A2 >= 0, link_at_A2, link_at_B2)
+ link_at_C2 = np.where(link_at_C2 >= 0, link_at_C2, link_at_B2)
+
+ # Getting the surrounding links to every particle from closest link
+ # 0: E, Right
+ # 2: W, Left
+ link_at_A1 = self.find_adjacent_links_at_link(
+ link_at_A2, objective_links="horizontal"
+ )[:, 0]
+ link_at_A3 = self.find_adjacent_links_at_link(
+ link_at_A2, objective_links="horizontal"
+ )[:, 2]
+
+ # Selecting downstream link based on velocity direction
+ link_at_A1 = np.where(self._vel_at_N[link_at_B2] >= 0, link_at_A1, link_at_A3)
+ link_at_A3 = np.where(self._vel_at_N[link_at_B2] >= 0, link_at_A3, link_at_A1)
+
+ link_at_B1 = self.find_adjacent_links_at_link(
+ link_at_B2, objective_links="horizontal"
+ )[
+ :, 0
+ ] # 0: E, Right
+ link_at_B3 = self.find_adjacent_links_at_link(
+ link_at_B2, objective_links="horizontal"
+ )[
+ :, 2
+ ] # 2: W, Left
+
+ # Selecting downstream link based on velocity direction
+ link_at_B1 = np.where(self._vel_at_N[link_at_B2] >= 0, link_at_B1, link_at_B3)
+ link_at_B3 = np.where(self._vel_at_N[link_at_B2] >= 0, link_at_B3, link_at_B1)
+
+ link_at_C1 = self.find_adjacent_links_at_link(
+ link_at_C2, objective_links="horizontal"
+ )[
+ :, 0
+ ] # 0: E, Right
+ link_at_C3 = self.find_adjacent_links_at_link(
+ link_at_C2, objective_links="horizontal"
+ )[
+ :, 2
+ ] # 2: W, Left
+
+ # Selecting downstream link based on velocity direction
+ link_at_C1 = np.where(self._vel_at_N[link_at_B2] >= 0, link_at_C1, link_at_C3)
+ link_at_C3 = np.where(self._vel_at_N[link_at_B2] >= 0, link_at_C3, link_at_C1)
+
+ # Getting velocity around the particle
+ vel_at_A1 = np.where(
+ link_at_A1 >= 0, self._vel_at_N[link_at_A1], self._vel_at_N[link_at_A2]
+ )
+ vel_at_A2 = self._vel_at_N[link_at_A2]
+ vel_at_A3 = np.where(
+ link_at_A3 >= 0, self._vel_at_N[link_at_A3], self._vel_at_N[link_at_A2]
+ )
+
+ vel_at_B1 = np.where(
+ link_at_B1 >= 0, self._vel_at_N[link_at_B1], self._vel_at_N[link_at_B2]
+ )
+ vel_at_B2 = self._vel_at_N[link_at_B2]
+ vel_at_B3 = np.where(
+ link_at_B3 >= 0, self._vel_at_N[link_at_B3], self._vel_at_N[link_at_B2]
+ )
+
+ vel_at_C1 = np.where(
+ link_at_C1 >= 0, self._vel_at_N[link_at_C1], self._vel_at_N[link_at_C2]
+ )
+ vel_at_C2 = self._vel_at_N[link_at_C2]
+ vel_at_C3 = np.where(
+ link_at_C3 >= 0, self._vel_at_N[link_at_C3], self._vel_at_N[link_at_C2]
+ )
+
+ # Getting coordinates around the particle
+ x_at_2 = self._grid.xy_of_link[link_at_B2][:, 0]
+ x_at_1 = np.where(self._vel_at_N[link_at_B2] >= 0, x_at_2 + dx, x_at_2 - dx)
+ x_at_3 = np.where(self._vel_at_N[link_at_B2] >= 0, x_at_2 - dx, x_at_2 + dx)
+
+ y_at_B = self._grid.xy_of_link[link_at_B2][:, 1]
+ y_at_A = np.where(temp_Vvel[link_at_B2] >= 0, y_at_B + dy, y_at_B - dy)
+ y_at_C = np.where(temp_Vvel[link_at_B2] >= 0, y_at_B - dy, y_at_B + dy)
+
+ # Calculating the weights W(i,j) for k around x-direction
+ W1 = (
+ (self._x_at_exit_point - x_at_2)
+ * (self._x_at_exit_point - x_at_3)
+ / ((x_at_1 - x_at_2) * (x_at_1 - x_at_3))
+ )
+ W2 = (
+ (self._x_at_exit_point - x_at_1)
+ * (self._x_at_exit_point - x_at_3)
+ / ((x_at_2 - x_at_1) * (x_at_2 - x_at_3))
+ )
+ W3 = (
+ (self._x_at_exit_point - x_at_1)
+ * (self._x_at_exit_point - x_at_2)
+ / ((x_at_3 - x_at_1) * (x_at_3 - x_at_2))
+ )
+
+ # Interpolation by row around 'x_at_exit_point'
+ A = W1 * vel_at_A1 + W2 * vel_at_A2 + W3 * vel_at_A3
+ B = W1 * vel_at_B1 + W2 * vel_at_B2 + W3 * vel_at_B3
+ C = W1 * vel_at_C1 + W2 * vel_at_C2 + W3 * vel_at_C3
+
+ # Calculating the weghts W(i,j) for l around y-direction
+ W1 = (
+ (self._y_at_exit_point - y_at_B)
+ * (self._y_at_exit_point - y_at_C)
+ / ((y_at_A - y_at_B) * (y_at_A - y_at_C))
+ )
+ W2 = (
+ (self._y_at_exit_point - y_at_A)
+ * (self._y_at_exit_point - y_at_C)
+ / ((y_at_B - y_at_A) * (y_at_B - y_at_C))
+ )
+ W3 = (
+ (self._y_at_exit_point - y_at_A)
+ * (self._y_at_exit_point - y_at_B)
+ / ((y_at_C - y_at_A) * (y_at_C - y_at_B))
+ )
+
+ # Calculating UsL by bicuadratic interpolation
+ self._UsL[tempB2] = W1 * A + W2 * B + W3 * C
+
+ # Computing viscous terms
+ # U-located particles
+ # Central difference scheme around x- and y- direction for U-located particles
+ self._Uvis = np.zeros_like(self._u_vel)
+
+ tempCalc1 = (
+ self._eddy_viscosity
+ * self._dt
+ * (vel_at_B3 - 2 * vel_at_B2 + vel_at_B1)
+ / (dx**2)
+ )
+ tempCalc2 = (
+ self._eddy_viscosity
+ * self._dt
+ * (vel_at_C2 - 2 * vel_at_B2 + vel_at_A2)
+ / (dy**2)
+ )
+
+ self._Uvis[tempB2] = tempCalc1 + tempCalc2
+
+ # Path line tracing
+ # V-velocity, y-direction, vertical links
+ # Getting the initial particle location at each volume faces
+ tempB1 = [j in self.grid.vertical_links for j in self.grid.active_links]
+ self._x_of_particle = self._grid.xy_of_link[:, 0][self.grid.active_links][
+ tempB1
+ ]
+ self._y_of_particle = self._grid.xy_of_link[:, 1][self.grid.active_links][
+ tempB1
+ ]
+
+ # Getting the initial particle velocity
+ tempB2 = [j in self.grid.active_links for j in self.grid.vertical_links]
+ self._v_vel_of_particle = self._v_vel[tempB2]
+ self._u_vel_of_particle = self._u_vel_at_v_links[tempB2]
+
+ # Getting a first 'exit' point to begin the loop
+ self._x_at_exit_point = self._x_of_particle
+ self._y_at_exit_point = self._y_of_particle
+
+ # Calculating path line backwards on time
+ self.path_line_tracing()
+
+ # Bicuatradic interpolation
+ # V-velocity, y-direction, around (p,q) location
+ self._VsL = np.zeros_like(self._v_vel)
+
+ # Getting V-velocity at U-links
+ temp_Uvel = np.zeros_like(self._vel_at_N)
+ temp_Uvel[self.grid.vertical_links] = self._u_vel_at_v_links
+
+ # Getting links around the particle and defining downstream direction based on velocity
+ nearest_link_to_particle = self.find_nearest_link(
+ self._x_at_exit_point, self._y_at_exit_point, objective_links="vertical"
+ )
+ adjacent_links_to_particle = self.find_adjacent_links_at_link(
+ nearest_link_to_particle, objective_links="vertical"
+ )
+
+ link_at_B2 = nearest_link_to_particle
+ link_at_A2 = adjacent_links_to_particle[:, 1] # 1: N, top
+ link_at_C2 = adjacent_links_to_particle[:, 3] # 3: S, bottom
+ link_at_A2 = np.where(self._vel_at_N[link_at_B2] >= 0, link_at_A2, link_at_C2)
+ link_at_C2 = np.where(self._vel_at_N[link_at_B2] >= 0, link_at_C2, link_at_A2)
+ link_at_A2 = np.where(link_at_A2 >= 0, link_at_A2, link_at_B2)
+ link_at_C2 = np.where(link_at_C2 >= 0, link_at_C2, link_at_B2)
+ # We avoid "-1" links close to the boundary
+
+ # Getting the surrounding links to every particle from closest link
+ link_at_A1 = self.find_adjacent_links_at_link(
+ link_at_A2, objective_links="vertical"
+ )[
+ :, 0
+ ] # 0: E, Left
+ link_at_A3 = self.find_adjacent_links_at_link(
+ link_at_A2, objective_links="vertical"
+ )[
+ :, 2
+ ] # 2: W, Right
+
+ # Selecting downstream link based on velocity direction
+ link_at_A1 = np.where(temp_Uvel[link_at_B2] >= 0, link_at_A1, link_at_A3)
+ link_at_A3 = np.where(temp_Uvel[link_at_B2] >= 0, link_at_A3, link_at_A1)
+
+ link_at_B1 = self.find_adjacent_links_at_link(
+ link_at_B2, objective_links="vertical"
+ )[
+ :, 0
+ ] # 0: E, Left
+ link_at_B3 = self.find_adjacent_links_at_link(
+ link_at_B2, objective_links="vertical"
+ )[
+ :, 2
+ ] # 2: W, Right
+
+ # Selecting downstream link based on velocity direction
+ link_at_B1 = np.where(temp_Uvel[link_at_B2] >= 0, link_at_B1, link_at_B3)
+ link_at_B3 = np.where(temp_Uvel[link_at_B2] >= 0, link_at_B3, link_at_B1)
+
+ link_at_C1 = self.find_adjacent_links_at_link(
+ link_at_C2, objective_links="vertical"
+ )[
+ :, 0
+ ] # 0: E, Left
+ link_at_C3 = self.find_adjacent_links_at_link(
+ link_at_C2, objective_links="vertical"
+ )[
+ :, 2
+ ] # 2: W, Right
+
+ # Selecting downstream link based on velocity direction
+ link_at_C1 = np.where(temp_Uvel[link_at_B2] >= 0, link_at_C1, link_at_C3)
+ link_at_C3 = np.where(temp_Uvel[link_at_B2] >= 0, link_at_C3, link_at_C1)
+
+ # Getting velocity around the particle
+ vel_at_A1 = np.where(
+ link_at_A1 >= 0, self._vel_at_N[link_at_A1], self._vel_at_N[link_at_A2]
+ )
+ vel_at_A2 = self._vel_at_N[link_at_A2]
+ vel_at_A3 = np.where(
+ link_at_A3 >= 0, self._vel_at_N[link_at_A3], self._vel_at_N[link_at_A2]
+ )
+
+ vel_at_B1 = np.where(
+ link_at_B1 >= 0, self._vel_at_N[link_at_B1], self._vel_at_N[link_at_B2]
+ )
+ vel_at_B2 = self._vel_at_N[link_at_B2]
+ vel_at_B3 = np.where(
+ link_at_B3 >= 0, self._vel_at_N[link_at_B3], self._vel_at_N[link_at_B2]
+ )
+
+ vel_at_C1 = np.where(
+ link_at_C1 >= 0, self._vel_at_N[link_at_C1], self._vel_at_N[link_at_C2]
+ )
+ vel_at_C2 = self._vel_at_N[link_at_C2]
+ vel_at_C3 = np.where(
+ link_at_C3 >= 0, self._vel_at_N[link_at_C3], self._vel_at_N[link_at_C2]
+ )
+
+ # Getting coordinates around the particle
+ x_at_2 = self._grid.xy_of_link[link_at_B2][:, 0]
+ x_at_1 = np.where(temp_Uvel[link_at_B2] >= 0, x_at_2 + dx, x_at_2 - dx)
+ x_at_3 = np.where(temp_Uvel[link_at_B2] >= 0, x_at_2 - dx, x_at_2 + dx)
+
+ y_at_B = self._grid.xy_of_link[link_at_B2][:, 1]
+ y_at_A = np.where(self._vel_at_N[link_at_B2] >= 0, y_at_B + dy, y_at_B - dy)
+ y_at_C = np.where(self._vel_at_N[link_at_B2] >= 0, y_at_B - dy, y_at_B + dy)
+
+ # Calculating the weights W(i,j) for k around x-direction
+ W1 = (
+ (self._x_at_exit_point - x_at_2)
+ * (self._x_at_exit_point - x_at_3)
+ / ((x_at_1 - x_at_2) * (x_at_1 - x_at_3))
+ )
+ W2 = (
+ (self._x_at_exit_point - x_at_1)
+ * (self._x_at_exit_point - x_at_3)
+ / ((x_at_2 - x_at_1) * (x_at_2 - x_at_3))
+ )
+ W3 = (
+ (self._x_at_exit_point - x_at_1)
+ * (self._x_at_exit_point - x_at_2)
+ / ((x_at_3 - x_at_1) * (x_at_3 - x_at_2))
+ )
+
+ # Interpolation by row around 'y_at_exit_point'
+ A = W1 * vel_at_A1 + W2 * vel_at_A2 + W3 * vel_at_A3
+ B = W1 * vel_at_B1 + W2 * vel_at_B2 + W3 * vel_at_B3
+ C = W1 * vel_at_C1 + W2 * vel_at_C2 + W3 * vel_at_C3
+
+ # Calculating the weghts W(i,j) for l around y-direction
+ W1 = (
+ (self._y_at_exit_point - y_at_B)
+ * (self._y_at_exit_point - y_at_C)
+ / ((y_at_A - y_at_B) * (y_at_A - y_at_C))
+ )
+ W2 = (
+ (self._y_at_exit_point - y_at_A)
+ * (self._y_at_exit_point - y_at_C)
+ / ((y_at_B - y_at_A) * (y_at_B - y_at_C))
+ )
+ W3 = (
+ (self._y_at_exit_point - y_at_A)
+ * (self._y_at_exit_point - y_at_B)
+ / ((y_at_C - y_at_A) * (y_at_C - y_at_B))
+ )
+
+ # Calculating VsL by bicuadratic interpolation
+ self._VsL[tempB2] = W1 * A + W2 * B + W3 * C
+
+ # Computing viscous terms
+ # V-located particles
+ # Central difference scheme around x- and y- direction for V-located particles
+ self._Vvis = np.zeros_like(self._v_vel)
+
+ tempCalc1 = (
+ self._eddy_viscosity
+ * self._dt
+ * (vel_at_B3 - 2 * vel_at_B2 + vel_at_B1)
+ / (dx**2)
+ )
+ tempCalc2 = (
+ self._eddy_viscosity
+ * self._dt
+ * (vel_at_C2 - 2 * vel_at_B2 + vel_at_A2)
+ / (dy**2)
+ )
+
+ self._Vvis[tempB2] = tempCalc1 + tempCalc2
+
+ # Computing advective terms (FU, FV)
+ self._f_vel = np.zeros_like(self._vel_at_N)
+
+ # Adding semi-lagrangian and viscous terms
+ tempCalc1 = self._UsL + self._Uvis
+ tempCalc2 = self._VsL + self._Vvis
+
+ # Including the results according with links directions
+ self._f_vel[self.grid.horizontal_links] = tempCalc1
+ self._f_vel[self.grid.vertical_links] = tempCalc2
+
+ # Setting G-faces
+ self._g_links = np.zeros_like(self._vel_at_N)
+
+ # Computing G-faces
+ self._g_links = self._h_at_N_at_links * self._f_vel - self._h_at_N_at_links * (
+ 1 - self._theta
+ ) * self._g * self._dt / dx * self._grid.calc_diff_at_link(self._eta_at_N)
+
+ # Using only wet-link values, and setting dry links equal to 0 to avoid
+ # using wrong values
+ self._g_links = np.where(self._wet_links, self._g_links, 0)
+ self._g_links = np.where(
+ self._grid.status_at_link == 4, 0, self._g_links
+ ) # link is active (0), fixed (2), inactive (4)
+
+ # Solving semi-implicit scheme with PCG method
+ # Building the system of equations 'A*x=b'
+ # Full 'A' matrix with all nodes on it
+ A = np.zeros((self.grid.number_of_nodes, self.grid.number_of_nodes))
+ b = self.grid.zeros(at="node") # Full 'b' vector with all nodes on it
+
+ # Getting surrounding locations for core nodes
+ adjacent_nodes = self._grid.adjacent_nodes_at_node[
+ self.grid.core_nodes
+ ] # East, North, West, South
+ adjacent_links = self._grid.links_at_node[
+ self.grid.core_nodes
+ ] # East, North, West, South
+ nodes_location = np.append(
+ adjacent_nodes, np.array([self.grid.core_nodes]).T, axis=1
+ ) # East, North, West, South, Center
+
+ # Boolean to differentiate between core and boundary nodes
+ tempB1 = np.isin(nodes_location, self.grid.core_nodes)
+ # Core node if tempB1 == True, boundary node if tempB1 == False
+ tempB2 = ~tempB1
+ # Boundary node if tempB2 == True, core node if tempB2 == False
+
+ ## Building 'b' for the right-hand side of the system
+ # Calculating 'delta' to build 'b'
+ tempCalc1 = (
+ self._h_at_N_at_links[adjacent_links] * self._vel_at_N[adjacent_links]
+ )
+ tempCalc2 = (
+ self._eta_at_N[self.grid.core_nodes]
+ - (1 - self._theta) * self._dt / dx * (tempCalc1[:, 0] - tempCalc1[:, 2])
+ - (1 - self._theta) * self._dt / dy * (tempCalc1[:, 1] - tempCalc1[:, 3])
+ )
+
+ tempCalc1 = (
+ self._h_at_N_at_links[adjacent_links]
+ * self._g_links[adjacent_links]
+ / self._a_links[adjacent_links]
+ )
+ b[self.grid.core_nodes] = (
+ tempCalc2
+ - self._theta * self._dt / dx * (tempCalc1[:, 0] - tempCalc1[:, 2])
+ - self._theta * self._dt / dy * (tempCalc1[:, 1] - tempCalc1[:, 3])
+ )
+
+ ## Building 'A' for the left-hand side of the system
+ # Calculating coefficients for the system of equations
+ tempCalc1 = (
+ self._h_at_N_at_links[adjacent_links] ** 2 / self._a_links[adjacent_links]
+ )
+ coefficients = [
+ -tempCalc1[:, 0] * (self._g * self._theta * self._dt / dx) ** 2,
+ -tempCalc1[:, 1] * (self._g * self._theta * self._dt / dy) ** 2,
+ -tempCalc1[:, 2] * (self._g * self._theta * self._dt / dx) ** 2,
+ -tempCalc1[:, 3] * (self._g * self._theta * self._dt / dy) ** 2,
+ 1
+ + (tempCalc1[:, 0] + tempCalc1[:, 2])
+ * (self._g * self._theta * self._dt / dx) ** 2
+ + (tempCalc1[:, 1] + tempCalc1[:, 3])
+ * (self._g * self._theta * self._dt / dy) ** 2,
+ ]
+ coefficients = np.array(coefficients).T
+
+ ## For loop iterates through every row of 'nodes_location' to:
+ # a) find the node number (row in A) and choose an equation, and
+ # b) find the columns associated with adjacent nodes
+ for row in range(nodes_location.shape[0]):
+ # Getting the current node
+ current_node = nodes_location[row, 4]
+ # Getting the row associated with the current node
+ current_rows_in_A = np.array([current_node])
+ # Getting the columns associated with surrounding nodes
+ current_cols_in_A = nodes_location[row, :]
+
+ # Filling A matrix with coefficients associated with surrounding nodes
+ A[np.ix_(current_rows_in_A, current_cols_in_A)] = (
+ coefficients[row, :] * tempB1[row, :]
+ )
+
+ # Adding known terms (boundary nodes) to the right-hand side of the equation
+ b[current_rows_in_A] = b[current_rows_in_A] - sum(
+ self._eta_at_N[nodes_location[row, :]]
+ * coefficients[row, :]
+ * tempB2[row, :]
+ )
+ # for END
+
+ # Extracting only core nodes to be solved
+ left_hand_side = A[np.ix_(self.grid.core_nodes, self.grid.core_nodes)]
+ right_hand_side = b[self.grid.core_nodes]
+
+ # Applying PCG method to 'LHS*eta=RHS' using np.diag() as a preconditioner for 'LHS'
+ # Preconditioned conjugated gradient output flag:
+ # 0 : successful exit
+ # >0 : convergence to tolerance not achieved, number of iterations
+ # <0 : illegal input or breakdown
+ # Alternative preconditiner: Li = np.linalg.cholesky(left_hand_side)
+ Mi = np.diag(np.diag(left_hand_side))
+ pcg_results = sp.sparse.linalg.cg(
+ left_hand_side,
+ right_hand_side,
+ M=Mi,
+ rtol=self._pcg_tolerance,
+ maxiter=self._pcg_max_iterations,
+ atol=0,
+ )
+
+ # Getting the new water surface elevation
+ self._eta = np.zeros_like(self._eta_at_N)
+ self._eta[self.grid.core_nodes] = pcg_results[0]
+
+ # Boundary conditions
+ # Radiation Boundary Conditions of Roed & Smedstad (1984) applied on open boundaries
+ # Water surface elevation
+ ## Updating the new WSE ('eta') with the fixed nodes values
+ if self._fixed_nodes_exist is True:
+ self._eta[self._fixed_entry_nodes] = (
+ self._entry_nodes_h_values - self._z[self._fixed_entry_nodes]
+ )
+
+ ## Getting the 1-line-upstream nodes from boundary nodes
+ tempCalc1 = self._grid.active_adjacent_nodes_at_node[self._open_boundary_nodes]
+ open_boundary_nodes_1_backwards = np.extract(tempCalc1 >= 0, tempCalc1)
+
+ ## Getting the 2-line-upstream nodes from boundary nodes
+ # Looking for these nodes
+ tempCalc1 = np.tile(self._open_boundary_nodes, (4, 1)).T
+ tempCalc2 = self._grid.active_adjacent_nodes_at_node[
+ open_boundary_nodes_1_backwards
+ ] # Surrounding nodes to 1-line-upstream
+
+ # Getting the node positions to extract them from all the surrounding nodes
+ tempB1 = np.tile([0, 1, 2, 3], (len(self._open_boundary_nodes), 1))
+ tempB2 = tempB1[tempCalc1 == tempCalc2]
+
+ # It gives me the node indices to extract
+ # folowing the face direction
+ tempB1 = np.where(tempB2 == 0, 2, tempB2)
+ tempB1 = np.where(tempB2 == 1, 3, tempB1)
+ tempB1 = np.where(tempB2 == 2, 0, tempB1)
+ tempB1 = np.where(tempB2 == 3, 1, tempB1)
+
+ open_boundary_nodes_2_backwards = tempCalc2[
+ [range(tempCalc2.shape[0])], tempB1
+ ][0]
+
+ ## Getting WSE at different locations
+ eta_at_N_at_B = self._eta_at_N[self._open_boundary_nodes]
+ eta_at_N_at_B_1 = self._eta_at_N[open_boundary_nodes_1_backwards]
+ eta_at_N_1_at_B_1 = self._eta_at_N_1[open_boundary_nodes_1_backwards]
+ eta_at_N_1_at_B_2 = self._eta_at_N_1[open_boundary_nodes_2_backwards]
+
+ ## Computing boundary condition
+ tempCalc1 = eta_at_N_at_B_1 - eta_at_N_1_at_B_1
+ tempCalc2 = eta_at_N_1_at_B_1 - eta_at_N_1_at_B_2
+ tempCalc3 = np.where(tempCalc2 == 0, 1, tempCalc2)
+
+ Ce = np.where(tempCalc2 == 0, 0, tempCalc1 / tempCalc3 * (-dx / self._dt))
+ Ce = np.where(tempCalc2 == 0, 0, Ce)
+
+ # eta[open_boundary_nodes] = tempCalc1/tempCalc2
+ self._eta[self._open_boundary_nodes] = np.where(
+ Ce >= 0, eta_at_N_at_B_1, eta_at_N_at_B
+ )
+ self._eta = np.where(
+ abs(self._eta) > abs(self._z), -self._z, self._eta
+ ) # Correcting WSE below topographic elevation
+
+ self._eta_at_links = self._grid.map_mean_of_link_nodes_to_link(self._eta)
+
+ # Corner nodes treatment
+ self._eta[self.grid.corner_nodes] = np.mean(
+ self._eta[self._adjacent_nodes_at_corner_nodes], axis=1
+ )
+
+ # Updating water velocity
+ # tempB1 : Considering only wet cells
+ # tempB2 : Cells with elevation below the water surface elevation
+ tempB1 = np.where(
+ abs(self._eta[self._grid.node_at_link_head])
+ <= abs(self._z[self._grid.node_at_link_head] - self._threshold_depth),
+ 1,
+ 0,
+ )
+ tempB2 = np.where(
+ abs(self._z[self._grid.node_at_link_head])
+ > abs(self._eta[self._grid.node_at_link_tail]),
+ 1,
+ 0,
+ )
+ tempB1 = tempB1 + tempB2
+ tempB1 = np.where(tempB1 > 1, 1, 0)
+
+ # Updating water velocity
+ tempCalc1 = (
+ self._theta
+ * self._g
+ * self._dt
+ / dx
+ * (self._grid.calc_diff_at_link(self._eta))
+ * self._h_at_N_at_links
+ / self._a_links
+ )
+ self._vel = self._g_links / self._a_links - tempCalc1 * tempB1
+
+ # Only updating velocity on wet cells
+ self._vel = np.where(self._wet_links, self._vel, 0)
+
+ # Boundary conditions
+ # Radiation Boundary Conditions of Roed & Smedstad (1984) applied on open boundaries
+ # Water velocity
+ ## Updating the new Velocity with the fixed links values
+ if self._fixed_links_exist is True:
+ self._vel[self._fixed_entry_links] = self._entry_links_vel_values
+
+ ## Getting the boundary links
+ tempB1 = [i in self._open_boundary_links for i in self.grid.active_links]
+ open_boundary_active_links = self._grid.active_links[tempB1]
+
+ ## Getting the 1-line-upstream links from boundary links
+ tempCalc1 = np.tile(open_boundary_active_links, (4, 1)).T
+ tempCalc2 = self._grid.links_at_node[open_boundary_nodes_1_backwards]
+
+ # Getting the link positions to extract them from all the surrounding nodes
+ tempB1 = np.tile([0, 1, 2, 3], (len(self._open_boundary_nodes), 1))
+ tempB2 = tempB1[tempCalc1 == tempCalc2]
+
+ # It gives me the link indices to extract
+ # folowing the face direction
+ tempB1 = np.where(tempB2 == 0, 2, tempB2)
+ tempB1 = np.where(tempB2 == 1, 3, tempB1)
+ # tempB1 is where the target link is located
+ tempB1 = np.where(tempB2 == 2, 0, tempB1)
+ # tempB2 is where the upstream link is located
+ tempB1 = np.where(tempB2 == 3, 1, tempB1)
+
+ open_boundary_active_links_1_backwards = tempCalc2[
+ [range(tempCalc2.shape[0])], tempB1
+ ][0]
+
+ ### Getting the 2-line-upstream links from boundary nodes
+ tempCalc1 = np.tile(open_boundary_active_links_1_backwards, (4, 1)).T
+ tempCalc2 = self._grid.links_at_node[open_boundary_nodes_2_backwards]
+
+ # Getting the link positions to extract them from all the surrounding nodes
+ tempB1 = np.tile([0, 1, 2, 3], (len(self._open_boundary_nodes), 1))
+ tempB2 = tempB1[(tempCalc1 == tempCalc2)]
+
+ # It gives me the link indices to extract
+ # folowing the face direction
+ tempB1 = np.where(tempB2 == 0, 2, tempB2)
+ tempB1 = np.where(tempB2 == 1, 3, tempB1)
+ # tempB1 is where the target link is located
+ tempB1 = np.where(tempB2 == 2, 0, tempB1)
+ # tempB2 is where the upstream link is located
+ tempB1 = np.where(tempB2 == 3, 1, tempB1)
+
+ open_boundary_active_links_2_backwards = tempCalc2[
+ [range(tempCalc2.shape[0])], tempB1
+ ][0]
+
+ ## Getting water velocity at different locations
+ vel_at_N_at_B = self._vel_at_N[open_boundary_active_links]
+ vel_at_N_at_B_1 = self._vel_at_N[open_boundary_active_links_1_backwards]
+ vel_at_N_1_at_B_1 = self._vel_at_N_1[open_boundary_active_links_1_backwards]
+ vel_at_N_1_at_B_2 = self._vel_at_N_1[open_boundary_active_links_2_backwards]
+
+ ## Computing boundary condition
+ tempCalc1 = vel_at_N_at_B_1 - vel_at_N_1_at_B_1
+ tempCalc2 = vel_at_N_1_at_B_1 - vel_at_N_1_at_B_2
+ tempCalc3 = np.where(tempCalc2 == 0, 1, tempCalc2)
+
+ Ce = np.where(tempCalc2 == 0, 0, tempCalc1 / tempCalc3 * (-dx / self._dt))
+ Ce = np.where(tempCalc2 == 0, 0, Ce)
+
+ self._vel[open_boundary_active_links] = np.where(
+ Ce >= 0, vel_at_N_at_B_1, vel_at_N_at_B
+ )
+
+ # Updating water depth at links
+ # Using only values where the WSE is above the topographic elevation
+ tempB1 = np.where(abs(self._eta) <= abs(self._z - self._threshold_depth), 1, 0)
+
+ # Updating water depth at links
+ tempCalc1 = (
+ self._z_at_links + self._eta[self._grid.node_at_link_head]
+ ) * tempB1[self._grid.node_at_link_head]
+ tempCalc2 = (
+ self._z_at_links + self._eta[self._grid.node_at_link_tail]
+ ) * tempB1[self._grid.node_at_link_tail]
+ tempCalc3 = np.zeros_like(self._h_at_N_at_links)
+
+ self._h_at_links = np.array((tempCalc1, tempCalc2, tempCalc3)).max(axis=0)
+
+ # Applying boundary condition at links
+ self._h_at_links[self._open_boundary_links] = (
+ self._z_at_links[self._open_boundary_links]
+ + self._eta_at_links[self._open_boundary_links]
+ )
+
+ # Wet cells threshold
+ self._h_at_links = np.where(
+ self._h_at_links < self._threshold_depth, 0, self._h_at_links
+ )
+
+ # Updating wet links
+ self._wet_links = np.where(
+ self._h_at_links >= self._threshold_depth, True, False
+ )
+ self._vel = self._vel * self._wet_links
+
+ # Calculating average water depth at nodes
+ # If a node is dry, using only surrounding links such that 'WSE' is above 'z'
+ # If a node is wet, using all surrounding links even if 'WSE' is below 'z' (jumps)
+
+ # Checking surrounding wet links
+ surrounding_links = self._grid.links_at_node[self.grid.core_nodes]
+
+ # Checking whether the core node is wet (T) or dry (F)
+ tempB1 = abs(self._eta[self.grid.core_nodes]) < abs(
+ self._z[self.grid.core_nodes] - self._threshold_depth
+ )
+
+ # Checking whether surrounding links are wet (T) or dry (F)
+ tempB2 = self._wet_links[surrounding_links]
+
+ # Checking whether surrounding 'WSE' links are above (T) or below (F) 'z' at nodes
+ tempB3 = (
+ abs(self._eta_at_links[surrounding_links])
+ < abs(self._z[self.grid.core_nodes] - self._threshold_depth)[:, None]
+ )
+
+ # Getting the number of wet links around each core node, satisfying tempB2,
+ # and avoiding divisions by zero
+ tempCalc2 = np.sum(tempB2 * 1, axis=1)
+ tempCalc2 = np.where(tempCalc2 == 0, -9999, tempCalc2)
+
+ # Getting the number of wet links around each core node, satisfying tempB3,
+ # and avoiding divisions by zero
+ tempCalc3 = np.sum(tempB2 * tempB3 * 1, axis=1)
+ tempCalc3 = np.where(tempCalc3 == 0, -9999, tempCalc3)
+
+ # Updating water depth
+ # h = h_at_N - rmg.calc_net_flux_at_node(h_at_links*vel) # (influx if negative)
+ self._h[self.grid.core_nodes] = np.where(
+ tempCalc3 > 0,
+ np.sum(self._h_at_links[surrounding_links] * tempB2 * tempB3, axis=1)
+ / tempCalc3,
+ 0,
+ ) # Dry nodes, tempB1 == False
+
+ ### Updating boundary nodes
+ if self._fixed_nodes_exist is True:
+ self._h[self._fixed_entry_nodes] = self._entry_nodes_h_values
+ self._h[self._open_boundary_nodes] = (
+ self._eta[self._open_boundary_nodes] + self._z[self._open_boundary_nodes]
+ )
+ self._h = np.where(self._h < self._threshold_depth, 0, self._h)
+
+ # Corner nodes treatment
+ self._h[self.grid.corner_nodes] = np.mean(
+ self._h[self._adjacent_nodes_at_corner_nodes], axis=1
+ )
+
+ # Updating wet nodes
+ self._wet_nodes = np.where(self._h >= self._threshold_depth, True, False)
+
+ # Storing values in the grid
+ self._grid.at_node["surface_water__depth"] = self._h
+ self._grid.at_link["surface_water__velocity"] = self._vel
+ self._grid.at_node["surface_water__elevation"] = self._eta + (
+ self._max_elevation + self._additional_z
+ )
+
+ self._grid.at_link["surface_water__velocity_at_N-1"] = self._vel_at_N
+ self._grid.at_node["surface_water__elevation_at_N-1"] = self._eta_at_N + (
+ self._max_elevation + self._additional_z
+ )
+ self._grid.at_node["surface_water__elevation_at_N-2"] = self._eta_at_N_1 + (
+ self._max_elevation + self._additional_z
+ )
+
+ # Storing values at previous time steps
+ self._eta_at_N = self._eta.copy()
+ self._eta_at_N_1 = self._eta_at_N.copy()
+ self._eta_at_N_2 = self._eta_at_N_1.copy()
+
+ self._h_at_N = self._h.copy()
+ self._h_at_N_at_links = self._h_at_links.copy()
+
+ self._vel_at_N = self._vel.copy()
+ self._vel_at_N_1 = self._vel_at_N.copy()
diff --git a/src/landlab/components/spatial_precip/generate_spatial_precip.py b/src/landlab/components/spatial_precip/generate_spatial_precip.py
index 290fd8399b..b1ffcfde0e 100644
--- a/src/landlab/components/spatial_precip/generate_spatial_precip.py
+++ b/src/landlab/components/spatial_precip/generate_spatial_precip.py
@@ -1,1749 +1,1749 @@
-import contextlib
-
-import numpy as np
-from scipy.stats import fisk
-from scipy.stats import genextreme
-
-from landlab import Component
-from landlab import RasterModelGrid
-
-
-class SpatialPrecipitationDistribution(Component):
- """Generate spatially resolved precipitation events.
-
- A component to generate a sequence of spatially resolved storms over a
- grid, following a lightly modified version (see below) of the
- stochastic methods of Singer & Michaelides, Env Res Lett 12, 104011,
- 2017, & Singer et al., Geosci. Model Dev., accepted, 10.5194/gmd-2018-86.
-
- The method is heavily stochastic, and at the present time is intimately
- calibrated against the conditions at Walnut Gulch, described in those
- papers. In particular, assumptions around intensity-duration
- calibration and orographic rainfall are "burned in" for now, and are
- not accessible to the user. The various probability distributions
- supplied to the various run methods default to WG values, but are
- easily modified. This calibration reflects a US desert southwest
- "monsoonal" climate, and the component distinguishes (optionally)
- between two seasons, "monsoonal" and "winter". The intensity-duration
- relationship is shared between the seasons, and so may prove useful in
- a variety of storm-dominated contexts.
-
- The default is to disable the orographic rainfall functionality of the
- component. However, if orographic_scenario == 'Singer', the component
- requires a 'topographic__elevation' field to already exist on the grid
- at the time of instantiation.
-
- The component has two ways of simulating a "year". This choice is
- controlled by the 'limit' parameter of the yield methods. If limit==
- 'total_rainfall', the component will continue to run until the total
- rainfall for the season and/or year exceeds a stochastically generated
- value. This method is directly comparable to the Singer & Michaelides
- method, but will almost always result in years which are not one
- calendar year long, unless the input distributions are very carefully
- recalibrated for each use case. If limit=='total_time', the component
- will terminate a season and/or year once the elapsed time exceeds one
- year. In this case, the total rainfall will not correspond to the
- stochastically generated total. You can access the actual total for the
- last season using the property `(median_)total_rainfall_last_season`.
-
- Note that this component cannot simulate the occurrence of more than one
- storm at the same time. Storms that should be synchronous will instead
- occur sequentially, with no interstorm time. This limitation means that
- if enough storms occur in a year that numstorms*mean_storm_duration
- exceeds one year, the number of simulated storms will saturate. This
- limitation may be relaxed in the future.
-
- The component offers the option to modify the maximum number of storms
- simulated per year. If you find simulations encountering this limit too
- often, you may need to raise this limit. Conversely, it could be lowered
- to reduce memory usage over small grids. However, in increasing the value,
- beware - the component maintains two limit*nnodes arrays, which will chew
- through memory if the limit gets too high. The default will happily
- simulate grids up to around 50 km * 50 km using the default probability
- distributions.
-
- Key methods are:
-
- yield_storms
- Generate a timeseries of storm:interstorm duration pairs, alongside
- a field that describes the spatial distribution of rain during that
- storm.
- yield_years
- Generate a timeseries of ints giving number of storms per year,
- alongside a field that describes the spatial distribution of total
- rainfall across that year.
- yield_seasons
- Generate a timeseries of ints giving number of storms per season,
- alongside a field that describes the spatial distribution of total
- rainfall across that season.
- calc_annual_rainfall
- Produce a timeseries of tuples giving total rainfall each season,
- without resolving the storms spatially (i.e., fast!).
-
- A large number of properties are available to access storm properties
- during generation:
-
- - current_year
- - current_season
- - storm_depth_last_storm
- - storm_recession_value_last_storm
- - storm_duration_last_storm
- - storm_area_last_storm
- - storm_intensity_last_storm
- - total_rainfall_this_season
- - total_rainfall_this_year
- - total_rainfall_last_season
- - total_rainfall_last_year
- - median_total_rainfall_this_season
- - median_total_rainfall_this_year
- - median_total_rainfall_last_season
- - median_total_rainfall_last_year
- - number_of_nodes_under_storm
- - nodes_under_storm
- - target_median_total_rainfall_this_season
-
- Note that becuase these are medians not means,
- median_total_rainfall_last_season + median_total_rainfall_this_season
- != median_total_rainfall_this_year.
-
- Significant differences between this component and the Singer code are:
-
- - The component does not model evapotranspiration. Use a separate
- Landlab component for this.
- - The component runs only over a LL grid; there is no such thing as a
- validation or simulation run.
- - It produces "fuzz" around intensity values using a continuous
- distribution; Singer does this with integer steps.
- - Step changes mid-run cannot be explicitly modelled. Instead, run the
- component for a fixed duration, make the change to the
- distribution input parameter, then run it again.
- - Storms can be centred at any spatial coordinate, not just over nodes.
- - Edge buffering is now dynamic; i.e., big storms have a bigger edge
- buffer than smaller storms. Storms can be centered off the grid
- edges.
- - Storms are never discarded - once a storm is drawn, it must hit the
- catchment, and positions are repeatedly selected until this can
- happen. Singer's method would discard such a storm and draw a new
- one.
- - Durations are not rescaled to ensure both total duration and total
- precip are both satisfied at the same time, as in Singer's method.
- Instead, the component either matches a year's duration, *or*
- exactly a year's worth of rain. This choice is dictated by the
- `limit` parameter in the yield methods.
-
- Examples
- --------
-
- >>> import numpy as np
- >>> from landlab import RasterModelGrid, VoronoiDelaunayGrid
- >>> mg = RasterModelGrid((10, 10), xy_spacing=1000.0)
- >>> rain = SpatialPrecipitationDistribution(mg)
-
- Calling yield_storms will produce storm-interstorm duration (hr) pairs
- until the model runtime has elapsed.
-
- >>> np.random.seed(1)
- >>> total_t_each_step = [
- ... (storm + interstorm) for (storm, interstorm) in rain.yield_storms()
- ... ]
- >>> len(total_t_each_step)
- 41
- >>> np.isclose(sum(total_t_each_step) / 24.0, 365.0)
- True
-
- The actual rainfall intensities during that interval are accessible in the
- 'rainfall__flux' field (mm/hr). The storm centre does not have to be over
- the grid, but in this case, it was for the last simulated storm:
-
- >>> mg.at_node["rainfall__flux"].argmax()
- 80
-
- We can also run the component for only one season (i.e., only using one
- of the pdf sets describing the storm properties):
-
- >>> for field in ("rainfall__flux", "rainfall__total_depth_per_year"):
- ... _ = mg.at_node.pop(field) # clear out the existing fields
- ...
- >>> rain = SpatialPrecipitationDistribution(mg, number_of_years=2)
- >>> np.random.seed(5)
- >>> total_t_each_step = [
- ... (storm + interstorm)
- ... for (storm, interstorm) in rain.yield_storms(
- ... style="monsoonal", monsoon_fraction_of_year=0.35
- ... )
- ... ]
- >>> np.isclose(sum(total_t_each_step) / 24.0 / 365.0 / 2.0, 0.35)
- True
-
- Note this behaviour can be stopped by upping monsoon_fraction_of_year:
-
- >>> np.random.seed(5)
- >>> total_t_each_step = [
- ... (storm + interstorm)
- ... for (storm, interstorm) in rain.yield_storms(
- ... style="monsoonal", monsoon_fraction_of_year=1.0
- ... )
- ... ]
- >>> np.isclose(round(sum(total_t_each_step) / 24.0 / 365.0 / 2.0, 2), 1.0)
- True
-
- yield_years yields the number of storms in the last whole year.
- Use 'rainfall__total_depth_per_year' to access the rainfall map for the
- last fully elapsed year, or equivalently, the total_rainfall_last_year
- property. Note the component seamlessly handles non-raster grid types:
-
- >>> vdg = VoronoiDelaunayGrid(
- ... np.random.rand(100) * 1000.0, np.random.rand(100) * 1000.0
- ... )
- >>> np.random.seed(3)
- >>> rain = SpatialPrecipitationDistribution(vdg, number_of_years=3)
- >>> storms_each_year = []
- >>> for total_storms in rain.yield_years(
- ... style="monsoonal", total_rf_trend=0.05, storminess_trend=-0.02
- ... ):
- ... storms_each_year.append(total_storms)
- ... assert np.all(
- ... np.equal(
- ... vdg.at_node["rainfall__total_depth_per_year"],
- ... rain.total_rainfall_last_year,
- ... )
- ... )
- >>> sum(storms_each_year)
- 11
-
- yield_seasons yields rainfall statistics for individual seasons. Access
- these using the various provided component properties. Note that we can
- get the component to yield a total rainfall that is calibrated to the
- supplied total_rf_gaussians if we set limit to 'total__rainfall' rather
- than 'total_time' (at the cost of exactly matching the season length):
-
- >>> for field in ("rainfall__flux", "rainfall__total_depth_per_year"):
- ... _ = mg.at_node.pop(field) # clear out the existing fields
- ...
- >>> rain = SpatialPrecipitationDistribution(mg, number_of_years=2)
- >>> np.random.seed(5)
- >>> season_list = []
- >>> theoretical_median_rf_season = []
- >>> median_rf_season = []
- >>> median_rf_last_year = []
- >>> mean_rf_season = []
- >>> mean_rf_last_year = []
- >>> for storm_number in rain.yield_seasons(limit="total_rainfall"):
- ... season_list.append(rain.current_season)
- ... theoretical_median_rf_season.append(
- ... rain.target_median_total_rainfall_this_season
- ... )
- ... median_rf_season.append(rain.median_total_rainfall_this_season)
- ... median_rf_last_year.append(rain.median_total_rainfall_last_year)
- ... mean_rf_season.append(rain.total_rainfall_this_season.mean())
- ... mean_rf_last_year.append(rain.total_rainfall_last_year.mean())
- ...
- >>> season_list == ["M", "W", "M", "W"]
- True
- >>> [
- ... meas > sim
- ... for (meas, sim) in zip(median_rf_season, theoretical_median_rf_season)
- ... ] # must exceed
- [True, True, True, True]
- >>> np.isclose(median_rf_last_year[0], 0.0)
- True
- >>> for season in (0, 2): # this property must be the same in both seasons
- ... np.isclose(median_rf_last_year[season], median_rf_last_year[season + 1])
- ...
- True
- True
-
- Note that because we work here with medians, the seasonal medians don't sum
- to the year median, but the means do:
-
- >>> np.isclose(median_rf_last_year[2], median_rf_season[0] + median_rf_season[1])
- False
- >>> np.isclose(mean_rf_last_year[2], mean_rf_season[0] + mean_rf_season[1])
- True
-
- References
- ----------
- **Required Software Citation(s) Specific to this Component**
-
- Singer, M., Michaelides, K., Hobley, D. (2018). STORM 1.0: a simple,
- flexible, and parsimonious stochastic rainfall generator for simulating
- climate and climate change. Geoscientific Model Development 11(9),
- 3713-3726. https://dx.doi.org/10.5194/gmd-11-3713-2018
-
- **Additional References**
-
- None Listed
-
- """
-
- _name = "SpatialPrecipitationDistribution"
-
- _unit_agnostic = False
-
- _cite_as = """@Article{gmd-2018-86,
- title={STORM: A simple, flexible, and parsimonious stochastic rainfall
- generator for simulating climate and climate change},
- author={Singer, M. B. and Michaelides, K. and Hobley, D. E. J.},
- journal={Geoscientific Model Development Discussions},
- volume={2018},
- pages={1--25},
- year={2018},
- url={https://www.geosci-model-dev-discuss.net/gmd-2018-86/},
- doi={10.5194/gmd-2018-86}
- }"""
-
- _info = {
- "rainfall__flux": {
- "dtype": float,
- "intent": "out",
- "optional": False,
- "units": "mm/hr",
- "mapping": "node",
- "doc": "Depth of water delivered per unit time in each storm",
- },
- "rainfall__total_depth_per_year": {
- "dtype": float,
- "intent": "out",
- "optional": False,
- "units": "mm/yr",
- "mapping": "node",
- "doc": "Depth of water delivered in total in each model year",
- },
- "topographic__elevation": {
- "dtype": float,
- "intent": "in",
- "optional": True,
- "units": "m",
- "mapping": "node",
- "doc": "Land surface topographic elevation",
- },
- }
-
- def __init__(
- self, grid, number_of_years=1, orographic_scenario=None, max_numstorms=5000
- ):
- """Create the SpatialPrecipitationDistribution generator component.
-
- Parameters
- ----------
- grid : ModelGrid
- A Landlab model grid of any type.
- number_of_years : int
- The number of years over which to generate storms.
- orographic_scenario : {None, 'Singer', func}
- Whether to use no orographic rule, or to adopt S&M's 2017
- calibration for Walnut Gulch. Alternatively, provide a function
- here that turns the provided elevation of the storm center into
- a length-11 curve weighting to select which orographic scenario
- to apply.
- """
- super().__init__(grid)
-
- gaugecount = (grid.status_at_node != grid.BC_NODE_IS_CLOSED).sum()
- self._gauge_dist_km = np.zeros(gaugecount, dtype="float")
- self._temp_dataslots1 = np.zeros(gaugecount, dtype="float")
- self._temp_dataslots2 = np.zeros(gaugecount, dtype="float")
- self._numyrs = number_of_years
-
- self._max_numstorms = max_numstorms
- # This is for initializing matrices. Trailing zeros are deleted from
- # matrixes at the end of the code.
-
- assert orographic_scenario in (None, "Singer")
- self._orographic_scenario = orographic_scenario
-
- # build LL fields:
- self.initialize_output_fields()
- # bind the field to the internal variable:
- self._rain_int_gauge = self._grid.at_node["rainfall__flux"]
- self._total_rf_year = self._grid.at_node["rainfall__total_depth_per_year"]
-
- # store some info on the open node grid extent:
- open_nodes = self._grid.status_at_node != self._grid.BC_NODE_IS_CLOSED
- self._minx = self._grid.node_x[open_nodes].min()
- self._maxx = self._grid.node_x[open_nodes].max()
- self._miny = self._grid.node_y[open_nodes].min()
- self._maxy = self._grid.node_y[open_nodes].max()
- self._widthx = self._maxx - self._minx
- self._widthy = self._maxy - self._miny
- self._running_total_rainfall_this_year = self._grid.zeros(at="node")
- self._running_total_rainfall_this_season = self._grid.zeros(at="node")
-
- self._open_area = self._grid.cell_area_at_node[open_nodes].sum()
- self._scaling_to_WG = self._open_area / 275710702.0
- # ^ this is the relative size of the catchment compared to WG
-
- def yield_storms(
- self,
- limit="total_time",
- style="whole_year",
- total_rf_trend=0.0,
- storminess_trend=0.0,
- monsoon_fraction_of_year=0.42,
- monsoon_total_rf_gaussian=(("sigma", 64.0), ("mu", 207.0)),
- monsoon_storm_duration_GEV=(
- ("shape", -0.570252),
- ("sigma", 35.7389),
- ("mu", 34.1409),
- ("trunc_interval", (0.0, 1040.0)),
- ),
- monsoon_storm_area_GEV=(
- ("shape", 0.0),
- ("sigma", 2.83876e07),
- ("mu", 1.22419e08),
- ("trunc_interval", (5.0e06, 3.0e08)),
- ),
- monsoon_storm_interarrival_GEV=(
- ("shape", -0.807971),
- ("sigma", 9.4957),
- ("mu", 10.6108),
- ("trunc_interval", (0.0, 720.0)),
- ),
- monsoon_storm_radial_weakening_gaussian=(("sigma", 0.08), ("mu", 0.25)),
- winter_total_rf_gaussian=(("sigma", 52.0), ("mu", 1.65)),
- winter_storm_duration_fisk=(
- ("c", 1.0821),
- ("scale", 68.4703),
- ("trunc_interval", (0.0, 5000.0)),
- ),
- winter_storm_area_GEV=(
- ("shape", 0.0),
- ("sigma", 2.83876e07),
- ("mu", 1.22419e08),
- ("trunc_interval", (5.0e06, 3.0e08)),
- ),
- winter_storm_interarrival_GEV=(
- ("shape", 1.1131),
- ("sigma", 53.2671),
- ("mu", 47.4944),
- ("trunc_interval", (0.0, 720.0)),
- ),
- winter_storm_radial_weakening_gaussian=(
- ("sigma", 0.08),
- ("mu", 0.25),
- ("trunc_interval", (0.15, 0.67)),
- ),
- ):
- """Yield a timeseries giving the number of storms occurring each year
- in a rainfall simulation.
-
- All default distributions specified as parameters reflect values for
- Walnut Gulch, see Singer & Michaelides, 2017 & Singer et al, submitted.
-
- Parameters
- ----------
- limit : str
- Controls whether a season is defined based on its total rainfall
- (and can be any length), or by its duration (and can have any
- amount of rainfall). One of 'total_time' or 'total_rainfall'.
- If 'total_time', monsoon_fraction_of_year
- sets the fraction of a year occupied by the monsoon.
- style : str
- Controls whether the component seeks to simulate a western US-
- style "monsoonal" climate, a western US-style winter climate,
- or a full year combining both. One of 'whole_year', 'monsoonal',
- or 'winter' These distributions are by default
- based on Singer et al.'s calibrations. Note if 'monsoonal',
- the total duration of a "year" will appear to be only
- `monsoon_fraction_of_year`, and the opposite for `winter`.
- total_rf_trend : float
- Controls if a drift is applied to the total rainfall distribution
- through time. If 0., no trend. If positive, rainfall totals
- increase gradually through time. If negative, they fall through
- time. S&M recommend +/- 0.07 for a realistic climate change driven
- drift at Walnut Gulch.
- storminess_trend : float
- Controls if a drift is applied to the expected intensity of
- individual storms through time. If 0., no trend. If positive,
- storms get more intense through time, if negative, less so. S&M
- recommend +/- 0.01 for a realistic climate change driven drift at
- Walnut Gulch.
- monsoon_fraction_of_year : float
- If limit == 'total_time', sets the fraction of one year occupied
- by the monsoon season. If not, ignored. Singer's monsoon runs from
- May to September, inclusive, and the default reflects this.
- monsoon_total_rf_gaussian : dict
- Parameters defining the normal distribution controlling the total
- rainfall expected in each year. S&M use 'mu' in {143., 271.} for
- step changes up/down in rainfall totals.
- monsoon_storm_duration_GEV : dict
- Parameters defining a generalised extreme value distribution
- controlling the duration of each storm. In minutes.
- monsoon_storm_area_GEV : dict
- Parameters defining a generalised extreme value distribution
- controlling the plan view area of each storm. S&M use 'shape': 0.,
- which collapses the distribution to a plain extreme value
- distribution.
- monsoon_storm_interarrival_GEV : dict
- Parameters defining a generalised extreme value
- distribution controlling the interarrival time between each storm.
- In HRS. Note that this calibration is specifically to Walnut Gulch,
- which has an area of 275 km**2. The generator directly scales this
- resulting distribution to the area ratio of Walnut Gulch to the
- open cells of the grid. This crudely accounts for the fact that
- bigger catchments will have more storms, but note that the heavy
- tail on this distribution means the default distribution shape
- will not be trustworthy for catchments with big differences in
- size from Walnut Gulch.
- monsoon_storm_radial_weakening_gaussian : dict
- Parameters defining a normal distribution
- controlling the rate of intensity decline with distance from storm
- center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
- et al., 2005.
- winter_total_rf_gaussian : dict
- Parameters defining a normal distribution controlling the total
- rainfall expected in each year. S&M use 'mu' in {143., 271.} for
- step changes up/down in rainfall totals.
- winter_storm_duration_fisk : dict
- Parameters defining a Fisk (i.e., log-logistic) distribution
- controlling the duration of each storm. Note this differs from the
- summer scaling. In Minutes.
- winter_storm_area_GEV is a generalised extreme value distribution
- controlling the plan view area of each storm. S&M use 'shape': 0.,
- which collapses the distribution to a plain extreme value
- distribution.
- winter_storm_interarrival_GEV : dict
- Parameters defining a generalised extreme value
- distribution controlling the interarrival time between each storm.
- In HRS. The same considerations apply here as for the monsoonal
- interstorm equivalent.
- winter_storm_radial_weakening_gaussian : dict
- Parameters defining a normal distribution
- controlling the rate of intensity decline with distance from storm
- center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
- et al., 2005.
-
- Yields
- ------
- (storm_t, interval_t) : (float, float)
- Tuple pair of duration of a single storm, then the interstorm
- interval that follows it. In hrs. The rainfall__flux field
- describes the rainfall rate during the interval storm_t as the
- tuple is yielded. In HRS.
- Note that the rainfall__total_depth_per_year field gives the total
- accumulated rainfall depth during the *last completed* model year,
- not the year to the point of yield. For the latter, use the
- property `total_rainfall_this_year`.
- """
- return self._run_the_process(
- yield_storms=True,
- yield_years=False,
- yield_seasons=False,
- limit=limit,
- style=style,
- monsoon_fraction_of_year=monsoon_fraction_of_year,
- total_rf_trend=total_rf_trend,
- storminess_trend=storminess_trend,
- monsoon_total_rf_gaussian=monsoon_total_rf_gaussian,
- monsoon_storm_duration_GEV=monsoon_storm_duration_GEV,
- monsoon_storm_area_GEV=monsoon_storm_area_GEV,
- monsoon_storm_interarrival_GEV=monsoon_storm_interarrival_GEV,
- monsoon_storm_radial_weakening_gaussian=monsoon_storm_radial_weakening_gaussian,
- winter_total_rf_gaussian=winter_total_rf_gaussian,
- winter_storm_duration_fisk=winter_storm_duration_fisk,
- winter_storm_area_GEV=winter_storm_area_GEV,
- winter_storm_interarrival_GEV=winter_storm_interarrival_GEV,
- winter_storm_radial_weakening_gaussian=winter_storm_radial_weakening_gaussian,
- )
-
- def yield_years(
- self,
- limit="total_time",
- style="whole_year",
- total_rf_trend=0.0,
- storminess_trend=0.0,
- monsoon_fraction_of_year=0.42,
- monsoon_total_rf_gaussian=(("sigma", 64.0), ("mu", 207.0)),
- monsoon_storm_duration_GEV=(
- ("shape", -0.570252),
- ("sigma", 35.7389),
- ("mu", 34.1409),
- ("trunc_interval", (1.0, 1040.0)),
- ),
- monsoon_storm_area_GEV=(
- ("shape", 0.0),
- ("sigma", 2.83876e07),
- ("mu", 1.22419e08),
- ("trunc_interval", (5.0e06, 3.0e08)),
- ),
- monsoon_storm_interarrival_GEV=(
- ("shape", -0.807971),
- ("sigma", 9.4957),
- ("mu", 10.6108),
- ("trunc_interval", (0.0, 720.0)),
- ),
- monsoon_storm_radial_weakening_gaussian=(
- ("sigma", 0.08),
- ("mu", 0.25),
- ("trunc_interval", (0.15, 0.67)),
- ),
- winter_total_rf_gaussian=(("sigma", 52.0), ("mu", 1.65)),
- winter_storm_duration_fisk=(
- ("c", 1.0821),
- ("scale", 68.4703),
- ("trunc_interval", (1.0, 5000.0)),
- ),
- winter_storm_area_GEV=(
- ("shape", 0.0),
- ("sigma", 2.83876e07),
- ("mu", 1.22419e08),
- ("trunc_interval", (5.0e06, 3.0e08)),
- ),
- winter_storm_interarrival_GEV=(
- ("shape", 1.1131),
- ("sigma", 53.2671),
- ("mu", 47.4944),
- ("trunc_interval", (0.0, 720.0)),
- ),
- winter_storm_radial_weakening_gaussian=(
- ("sigma", 0.08),
- ("mu", 0.25),
- ("trunc_interval", (0.15, 0.67)),
- ),
- ):
- """Yield a timeseries giving the number if storms occurring each year
- in a rainfall simulation.
-
- All default distributions specified as parameters reflect values for
- Walnut Gulch, see Singer & Michaelides, 2017 & Singer et al, submitted.
-
- Parameters
- ----------
- limit : ('total_time', 'total_rainfall')
- Controls whether a season is defined based on its total rainfall
- (and can be any length), or by its duration (and can have any
- amount of rainfall). If 'total_time', monsoon_fraction_of_year
- sets the fraction of a year occupied by the monsoon.
- style : ('whole_year', 'monsoonal', 'winter')
- Controls whether the component seeks to simulate a western US-
- style "monsoonal" climate, a western US-style winter climate,
- or a full year combining both. These distributions are by default
- based on Singer et al.'s calibrations. Note if 'monsoonal',
- the total duration of a "year" will appear to be only
- `monsoon_fraction_of_year`, and the opposite for `winter`.
- total_rf_trend : float
- Controls if a drift is applied to the total rainfall distribution
- through time. If 0., no trend. If positive, rainfall totals
- increase gradually through time. If negative, they fall through
- time. S&M recommend +/- 0.07 for a realistic climate chage driven
- drift at Walnut Gulch.
- storminess_trend : float
- Controls if a drift is applied to the expected intensity of
- individual storms through time. If 0., no trend. If positive,
- storms get more intense through time, if negative, less so. S&M
- recommend +/- 0.01 for a realistic climate change driven drift at
- Walnut Gulch.
- monsoon_fraction_of_year : float
- If limit == 'total_time', sets the fraction of one year occupied
- by the monsoon season. If not, ignored. Singer's monsoon runs from
- May to September, inclusive, and the default reflects this.
-
- monsoon_total_rf_gaussian is a normal distribution controlling the
- total rainfall expected in each year. S&M use 'mu' in {143., 271.}
- for step changes up/down in rainfall totals. In mm.
- monsoon_storm_duration_GEV is a generalised extreme value distribution
- controlling the duration of each storm. In MIN.
- monsoon_storm_area_GEV is a generalised extreme value distribution
- controlling the plan view area of each storm. S&M use 'shape': 0.,
- which collapses the distribution to a plain extreme value
- distribution.
- monsoon_storm_interarrival_GEV is a generalised extreme value
- distribution controlling the interarrival time between each storm.
- In HRS. Note that this calibration is specifically to Walnut Gulch,
- which has an area of 275 km**2. The generator directly scales this
- resulting distribution to the area ratio of Walnut Gulch to the
- open cells of the grid. This crudely accounts for the fact that
- bigger catchments will have more storms, but note that the heavy
- tail on this distribution means the default distribution shape
- will not be trustworthy for catchments with big differences in
- size from Walnut Gulch.
- monsoon_storm_radial_weakening_gaussian is a normal distribution
- controlling the rate of intensity decline with distance from storm
- center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
- et al., 2005.
-
- winter_total_rf_gaussian is a normal distribution controlling the total
- rainfall expected in each year. S&M use 'mu' in {143., 271.} for
- step changes up/down in rainfall totals.
- winter_storm_duration_fisk is a Fisk (i.e., log-logistic) distribution
- controlling the duration of each storm. Note this differs from the
- summer scaling. In MIN.
- winter_storm_area_GEV is a generalised extreme value distribution
- controlling the plan view area of each storm. S&M use 'shape': 0.,
- which collapses the distribution to a plain extreme value
- distribution.
- winter_storm_interarrival_GEV is a generalised extreme value
- distribution controlling the interarrival time between each storm.
- In HRS. The same considerations apply here as for the monsoonal
- interstorm equivalent.
- winter_storm_radial_weakening_gaussian is a normal distribution
- controlling the rate of intensity decline with distance from storm
- center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
- et al., 2005.
-
- Yields
- ------
- number_of_storms_per_year : float
- Float that gives the number of storms simulated in the year that
- elapsed since the last yield. The rainfall__total_depth_per_year
- field gives the total accumulated rainfall depth during the year
- preceding the yield. rainfall__flux gives the rainfall intensity of
- the last storm in that year.
- """
- return self._run_the_process(
- yield_storms=False,
- yield_years=True,
- yield_seasons=False,
- limit=limit,
- style=style,
- total_rf_trend=total_rf_trend,
- storminess_trend=storminess_trend,
- monsoon_fraction_of_year=monsoon_fraction_of_year,
- monsoon_total_rf_gaussian=monsoon_total_rf_gaussian,
- monsoon_storm_duration_GEV=monsoon_storm_duration_GEV,
- monsoon_storm_area_GEV=monsoon_storm_area_GEV,
- monsoon_storm_interarrival_GEV=monsoon_storm_interarrival_GEV,
- monsoon_storm_radial_weakening_gaussian=monsoon_storm_radial_weakening_gaussian,
- winter_total_rf_gaussian=winter_total_rf_gaussian,
- winter_storm_duration_fisk=winter_storm_duration_fisk,
- winter_storm_area_GEV=winter_storm_area_GEV,
- winter_storm_interarrival_GEV=winter_storm_interarrival_GEV,
- winter_storm_radial_weakening_gaussian=winter_storm_radial_weakening_gaussian,
- )
-
- def yield_seasons(
- self,
- limit="total_time",
- style="whole_year",
- total_rf_trend=0.0,
- storminess_trend=0.0,
- monsoon_fraction_of_year=0.42,
- monsoon_total_rf_gaussian=(("sigma", 64.0), ("mu", 207.0)),
- monsoon_storm_duration_GEV=(
- ("shape", -0.570252),
- ("sigma", 35.7389),
- ("mu", 34.1409),
- ("trunc_interval", (1.0, 1040.0)),
- ),
- monsoon_storm_area_GEV=(
- ("shape", 0.0),
- ("sigma", 2.83876e07),
- ("mu", 1.22419e08),
- ("trunc_interval", (5.0e06, 3.0e08)),
- ),
- monsoon_storm_interarrival_GEV=(
- ("shape", -0.807971),
- ("sigma", 9.4957),
- ("mu", 10.6108),
- ("trunc_interval", (0.0, 720.0)),
- ),
- monsoon_storm_radial_weakening_gaussian=(
- ("sigma", 0.08),
- ("mu", 0.25),
- ("trunc_interval", (0.15, 0.67)),
- ),
- winter_total_rf_gaussian=(("sigma", 52.0), ("mu", 1.65)),
- winter_storm_duration_fisk=(
- ("c", 1.0821),
- ("scale", 68.4703),
- ("trunc_interval", (1.0, 5000.0)),
- ),
- winter_storm_area_GEV=(
- ("shape", 0.0),
- ("sigma", 2.83876e07),
- ("mu", 1.22419e08),
- ("trunc_interval", (5.0e06, 3.0e08)),
- ),
- winter_storm_interarrival_GEV=(
- ("shape", 1.1131),
- ("sigma", 53.2671),
- ("mu", 47.4944),
- ("trunc_interval", (0.0, 720.0)),
- ),
- winter_storm_radial_weakening_gaussian=(
- ("sigma", 0.08),
- ("mu", 0.25),
- ("trunc_interval", (0.15, 0.67)),
- ),
- ):
- """Yield a timeseries giving the number if storms occurring each season
- in a rainfall simulation. Only meaningfully different from yield_years
- if style=='whole_year'.
-
- All default distributions specified as parameters reflect values for
- Walnut Gulch, see Singer & Michaelides, 2017 & Singer et al, submitted.
-
- Parameters
- ----------
- limit : ('total_time', 'total_rainfall')
- Controls whether a season is defined based on its total rainfall
- (and can be any length), or by its duration (and can have any
- amount of rainfall). If 'total_time', monsoon_fraction_of_year
- sets the fraction of a year occupied by the monsoon.
- style : ('whole_year', 'monsoonal', 'winter')
- Controls whether the component seeks to simulate a western US-
- style "monsoonal" climate, a western US-style winter climate,
- or a full year combining both. These distributions are by default
- based on Singer et al.'s calibrations. Note if 'monsoonal',
- the total duration of a "year" will appear to be only
- `monsoon_fraction_of_year`, and the opposite for `winter`.
- total_rf_trend : float
- Controls if a drift is applied to the total rainfall distribution
- through time. If 0., no trend. If positive, rainfall totals
- increase gradually through time. If negative, they fall through
- time. S&M recommend +/- 0.07 for a realistic climate chage driven
- drift at Walnut Gulch.
- storminess_trend : float
- Controls if a drift is applied to the expected intensity of
- individual storms through time. If 0., no trend. If positive,
- storms get more intense through time, if negative, less so. S&M
- recommend +/- 0.01 for a realistic climate change driven drift at
- Walnut Gulch.
- monsoon_fraction_of_year : float
- If limit == 'total_time', sets the fraction of one year occupied
- by the monsoon season. If not, ignored. Singer's monsoon runs from
- May to September, inclusive, and the default reflects this.
-
- monsoon_total_rf_gaussian is a normal distribution controlling the
- total rainfall expected in each year. S&M use 'mu' in {143., 271.}
- for step changes up/down in rainfall totals. In mm.
- monsoon_storm_duration_GEV is a generalised extreme value distribution
- controlling the duration of each storm. In MIN.
- monsoon_storm_area_GEV is a generalised extreme value distribution
- controlling the plan view area of each storm. S&M use 'shape': 0.,
- which collapses the distribution to a plain extreme value
- distribution.
- monsoon_storm_interarrival_GEV is a generalised extreme value
- distribution controlling the interarrival time between each storm.
- In HRS. Note that this calibration is specifically to Walnut Gulch,
- which has an area of 275 km**2. The generator directly scales this
- resulting distribution to the area ratio of Walnut Gulch to the
- open cells of the grid. This crudely accounts for the fact that
- bigger catchments will have more storms, but note that the heavy
- tail on this distribution means the default distribution shape
- will not be trustworthy for catchments with big differences in
- size from Walnut Gulch.
- monsoon_storm_radial_weakening_gaussian is a normal distribution
- controlling the rate of intensity decline with distance from storm
- center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
- et al., 2005.
-
- winter_total_rf_gaussian is a normal distribution controlling the total
- rainfall expected in each year. S&M use 'mu' in {143., 271.} for
- step changes up/down in rainfall totals.
- winter_storm_duration_fisk is a Fisk (i.e., log-logistic) distribution
- controlling the duration of each storm. Note this differs from the
- summer scaling. In MIN.
- winter_storm_area_GEV is a generalised extreme value distribution
- controlling the plan view area of each storm. S&M use 'shape': 0.,
- which collapses the distribution to a plain extreme value
- distribution.
- winter_storm_interarrival_GEV is a generalised extreme value
- distribution controlling the interarrival time between each storm.
- In HRS. The same considerations apply here as for the monsoonal
- interstorm equivalent.
- winter_storm_radial_weakening_gaussian is a normal distribution
- controlling the rate of intensity decline with distance from storm
- center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
- et al., 2005.
-
- Yields
- ------
- number_of_storms_per_season : float
- Float that gives the number of storms simulated in the season that
- elapsed since the last yield. The rainfall__total_depth_per_year
- field gives the total accumulated rainfall depth during the *year*
- preceding the yield, *so far*. rainfall__flux gives the rainfall
- intensity of the last storm in that year.
- NB: Use the component property total_rainfall_last_season to access
- the *actual* amount of rainfall in the season that has the number
- of storms that the method generates.
- """
- return self._run_the_process(
- yield_storms=False,
- yield_years=False,
- yield_seasons=True,
- limit=limit,
- style=style,
- total_rf_trend=total_rf_trend,
- storminess_trend=storminess_trend,
- monsoon_fraction_of_year=monsoon_fraction_of_year,
- monsoon_total_rf_gaussian=monsoon_total_rf_gaussian,
- monsoon_storm_duration_GEV=monsoon_storm_duration_GEV,
- monsoon_storm_area_GEV=monsoon_storm_area_GEV,
- monsoon_storm_interarrival_GEV=monsoon_storm_interarrival_GEV,
- monsoon_storm_radial_weakening_gaussian=monsoon_storm_radial_weakening_gaussian,
- winter_total_rf_gaussian=winter_total_rf_gaussian,
- winter_storm_duration_fisk=winter_storm_duration_fisk,
- winter_storm_area_GEV=winter_storm_area_GEV,
- winter_storm_interarrival_GEV=winter_storm_interarrival_GEV,
- winter_storm_radial_weakening_gaussian=winter_storm_radial_weakening_gaussian,
- )
-
- def _run_the_process(
- self,
- yield_storms=True,
- yield_years=False,
- yield_seasons=False,
- limit="total_time",
- style="whole_year",
- monsoon_fraction_of_year=0.42,
- total_rf_trend=0.0,
- storminess_trend=0.0,
- monsoon_total_rf_gaussian=(("sigma", 64.0), ("mu", 207.0)),
- monsoon_storm_duration_GEV=(
- ("shape", -0.570252),
- ("sigma", 35.7389),
- ("mu", 34.1409),
- ("trunc_interval", (1.0, 1040.0)),
- ),
- monsoon_storm_area_GEV=(
- ("shape", 0.0),
- ("sigma", 2.83876e07),
- ("mu", 1.22419e08),
- ("trunc_interval", (5.0e06, 3.0e08)),
- ),
- monsoon_storm_interarrival_GEV=(
- ("shape", -0.807971),
- ("sigma", 9.4957),
- ("mu", 10.6108),
- ("trunc_interval", (0.0, 720.0)),
- ),
- monsoon_storm_radial_weakening_gaussian=(
- ("sigma", 0.08),
- ("mu", 0.25),
- ("trunc_interval", (0.15, 0.67)),
- ),
- winter_total_rf_gaussian=(("sigma", 52.0), ("mu", 1.65)),
- winter_storm_duration_fisk=(
- ("c", 1.0821),
- ("scale", 68.4703),
- ("trunc_interval", (1.0, 5000.0)),
- ),
- winter_storm_area_GEV=(
- ("shape", 0.0),
- ("sigma", 2.83876e07),
- ("mu", 1.22419e08),
- ("trunc_interval", (5.0e06, 3.0e08)),
- ),
- winter_storm_interarrival_GEV=(
- ("shape", 1.1131),
- ("sigma", 53.2671),
- ("mu", 47.4944),
- ("trunc_interval", (0.0, 720.0)),
- ),
- winter_storm_radial_weakening_gaussian=(
- ("sigma", 0.08),
- ("mu", 0.25),
- ("trunc_interval", (0.15, 0.67)),
- ),
- ):
- """This is the underlying process that runs the component, but it
- should be run by a user through the yield_storms and yield_years
- methods.
-
- Fuzz to the chosen values is now selected from a continuous
- distribution, not from integer values.
-
- total_rf_trend controls if a drift is applied to the total rainfall
- distribution through time. If 0., no trend. If positive, rainfall
- totals increase gradually through time. If negative, they fall through
- time. S&M recommend +/- 0.07 for a realistic climate chage driven drift
- at Walnut Gulch.
-
- storminess_trend controls if a drift is applied to the expected
- intensity of individual storms through time. If 0., no trend. If
- positive, storms get more intense through time, if negative, less so.
- S&M recommend +/- 0.01 for a realistic climate change driven drift at
- Walnut Gulch.
-
- All default distributions reflect values for Walnut Gulch, see Singer &
- Michaelides, submitted:
-
- monsoon_total_rf_gaussian is a normal distribution controlling the
- total rainfall expected in each year. S&M use 'mu' in {143., 271.}
- for step changes up/down in rainfall totals. In mm.
- monsoon_storm_duration_GEV is a generalised extreme value distribution
- controlling the duration of each storm. In MIN.
- monsoon_storm_area_GEV is a generalised extreme value distribution
- controlling the plan view area of each storm. S&M use 'shape': 0.,
- which collapses the distribution to a plain extreme value
- distribution.
- monsoon_storm_interarrival_GEV is a generalised extreme value
- distribution controlling the interarrival time between each storm.
- In HRS. Note that this calibration is specifically to Walnut Gulch,
- which has an area of 275 km**2. The generator directly scales this
- resulting distribution to the area ratio of Walnut Gulch to the
- open cells of the grid. This crudely accounts for the fact that
- bigger catchments will have more storms, but note that the heavy
- tail on this distribution means the default distribution shape
- will not be trustworthy for catchments with big differences in
- size from Walnut Gulch.
- monsoon_storm_radial_weakening_gaussian is a normal distribution
- controlling the rate of intensity decline with distance from storm
- center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
- et al., 2005.
- winter_total_rf_gaussian is a normal distribution controlling the total
- rainfall expected in each year. S&M use 'mu' in {143., 271.} for
- step changes up/down in rainfall totals.
- winter_storm_duration_fisk is a Fisk (i.e., log-logistic) distribution
- controlling the duration of each storm. Note this differs from the
- summer scaling. In MIN.
- winter_storm_area_GEV is a generalised extreme value distribution
- controlling the plan view area of each storm. S&M use 'shape': 0.,
- which collapses the distribution to a plain extreme value
- distribution.
- winter_storm_interarrival_GEV is a generalised extreme value
- distribution controlling the interarrival time between each storm.
- In HRS. The same considerations apply here as for the monsoonal
- interstorm equivalent.
- winter_storm_radial_weakening_gaussian is a normal distribution
- controlling the rate of intensity decline with distance from storm
- center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
- et al., 2005.
- """
- monsoon_total_rf_gaussian = dict(monsoon_total_rf_gaussian)
- monsoon_storm_duration_GEV = dict(monsoon_storm_duration_GEV)
- monsoon_storm_area_GEV = dict(monsoon_storm_area_GEV)
- monsoon_storm_interarrival_GEV = dict(monsoon_storm_interarrival_GEV)
- monsoon_storm_radial_weakening_gaussian = dict(
- monsoon_storm_radial_weakening_gaussian
- )
- winter_total_rf_gaussian = dict(winter_total_rf_gaussian)
- winter_storm_duration_fisk = dict(winter_storm_duration_fisk)
- winter_storm_area_GEV = dict(winter_storm_area_GEV)
- winter_storm_interarrival_GEV = dict(winter_storm_interarrival_GEV)
- winter_storm_radial_weakening_gaussian = dict(
- winter_storm_radial_weakening_gaussian
- )
-
- FUZZMETHOD = "DEJH"
- FUZZWIDTH = 5.0 # if DEJH
- self._phantom_storm_count = 0
- # ^this property tracks the number of storms in the run that received
- # zero intensity (and thus didn't really exist)
- self._opennodes = self._grid.status_at_node != self._grid.BC_NODE_IS_CLOSED
- self._total_rainfall_last_season = self._grid.zeros(at="node")
-
- # safety check for init conds:
- if yield_storms:
- assert yield_years is False
- assert yield_seasons is False
- if yield_years:
- assert yield_storms is False
- assert yield_seasons is False
- if yield_seasons:
- assert yield_storms is False
- assert yield_years is False
-
- # add variable for number of simulations of simyears
- simyears = self._numyrs # number of years to simulate
- numcurves = 11 # number of intensity-duration curves (see below for
- # curve equations)
- hrsinyr = 24.0 * 365.0
- hrsinmonsoon = monsoon_fraction_of_year * hrsinyr
- hrsinwinter = (1.0 - monsoon_fraction_of_year) * hrsinyr
-
- assert limit in ("total_rainfall", "total_time")
-
- assert style in ("whole_year", "monsoonal", "winter")
- if style == "whole_year":
- reps = 2
- else:
- reps = 1
-
- opennodes = self._opennodes
- num_opennodes = np.sum(opennodes)
- IDs_open = np.where(opennodes)[0] # need this later
- X1 = self._grid.node_x
- Y1 = self._grid.node_y
- Xin = X1[opennodes]
- Yin = Y1[opennodes]
- try:
- Zz = self._grid.at_node["topographic__elevation"][opennodes]
- except KeyError:
- assert self._orographic_scenario is None
- numgauges = Xin.size # number of rain gauges in the basin.
- # NOTE: In this version this produces output on a grid, rather than at
- # real gauge locations.
-
- assert FUZZMETHOD == "DEJH", "The Singer method for fuzz is no longer supported"
-
- # lambda_, kappa, and C are parameters of the intensity-duration curves
- # of the form: intensity =
- # lambda*exp(-0.508*duration)+kappa*exp(-0.008*duration)+C
- lambda_ = [
- 642.2,
- 578.0,
- 513.8,
- 449.5,
- 385.3,
- 321.1,
- 256.9,
- 192.7,
- 128.4,
- 64.1,
- 21.0,
- ]
- kappa = [93.1, 83.8, 74.5, 65.2, 55.9, 46.6, 37.2, 27.9, 18.6, 9.3, 0.9]
- C = [4.5, 4.0, 3.5, 3.0, 2.5, 2.0, 1.5, 1.0, 0.5, 0.25, 0.05]
-
- # Unlike MS's original implementation, we no longer pull ET values, as
- # this should be a different component.
-
- self._Ptot_ann_global = np.zeros(simyears)
- self._Ptot_monsoon_global = np.zeros(simyears)
-
- master_storm_count = 0
- storm_trend = 0
-
- for syear in range(simyears):
- self._year = syear
- year_time = 0.0 # tracks simulation time per year in hours
- storm_trend += storminess_trend
- year_storm_count = 0
- breaker = False
- Storm_total_local_year = np.zeros((self._max_numstorms, num_opennodes))
- self._storm_running_sum_of_seasons = np.zeros(num_opennodes)
- self._storm_running_sum_1st_seas = np.zeros(num_opennodes)
-
- storms_yr_so_far = 0
- for seas in range(reps):
- seas_time = 0.0 # tracks elapsed season time in hours
- Storm_running_sum_seas = np.zeros((2, num_opennodes))
- # ^ 1st col is running total, 2nd is data to add to it
- if seas == 0 and style != "winter":
- self._current_season = "M"
- # This is the pdf fitted to all available station precip
- # data (normal dist). It will be sampled below.
- Ptot_pdf_norm = monsoon_total_rf_gaussian
-
- # This is the pdf fitted to all available station duration
- # data (GEV dist). It will be sampled below.
- # #### matlab's GEV is (shape_param, scale(sigma), pos(mu))
- # note that in Scipy, we must add a minus to the shape
- # param for a GEV to match Matlab's implementation
- Duration_pdf = monsoon_storm_duration_GEV
- # This is the pdf fitted to all available station area
- # data (EV dist). It will be sampled below.
- # #### matlab's EV is (mu, sigma)
- Area_pdf_EV = monsoon_storm_area_GEV
- # This is the pdf fitted to all available station area
- # data (GEV dist). It will be sampled below.
- Int_arr_pdf_GEV = monsoon_storm_interarrival_GEV
- # This is the pdf of storm gradient recession coefficients
- # from Morin et al, 2005 (normal dist). It will be sampled
- # below.
- Recess_pdf_norm = monsoon_storm_radial_weakening_gaussian
- seas_total = hrsinmonsoon
- else:
- self._current_season = "W"
- Ptot_pdf_norm = winter_total_rf_gaussian
- Duration_pdf = winter_storm_duration_fisk
- Area_pdf_EV = winter_storm_area_GEV
- Int_arr_pdf_GEV = winter_storm_interarrival_GEV
- Recess_pdf_norm = winter_storm_radial_weakening_gaussian
- seas_total = hrsinwinter
-
- if not np.isclose(total_rf_trend, 0.0):
- mu = Ptot_pdf_norm.pop("mu")
- mu += mu * total_rf_trend
- Ptot_pdf_norm["mu"] = mu
- # sample from normal distribution and saves global value of
- # Ptot (that must be equalled or exceeded) for each year
- season_rf_limit = self.calc_annual_rainfall(
- style=style, monsoon_total_rf_gaussian=Ptot_pdf_norm
- )[seas]
- self._season_rf_limit = season_rf_limit
- self._Ptot_ann_global[syear] += season_rf_limit
- if seas == 0 and style != "winter":
- self._Ptot_monsoon_global[syear] = season_rf_limit
- Storm_total_local_seas = np.zeros((self._max_numstorms, num_opennodes))
- seas_cum_Ptot_gauge = np.zeros(numgauges)
- self._entries = 0
-
- for seas_storm_count, storm in enumerate(range(self._max_numstorms)):
- self._rain_int_gauge.fill(0.0)
- int_arr_val = genextreme.rvs(
- c=Int_arr_pdf_GEV["shape"],
- loc=Int_arr_pdf_GEV["mu"],
- scale=Int_arr_pdf_GEV["sigma"],
- )
- try:
- int_arr_val = np.clip(
- int_arr_val,
- Int_arr_pdf_GEV["trunc_interval"][0],
- Int_arr_pdf_GEV["trunc_interval"][1],
- )
- except KeyError:
- # ...just in case
- if int_arr_val < 0.0:
- int_arr_val = 0.0
- # now, correct the scaling relative to WG
- int_arr_val /= self._scaling_to_WG
- self._int_arr_val = int_arr_val
- # ^Samples from distribution of interarrival times (hr).
- # This can be used to develop STORM output for use in
- # rainfall-runoff models or any water balance application.
- # sample uniformly from storm center matrix from grid w
- # 10 m spacings covering basin:
-
- area_val = genextreme.rvs(
- c=Area_pdf_EV["shape"],
- loc=Area_pdf_EV["mu"],
- scale=Area_pdf_EV["sigma"],
- )
- try:
- area_val = np.clip(
- area_val,
- Area_pdf_EV["trunc_interval"][0],
- Area_pdf_EV["trunc_interval"][1],
- )
- except KeyError:
- # ...just in case
- if area_val < 0.0:
- area_val = 0.0
- self._area_val = area_val
- # ^Samples from distribution of storm areas
-
- r = np.sqrt(area_val / np.pi) # value here shd be selected
- rsq = r**2
- # based on area above in meters to match the UTM values
-
- # This way of handling storm locations is really quite
- # different to MS's. He uses a fixed buffer width, and
- # throws away any storm that doesn't intersect. We
- # instead retain all storms, and *make sure* the storm
- # intersects using a dynamic buffer. MS's method will
- # preferentially sample larger storms, though unclear
- # what that would mean in practice.
- # MS also snaps his storms onto the grid. This seems
- # unnecessary, and we don't do it here.
- while 1:
- cx, cy = self._locate_storm(r)
- # Determine which gauges are hit by Euclidean geometry:
- gdist = (Xin - cx) ** 2 + (Yin - cy) ** 2
- mask_name = gdist <= rsq # this is defacto MS's aa
- # this short circuits the storm loop in the case that
- # the storm does not affect any 'gauging' location
- if np.any(np.equal(mask_name, True)):
- break
-
- self._x = cx
- self._y = cy
- year_storm_count += 1
- seas_storm_count += 1
- master_storm_count += 1
-
- # This routine below determines to which orographic group
- # the closest gauge to the storm center belongs to, and
- # censors the number of curves accordingly
- # missing top curve in GR1, top and bottom curves for GR2,
- # and bottom curve for GR3
- # NOTE again, DEJH thinks this could be generalised a lot
-
- # original curve# probs for 30%-20%-10%: [0.0636, 0.0727,
- # 0.0819, 0.0909, 0.0909, 0.0909, 0.0909, 0.0909, 0.1001,
- # 0.1090, 0.1182]
- # original curve# probs are modified as below
- # add weights to reflect reasonable probabilities that
- # favor lower curves:
- if self._orographic_scenario is not None:
- # this routine below allows for orography in precip by
- # first determining the closest gauge and then
- # determining its orographic grouping
- cc = np.argmin(gdist)
- closest_gauge_z = Zz[cc] # this will be
- # compared against orographic gauge groupings to
- # determine the appropriate set of intensity-duration
- # curves
- if self._orographic_scenario == "Singer":
- wgts = Singer_orographic_rainfall(closest_gauge_z)
- else:
- wgts = self._orographic_scenario(closest_gauge_z)
- elif self._orographic_scenario is None:
- wgts = [
- 0.0636,
- 0.0727,
- 0.0819,
- 0.0909,
- 0.0909,
- 0.0909,
- 0.0909,
- 0.0909,
- 0.1001,
- 0.1090,
- 0.1182,
- ]
- if seas == 0 and style != "winter":
- duration_val = genextreme.rvs(
- c=Duration_pdf["shape"],
- loc=Duration_pdf["mu"],
- scale=Duration_pdf["sigma"],
- )
- else:
- duration_val = fisk.rvs(
- c=Duration_pdf["c"], scale=Duration_pdf["scale"]
- )
- # hacky fix to prevent occasional < 0 values:
- # (I think because Matlab is able to set limits manually)
- try:
- duration_val = np.clip(
- duration_val,
- Duration_pdf["trunc_interval"][0],
- Duration_pdf["trunc_interval"][1],
- )
- except KeyError:
- # ...just in case
- if duration_val < 0.0:
- duration_val = 0.0
- durationhrs = duration_val / 60.0
- self._durationhrs = durationhrs
- year_time += durationhrs
- seas_time += durationhrs
- # we will always do the next storm, even if it exceeds the
- # specified "total" time
-
- # which curve did we pick?:
- int_dur_curve_val = np.random.choice(numcurves, p=wgts)
-
- intensity_val = (
- lambda_[int_dur_curve_val] * np.exp(-0.508 * duration_val)
- + kappa[int_dur_curve_val] * np.exp(-0.008 * duration_val)
- + C[int_dur_curve_val]
- )
- # ...these curves are based on empirical data from WG
-
- # this dist should look identical, w/o discretisation
- fuzz_int_val = FUZZWIDTH * 2.0 * (np.random.rand() - 0.5)
-
- intensity_val += fuzz_int_val
- # ^this allows for specified fuzzy tolerance around
- # selected intensity (but it can go -ve)
- # formerly, here MS used a rounding and threshold to
- # prevent storms with a value < 1. We're going to remove
- # the rounding and threshold at zero instead. (below)
-
- # This scales the storm center intensity upward, so the
- # values at each gauge are realistic once the gradient is
- # applied.
- intensity_val += intensity_val * storm_trend
- # storminess trend is applied and its effect rises each
- # year of simulation
- # DEJH has removed the rounding
- # Note that is is now possible for intensity_val to go
- # negative, so:
- if intensity_val < 0.0:
- intensity_val = 0.0
- self._phantom_storm_count += 1
- # note storms of zero intensity are now permitted (though
- # should hopefully remain pretty rare.)
- self._intensity_val = intensity_val
-
- # area to determine which gauges are hit:
- recess_val = np.random.normal(
- loc=Recess_pdf_norm["mu"], scale=Recess_pdf_norm["sigma"]
- )
- with contextlib.suppress(KeyError):
- recess_val = np.clip(
- recess_val,
- Recess_pdf_norm["trunc_interval"][0],
- Recess_pdf_norm["trunc_interval"][1],
- )
- self._recess_val = recess_val
- # this pdf of recession coefficients determines how
- # intensity declines with distance from storm center (see
- # below)
- # determine cartesian distances to all hit gauges and
- # associated intensity values at each gauge hit by the
- # storm
- # This is a data storage solution to avoid issues that can
- # arise with slicing grid areas with heavy tailed sizes
- self._entries = np.sum(mask_name) # only open nodes
- entries = self._entries
- # NOTE _gauge_dist_km only contains nodes under the storm!
- # The remaining entries are garbage
- # Xin -> only the open nodes, note
- self._gauge_dist_km[:entries] = np.sqrt(gdist[mask_name]) / 1000.0
- self._temp_dataslots2[:entries] = gdist[mask_name] / 1.0e6
- self._temp_dataslots2[:entries] *= -2.0 * recess_val**2
- np.exp(
- self._temp_dataslots2[:entries],
- out=self._temp_dataslots2[:entries],
- )
- self._temp_dataslots2[:entries] *= intensity_val
- mask_incl_closed = IDs_open[mask_name]
- self._nodes_hit = mask_incl_closed
- # ^note this is by ID, not bool
- self._rain_int_gauge[mask_incl_closed] = self._temp_dataslots2[
- :entries
- ]
- # calc of _rain_int_gauge follows Rodriguez-Iturbe et al.,
- # 1986; Morin et al., 2005 but sampled from a distribution
- # only need to add the bit that got rained on, so:
- self._temp_dataslots2[:entries] *= duration_val / 60.0
- seas_cum_Ptot_gauge[mask_name] += self._temp_dataslots2[:entries]
- # collect storm totals for all gauges into rows by storm
- Storm_total_local_seas[storm, :] = (
- self._rain_int_gauge[opennodes] * duration_val / 60.0
- )
- Storm_total_local_year[(storm + storms_yr_so_far), :] = (
- Storm_total_local_seas[storm, :]
- )
- self._max_storm_depth = Storm_total_local_seas[storm, :].max()
-
- self._Storm_total_local_seas = Storm_total_local_seas
- self._Storm_total_local_year = Storm_total_local_year
- Storm_running_sum_seas[1, :] = Storm_total_local_seas[storm, :]
- np.nansum(
- Storm_running_sum_seas, axis=0, out=Storm_running_sum_seas[0, :]
- )
- if np.any(Storm_total_local_seas < 0.0):
- raise ValueError(syear, storm)
- self._median_seas_rf_total = np.nanmedian(
- Storm_running_sum_seas[0, :]
- )
- self._Storm_running_sum_seas = Storm_running_sum_seas[0, :]
-
- if limit == "total_time":
- if seas_time + int_arr_val > seas_total:
- int_arr_val = (seas_total - seas_time).clip(0.0)
- breaker = True
- else:
- if self._median_seas_rf_total > season_rf_limit:
- breaker = True
- if yield_storms is True:
- yield (durationhrs, int_arr_val)
- seas_time += int_arr_val
- year_time += int_arr_val
- if breaker:
- # Don't create Ptotal_local per MS... just
- breaker = False
- break
- if storm + 1 == self._max_numstorms:
- raise ValueError("_max_numstorms set too low for this run")
- storms_yr_so_far = seas_storm_count
- self._storm_running_sum_of_seasons += Storm_running_sum_seas[0, :]
- self._total_rainfall_last_season[self._opennodes] = (
- Storm_running_sum_seas[0, :]
- )
- self._storm_running_sum_1st_seas += Storm_running_sum_seas[0, :]
- if yield_seasons:
- yield seas_storm_count
-
- self._total_rf_year[opennodes] = self._storm_running_sum_of_seasons
- if yield_years is True and yield_seasons is False:
- yield year_storm_count
-
- def calc_annual_rainfall(
- self,
- style="whole_year",
- monsoon_total_rf_gaussian=(("sigma", 64.0), ("mu", 207.0)),
- winter_total_rf_gaussian=(("sigma", 52.0), ("mu", 1.65)),
- ):
- """Return a tuple of rainfall totals (mm) for the year, with entries
- subdividing the yearly total into seasons as appropriate.
-
- Parameters
- ----------
- style : ('whole_year', 'monsoonal', 'winter')
- Whether to simulate 2 seasons, or a single season.
- monsoon_total_rf_gaussian : dict of sigma and mu for the summer
- distribution (if used). Defaults to Walnut Gulch.
- winter_total_rf_gaussian : dict of sigma and mu for the summer
- distribution (if used). Defaults to Walnut Gulch.
-
- Returns
- -------
- tuple : (first_season_total, [second_season_total])
- If style=='monsoonal' or 'winter', a len(1) tuple of the total rf.
- If style=='whole_year', a len(2) tuple of (monsoon, winter) totals.
-
- Examples
- --------
- >>> mg = RasterModelGrid((10, 10), xy_spacing=500.0)
- >>> z = mg.add_zeros("topographic__elevation", at="node")
- >>> rain = SpatialPrecipitationDistribution(mg)
- >>> mytotals = []
- >>> for yr in range(5):
- ... mytotals.append(rain.calc_annual_rainfall(style="whole_year"))
- ...
- >>> [len(x) == 2 for x in mytotals]
- [True, True, True, True, True]
- >>> mytotals = []
- >>> for yr in range(3):
- ... mytotals.append(rain.calc_annual_rainfall(style="monsoonal"))
- ...
- >>> [len(x) == 1 for x in mytotals]
- [True, True, True]
- """
- monsoon_total_rf_gaussian = dict(monsoon_total_rf_gaussian)
- winter_total_rf_gaussian = dict(winter_total_rf_gaussian)
-
- assert style in ("whole_year", "monsoonal", "winter")
- if style in ("whole_year", "monsoonal"):
- # sample from normal distribution and saves global value of Ptot
- # (that must be equalled or exceeded) for each year
- summer_rf_limit = np.random.normal(
- loc=monsoon_total_rf_gaussian["mu"],
- scale=monsoon_total_rf_gaussian["sigma"],
- )
- try:
- summer_rf_limit = np.clip(
- summer_rf_limit,
- monsoon_total_rf_gaussian["trunc_interval"][0],
- monsoon_total_rf_gaussian["trunc_interval"][1],
- )
- except KeyError:
- # ...just in case
- if summer_rf_limit < 0.0:
- summer_rf_limit = 0.0
- if style in ("whole_year", "winter"):
- # sample from normal distribution and saves global value of Ptot
- # (that must be equalled or exceeded) for each year
- winter_rf_limit = np.random.normal(
- loc=winter_total_rf_gaussian["mu"],
- scale=winter_total_rf_gaussian["sigma"],
- )
- try:
- winter_rf_limit = np.clip(
- winter_rf_limit,
- winter_total_rf_gaussian["trunc_interval"][0],
- winter_total_rf_gaussian["trunc_interval"][1],
- )
- except KeyError:
- # ...just in case
- if winter_rf_limit < 0.0:
- winter_rf_limit = 0.0
- if style == "monsoonal":
- return (summer_rf_limit,)
- elif style == "winter":
- return (winter_rf_limit,)
- else:
- return (summer_rf_limit, winter_rf_limit)
-
- def _locate_storm(self, storm_radius):
- """Because of the way the stats fall out, any simulated storm from the
- distribution must intersect the catchment somewhere.
-
- Note written in a grid-agnostic fashion.
- """
- stormposx = np.random.rand() * (self._widthx + 2.0 * storm_radius)
- stormposy = np.random.rand() * (self._widthy + 2.0 * storm_radius)
- stormx = self._minx - storm_radius + stormposx
- stormy = self._miny - storm_radius + stormposy
- return stormx, stormy
-
- @property
- def current_year(self):
- """Get the current year as an int."""
- return self._year
-
- @property
- def current_season(self):
- """Get the current season.
-
- 'M' is monsoon, 'W' is winter.
- """
- return self._current_season
-
- @property
- def storm_depth_last_storm(self):
- """Get the maximum storm depth during the last storm (mm)."""
- return self._max_storm_depth
-
- @property
- def storm_recession_value_last_storm(self):
- """Get the recession parameter (radial die-off) for the last storm."""
- return self._recess_val
-
- @property
- def storm_duration_last_storm(self):
- """Get the duration (in hrs) of the last storm."""
- return self._durationhrs
-
- @property
- def storm_area_last_storm(self):
- """Get the area (in m**2) of the last storm."""
- return self._area_val
-
- @property
- def storm_intensity_last_storm(self):
- """Get the intensity (mm/hr) of the last storm, averaged under the
- storm.
-
- footprint. Note that duration * intensity != storm max depth.
- """
- return self._intensity_val
-
- @property
- def total_rainfall_last_season(self):
- """Get the total recorded rainfall over the last (completed) simulated
- season, spatially resolved (mm)."""
- return self._total_rainfall_last_season
-
- @property
- def total_rainfall_last_year(self):
- """Get the total recorded rainfall over the last (completed) simulated
- year, spatially resolved (mm).
-
- Equivalent to the field 'rainfall__total_depth_per_year'.
- """
- return self._total_rf_year
-
- @property
- def total_rainfall_this_season(self):
- """Get the accumulated, spatially resolved total rainfall over the grid
- for the season so far (mm)."""
- self._running_total_rainfall_this_season[self._opennodes] = (
- self._Storm_running_sum_seas
- )
- return self._running_total_rainfall_this_season
-
- @property
- def total_rainfall_this_year(self):
- """Get the accumulated, spatially resolved total rainfall over the grid
- for the year so far (mm)."""
- self._running_total_rainfall_this_year[self._opennodes] = (
- self._storm_running_sum_1st_seas + self._Storm_running_sum_seas
- )
- return self._running_total_rainfall_this_year
-
- @property
- def median_total_rainfall_last_season(self):
- """Get the median total rainfall recorded over the open nodes of the
- grid during the last (completed) simulated season (mm)."""
- return np.nanmedian(self._total_rainfall_last_season[self._opennodes])
-
- @property
- def median_total_rainfall_last_year(self):
- """Get the median total rainfall recorded over the open nodes of the
- grid during the last (completed) simulated year (mm)."""
- return np.nanmedian(self.total_rainfall_last_year[self._opennodes])
-
- @property
- def median_total_rainfall_this_season(self):
- """Get the accumulated median total rainfall over the open nodes of the
- grid so far this season (mm)."""
- return self._median_seas_rf_total
-
- @property
- def median_total_rainfall_this_year(self):
- """Get the accumulated median total rainfall over the open nodes of the
- grid so far this year (mm)."""
- return np.nanmedian(self.total_rainfall_this_year[self._opennodes])
-
- @property
- def number_of_nodes_under_storm(self):
- """Get the number of nodes under the last storm."""
- return self._entries
-
- @property
- def nodes_under_storm(self):
- """Get the IDs of the nodes under the last storm."""
- return self._nodes_hit
-
- @property
- def coordinates_of_last_storm_center(self):
- """Get the coordinates of the center of the last storm as (x, y)."""
- return (self._x, self._y)
-
- @property
- def target_median_total_rainfall_this_season(self):
- """Get the stochastically generated "target" average total rainfall
- amount over the catchment for the current season.
-
- If limit == 'total_rainfall', this will be very close to
- median_total_rainfall_last_season. If 'total_time', it will
- diverge from this value.
- """
- return self._season_rf_limit
-
-
-def Singer_orographic_rainfall(z_closest_node_to_center):
- """Return a set of curve weights for a provided z, assuming an orographic
- rule following that presented in Singer & Michaelides 2017 & Singer et al.
- 2018 and applicable specifically to Walnut Gulch. i.e., there are three
- orographic divisions, divided at 1350 m and 1500 m.
-
- Parameters
- ----------
- z_closest_node_to_center : float
- The elevation of the node closest to the storm center.
-
- Returns
- -------
- wgts : length 11 list
- The weighting parameters to use in selecting a storm distribution
- curve.
- """
- if z_closest_node_to_center <= 1350:
- wgts = [
- 0.0318,
- 0.0759,
- 0.0851,
- 0.0941,
- 0.0941,
- 0.0941,
- 0.0941,
- 0.0941,
- 0.1033,
- 0.1121,
- 0.1213,
- ]
- elif 1350 < z_closest_node_to_center <= 1500:
- wgts = [
- 0.0478,
- 0.0778,
- 0.0869,
- 0.0959,
- 0.0959,
- 0.0959,
- 0.0959,
- 0.0959,
- 0.1051,
- 0.1141,
- 0.0888,
- ]
- elif z_closest_node_to_center > 1500:
- wgts = [
- 0.0696,
- 0.0786,
- 0.0878,
- 0.0968,
- 0.0968,
- 0.0968,
- 0.0968,
- 0.0968,
- 0.1060,
- 0.1149,
- 0.0591,
- ]
- return wgts
-
-
-if __name__ == "__main__":
- from matplotlib.pyplot import show
-
- nx = 17
- ny = 8
- dx = 1000.0
- mg = RasterModelGrid((nx, ny), xy_spacing=dx)
-
- z = mg.add_zeros("topographic__elevation", at="node")
- z += 1400.0
- rain = SpatialPrecipitationDistribution(mg, number_of_years=1)
- total_t = 0.0
- for count, dt, interval_t in enumerate(
- rain.yield_storms(style="whole_year", limit="total_time")
- ):
- total_t += dt + interval_t
- print(dt, interval_t)
- if count % 100 == 0:
- print("Season:", rain.current_season, "of yr", rain.current_year)
- print("Current storm:", count)
- show()
- print("Effective total years:")
- print(total_t / 24.0 / 365.0)
- print("Storms simulated:")
- print(count)
+import contextlib
+
+import numpy as np
+from scipy.stats import fisk
+from scipy.stats import genextreme
+
+from landlab import Component
+from landlab import RasterModelGrid
+
+
+class SpatialPrecipitationDistribution(Component):
+ """Generate spatially resolved precipitation events.
+
+ A component to generate a sequence of spatially resolved storms over a
+ grid, following a lightly modified version (see below) of the
+ stochastic methods of Singer & Michaelides, Env Res Lett 12, 104011,
+ 2017, & Singer et al., Geosci. Model Dev., accepted, 10.5194/gmd-2018-86.
+
+ The method is heavily stochastic, and at the present time is intimately
+ calibrated against the conditions at Walnut Gulch, described in those
+ papers. In particular, assumptions around intensity-duration
+ calibration and orographic rainfall are "burned in" for now, and are
+ not accessible to the user. The various probability distributions
+ supplied to the various run methods default to WG values, but are
+ easily modified. This calibration reflects a US desert southwest
+ "monsoonal" climate, and the component distinguishes (optionally)
+ between two seasons, "monsoonal" and "winter". The intensity-duration
+ relationship is shared between the seasons, and so may prove useful in
+ a variety of storm-dominated contexts.
+
+ The default is to disable the orographic rainfall functionality of the
+ component. However, if orographic_scenario == 'Singer', the component
+ requires a 'topographic__elevation' field to already exist on the grid
+ at the time of instantiation.
+
+ The component has two ways of simulating a "year". This choice is
+ controlled by the 'limit' parameter of the yield methods. If limit==
+ 'total_rainfall', the component will continue to run until the total
+ rainfall for the season and/or year exceeds a stochastically generated
+ value. This method is directly comparable to the Singer & Michaelides
+ method, but will almost always result in years which are not one
+ calendar year long, unless the input distributions are very carefully
+ recalibrated for each use case. If limit=='total_time', the component
+ will terminate a season and/or year once the elapsed time exceeds one
+ year. In this case, the total rainfall will not correspond to the
+ stochastically generated total. You can access the actual total for the
+ last season using the property `(median_)total_rainfall_last_season`.
+
+ Note that this component cannot simulate the occurrence of more than one
+ storm at the same time. Storms that should be synchronous will instead
+ occur sequentially, with no interstorm time. This limitation means that
+ if enough storms occur in a year that numstorms*mean_storm_duration
+ exceeds one year, the number of simulated storms will saturate. This
+ limitation may be relaxed in the future.
+
+ The component offers the option to modify the maximum number of storms
+ simulated per year. If you find simulations encountering this limit too
+ often, you may need to raise this limit. Conversely, it could be lowered
+ to reduce memory usage over small grids. However, in increasing the value,
+ beware - the component maintains two limit*nnodes arrays, which will chew
+ through memory if the limit gets too high. The default will happily
+ simulate grids up to around 50 km * 50 km using the default probability
+ distributions.
+
+ Key methods are:
+
+ yield_storms
+ Generate a timeseries of storm:interstorm duration pairs, alongside
+ a field that describes the spatial distribution of rain during that
+ storm.
+ yield_years
+ Generate a timeseries of ints giving number of storms per year,
+ alongside a field that describes the spatial distribution of total
+ rainfall across that year.
+ yield_seasons
+ Generate a timeseries of ints giving number of storms per season,
+ alongside a field that describes the spatial distribution of total
+ rainfall across that season.
+ calc_annual_rainfall
+ Produce a timeseries of tuples giving total rainfall each season,
+ without resolving the storms spatially (i.e., fast!).
+
+ A large number of properties are available to access storm properties
+ during generation:
+
+ - current_year
+ - current_season
+ - storm_depth_last_storm
+ - storm_recession_value_last_storm
+ - storm_duration_last_storm
+ - storm_area_last_storm
+ - storm_intensity_last_storm
+ - total_rainfall_this_season
+ - total_rainfall_this_year
+ - total_rainfall_last_season
+ - total_rainfall_last_year
+ - median_total_rainfall_this_season
+ - median_total_rainfall_this_year
+ - median_total_rainfall_last_season
+ - median_total_rainfall_last_year
+ - number_of_nodes_under_storm
+ - nodes_under_storm
+ - target_median_total_rainfall_this_season
+
+ Note that becuase these are medians not means,
+ median_total_rainfall_last_season + median_total_rainfall_this_season
+ != median_total_rainfall_this_year.
+
+ Significant differences between this component and the Singer code are:
+
+ - The component does not model evapotranspiration. Use a separate
+ Landlab component for this.
+ - The component runs only over a LL grid; there is no such thing as a
+ validation or simulation run.
+ - It produces "fuzz" around intensity values using a continuous
+ distribution; Singer does this with integer steps.
+ - Step changes mid-run cannot be explicitly modelled. Instead, run the
+ component for a fixed duration, make the change to the
+ distribution input parameter, then run it again.
+ - Storms can be centred at any spatial coordinate, not just over nodes.
+ - Edge buffering is now dynamic; i.e., big storms have a bigger edge
+ buffer than smaller storms. Storms can be centered off the grid
+ edges.
+ - Storms are never discarded - once a storm is drawn, it must hit the
+ catchment, and positions are repeatedly selected until this can
+ happen. Singer's method would discard such a storm and draw a new
+ one.
+ - Durations are not rescaled to ensure both total duration and total
+ precip are both satisfied at the same time, as in Singer's method.
+ Instead, the component either matches a year's duration, *or*
+ exactly a year's worth of rain. This choice is dictated by the
+ `limit` parameter in the yield methods.
+
+ Examples
+ --------
+
+ >>> import numpy as np
+ >>> from landlab import RasterModelGrid, VoronoiDelaunayGrid
+ >>> mg = RasterModelGrid((10, 10), xy_spacing=1000.0)
+ >>> rain = SpatialPrecipitationDistribution(mg)
+
+ Calling yield_storms will produce storm-interstorm duration (hr) pairs
+ until the model runtime has elapsed.
+
+ >>> np.random.seed(1)
+ >>> total_t_each_step = [
+ ... (storm + interstorm) for (storm, interstorm) in rain.yield_storms()
+ ... ]
+ >>> len(total_t_each_step)
+ 41
+ >>> np.isclose(sum(total_t_each_step) / 24.0, 365.0)
+ True
+
+ The actual rainfall intensities during that interval are accessible in the
+ 'rainfall__flux' field (mm/hr). The storm centre does not have to be over
+ the grid, but in this case, it was for the last simulated storm:
+
+ >>> mg.at_node["rainfall__flux"].argmax()
+ 80
+
+ We can also run the component for only one season (i.e., only using one
+ of the pdf sets describing the storm properties):
+
+ >>> for field in ("rainfall__flux", "rainfall__total_depth_per_year"):
+ ... _ = mg.at_node.pop(field) # clear out the existing fields
+ ...
+ >>> rain = SpatialPrecipitationDistribution(mg, number_of_years=2)
+ >>> np.random.seed(5)
+ >>> total_t_each_step = [
+ ... (storm + interstorm)
+ ... for (storm, interstorm) in rain.yield_storms(
+ ... style="monsoonal", monsoon_fraction_of_year=0.35
+ ... )
+ ... ]
+ >>> np.isclose(sum(total_t_each_step) / 24.0 / 365.0 / 2.0, 0.35)
+ True
+
+ Note this behaviour can be stopped by upping monsoon_fraction_of_year:
+
+ >>> np.random.seed(5)
+ >>> total_t_each_step = [
+ ... (storm + interstorm)
+ ... for (storm, interstorm) in rain.yield_storms(
+ ... style="monsoonal", monsoon_fraction_of_year=1.0
+ ... )
+ ... ]
+ >>> np.isclose(round(sum(total_t_each_step) / 24.0 / 365.0 / 2.0, 2), 1.0)
+ True
+
+ yield_years yields the number of storms in the last whole year.
+ Use 'rainfall__total_depth_per_year' to access the rainfall map for the
+ last fully elapsed year, or equivalently, the total_rainfall_last_year
+ property. Note the component seamlessly handles non-raster grid types:
+
+ >>> vdg = VoronoiDelaunayGrid(
+ ... np.random.rand(100) * 1000.0, np.random.rand(100) * 1000.0
+ ... )
+ >>> np.random.seed(3)
+ >>> rain = SpatialPrecipitationDistribution(vdg, number_of_years=3)
+ >>> storms_each_year = []
+ >>> for total_storms in rain.yield_years(
+ ... style="monsoonal", total_rf_trend=0.05, storminess_trend=-0.02
+ ... ):
+ ... storms_each_year.append(total_storms)
+ ... assert np.all(
+ ... np.equal(
+ ... vdg.at_node["rainfall__total_depth_per_year"],
+ ... rain.total_rainfall_last_year,
+ ... )
+ ... )
+ >>> sum(storms_each_year)
+ 11
+
+ yield_seasons yields rainfall statistics for individual seasons. Access
+ these using the various provided component properties. Note that we can
+ get the component to yield a total rainfall that is calibrated to the
+ supplied total_rf_gaussians if we set limit to 'total__rainfall' rather
+ than 'total_time' (at the cost of exactly matching the season length):
+
+ >>> for field in ("rainfall__flux", "rainfall__total_depth_per_year"):
+ ... _ = mg.at_node.pop(field) # clear out the existing fields
+ ...
+ >>> rain = SpatialPrecipitationDistribution(mg, number_of_years=2)
+ >>> np.random.seed(5)
+ >>> season_list = []
+ >>> theoretical_median_rf_season = []
+ >>> median_rf_season = []
+ >>> median_rf_last_year = []
+ >>> mean_rf_season = []
+ >>> mean_rf_last_year = []
+ >>> for storm_number in rain.yield_seasons(limit="total_rainfall"):
+ ... season_list.append(rain.current_season)
+ ... theoretical_median_rf_season.append(
+ ... rain.target_median_total_rainfall_this_season
+ ... )
+ ... median_rf_season.append(rain.median_total_rainfall_this_season)
+ ... median_rf_last_year.append(rain.median_total_rainfall_last_year)
+ ... mean_rf_season.append(rain.total_rainfall_this_season.mean())
+ ... mean_rf_last_year.append(rain.total_rainfall_last_year.mean())
+ ...
+ >>> season_list == ["M", "W", "M", "W"]
+ True
+ >>> [
+ ... meas > sim
+ ... for (meas, sim) in zip(median_rf_season, theoretical_median_rf_season)
+ ... ] # must exceed
+ [True, True, True, True]
+ >>> np.isclose(median_rf_last_year[0], 0.0)
+ True
+ >>> for season in (0, 2): # this property must be the same in both seasons
+ ... np.isclose(median_rf_last_year[season], median_rf_last_year[season + 1])
+ ...
+ True
+ True
+
+ Note that because we work here with medians, the seasonal medians don't sum
+ to the year median, but the means do:
+
+ >>> np.isclose(median_rf_last_year[2], median_rf_season[0] + median_rf_season[1])
+ False
+ >>> np.isclose(mean_rf_last_year[2], mean_rf_season[0] + mean_rf_season[1])
+ True
+
+ References
+ ----------
+ **Required Software Citation(s) Specific to this Component**
+
+ Singer, M., Michaelides, K., Hobley, D. (2018). STORM 1.0: a simple,
+ flexible, and parsimonious stochastic rainfall generator for simulating
+ climate and climate change. Geoscientific Model Development 11(9),
+ 3713-3726. https://dx.doi.org/10.5194/gmd-11-3713-2018
+
+ **Additional References**
+
+ None Listed
+
+ """
+
+ _name = "SpatialPrecipitationDistribution"
+
+ _unit_agnostic = False
+
+ _cite_as = """@Article{gmd-2018-86,
+ title={STORM: A simple, flexible, and parsimonious stochastic rainfall
+ generator for simulating climate and climate change},
+ author={Singer, M. B. and Michaelides, K. and Hobley, D. E. J.},
+ journal={Geoscientific Model Development Discussions},
+ volume={2018},
+ pages={1--25},
+ year={2018},
+ url={https://www.geosci-model-dev-discuss.net/gmd-2018-86/},
+ doi={10.5194/gmd-2018-86}
+ }"""
+
+ _info = {
+ "rainfall__flux": {
+ "dtype": float,
+ "intent": "out",
+ "optional": False,
+ "units": "mm/hr",
+ "mapping": "node",
+ "doc": "Depth of water delivered per unit time in each storm",
+ },
+ "rainfall__total_depth_per_year": {
+ "dtype": float,
+ "intent": "out",
+ "optional": False,
+ "units": "mm/yr",
+ "mapping": "node",
+ "doc": "Depth of water delivered in total in each model year",
+ },
+ "topographic__elevation": {
+ "dtype": float,
+ "intent": "in",
+ "optional": True,
+ "units": "m",
+ "mapping": "node",
+ "doc": "Land surface topographic elevation",
+ },
+ }
+
+ def __init__(
+ self, grid, number_of_years=1, orographic_scenario=None, max_numstorms=5000
+ ):
+ """Create the SpatialPrecipitationDistribution generator component.
+
+ Parameters
+ ----------
+ grid : ModelGrid
+ A Landlab model grid of any type.
+ number_of_years : int
+ The number of years over which to generate storms.
+ orographic_scenario : {None, 'Singer', func}
+ Whether to use no orographic rule, or to adopt S&M's 2017
+ calibration for Walnut Gulch. Alternatively, provide a function
+ here that turns the provided elevation of the storm center into
+ a length-11 curve weighting to select which orographic scenario
+ to apply.
+ """
+ super().__init__(grid)
+
+ gaugecount = (grid.status_at_node != grid.BC_NODE_IS_CLOSED).sum()
+ self._gauge_dist_km = np.zeros(gaugecount, dtype="float")
+ self._temp_dataslots1 = np.zeros(gaugecount, dtype="float")
+ self._temp_dataslots2 = np.zeros(gaugecount, dtype="float")
+ self._numyrs = number_of_years
+
+ self._max_numstorms = max_numstorms
+ # This is for initializing matrices. Trailing zeros are deleted from
+ # matrixes at the end of the code.
+
+ assert orographic_scenario in (None, "Singer")
+ self._orographic_scenario = orographic_scenario
+
+ # build LL fields:
+ self.initialize_output_fields()
+ # bind the field to the internal variable:
+ self._rain_int_gauge = self._grid.at_node["rainfall__flux"]
+ self._total_rf_year = self._grid.at_node["rainfall__total_depth_per_year"]
+
+ # store some info on the open node grid extent:
+ open_nodes = self._grid.status_at_node != self._grid.BC_NODE_IS_CLOSED
+ self._minx = self._grid.node_x[open_nodes].min()
+ self._maxx = self._grid.node_x[open_nodes].max()
+ self._miny = self._grid.node_y[open_nodes].min()
+ self._maxy = self._grid.node_y[open_nodes].max()
+ self._widthx = self._maxx - self._minx
+ self._widthy = self._maxy - self._miny
+ self._running_total_rainfall_this_year = self._grid.zeros(at="node")
+ self._running_total_rainfall_this_season = self._grid.zeros(at="node")
+
+ self._open_area = self._grid.cell_area_at_node[open_nodes].sum()
+ self._scaling_to_WG = self._open_area / 275710702.0
+ # ^ this is the relative size of the catchment compared to WG
+
+ def yield_storms(
+ self,
+ limit="total_time",
+ style="whole_year",
+ total_rf_trend=0.0,
+ storminess_trend=0.0,
+ monsoon_fraction_of_year=0.42,
+ monsoon_total_rf_gaussian=(("sigma", 64.0), ("mu", 207.0)),
+ monsoon_storm_duration_GEV=(
+ ("shape", -0.570252),
+ ("sigma", 35.7389),
+ ("mu", 34.1409),
+ ("trunc_interval", (0.0, 1040.0)),
+ ),
+ monsoon_storm_area_GEV=(
+ ("shape", 0.0),
+ ("sigma", 2.83876e07),
+ ("mu", 1.22419e08),
+ ("trunc_interval", (5.0e06, 3.0e08)),
+ ),
+ monsoon_storm_interarrival_GEV=(
+ ("shape", -0.807971),
+ ("sigma", 9.4957),
+ ("mu", 10.6108),
+ ("trunc_interval", (0.0, 720.0)),
+ ),
+ monsoon_storm_radial_weakening_gaussian=(("sigma", 0.08), ("mu", 0.25)),
+ winter_total_rf_gaussian=(("sigma", 52.0), ("mu", 1.65)),
+ winter_storm_duration_fisk=(
+ ("c", 1.0821),
+ ("scale", 68.4703),
+ ("trunc_interval", (0.0, 5000.0)),
+ ),
+ winter_storm_area_GEV=(
+ ("shape", 0.0),
+ ("sigma", 2.83876e07),
+ ("mu", 1.22419e08),
+ ("trunc_interval", (5.0e06, 3.0e08)),
+ ),
+ winter_storm_interarrival_GEV=(
+ ("shape", 1.1131),
+ ("sigma", 53.2671),
+ ("mu", 47.4944),
+ ("trunc_interval", (0.0, 720.0)),
+ ),
+ winter_storm_radial_weakening_gaussian=(
+ ("sigma", 0.08),
+ ("mu", 0.25),
+ ("trunc_interval", (0.15, 0.67)),
+ ),
+ ):
+ """Yield a timeseries giving the number of storms occurring each year
+ in a rainfall simulation.
+
+ All default distributions specified as parameters reflect values for
+ Walnut Gulch, see Singer & Michaelides, 2017 & Singer et al, submitted.
+
+ Parameters
+ ----------
+ limit : str
+ Controls whether a season is defined based on its total rainfall
+ (and can be any length), or by its duration (and can have any
+ amount of rainfall). One of 'total_time' or 'total_rainfall'.
+ If 'total_time', monsoon_fraction_of_year
+ sets the fraction of a year occupied by the monsoon.
+ style : str
+ Controls whether the component seeks to simulate a western US-
+ style "monsoonal" climate, a western US-style winter climate,
+ or a full year combining both. One of 'whole_year', 'monsoonal',
+ or 'winter' These distributions are by default
+ based on Singer et al.'s calibrations. Note if 'monsoonal',
+ the total duration of a "year" will appear to be only
+ `monsoon_fraction_of_year`, and the opposite for `winter`.
+ total_rf_trend : float
+ Controls if a drift is applied to the total rainfall distribution
+ through time. If 0., no trend. If positive, rainfall totals
+ increase gradually through time. If negative, they fall through
+ time. S&M recommend +/- 0.07 for a realistic climate change driven
+ drift at Walnut Gulch.
+ storminess_trend : float
+ Controls if a drift is applied to the expected intensity of
+ individual storms through time. If 0., no trend. If positive,
+ storms get more intense through time, if negative, less so. S&M
+ recommend +/- 0.01 for a realistic climate change driven drift at
+ Walnut Gulch.
+ monsoon_fraction_of_year : float
+ If limit == 'total_time', sets the fraction of one year occupied
+ by the monsoon season. If not, ignored. Singer's monsoon runs from
+ May to September, inclusive, and the default reflects this.
+ monsoon_total_rf_gaussian : dict
+ Parameters defining the normal distribution controlling the total
+ rainfall expected in each year. S&M use 'mu' in {143., 271.} for
+ step changes up/down in rainfall totals.
+ monsoon_storm_duration_GEV : dict
+ Parameters defining a generalised extreme value distribution
+ controlling the duration of each storm. In minutes.
+ monsoon_storm_area_GEV : dict
+ Parameters defining a generalised extreme value distribution
+ controlling the plan view area of each storm. S&M use 'shape': 0.,
+ which collapses the distribution to a plain extreme value
+ distribution.
+ monsoon_storm_interarrival_GEV : dict
+ Parameters defining a generalised extreme value
+ distribution controlling the interarrival time between each storm.
+ In HRS. Note that this calibration is specifically to Walnut Gulch,
+ which has an area of 275 km**2. The generator directly scales this
+ resulting distribution to the area ratio of Walnut Gulch to the
+ open cells of the grid. This crudely accounts for the fact that
+ bigger catchments will have more storms, but note that the heavy
+ tail on this distribution means the default distribution shape
+ will not be trustworthy for catchments with big differences in
+ size from Walnut Gulch.
+ monsoon_storm_radial_weakening_gaussian : dict
+ Parameters defining a normal distribution
+ controlling the rate of intensity decline with distance from storm
+ center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
+ et al., 2005.
+ winter_total_rf_gaussian : dict
+ Parameters defining a normal distribution controlling the total
+ rainfall expected in each year. S&M use 'mu' in {143., 271.} for
+ step changes up/down in rainfall totals.
+ winter_storm_duration_fisk : dict
+ Parameters defining a Fisk (i.e., log-logistic) distribution
+ controlling the duration of each storm. Note this differs from the
+ summer scaling. In Minutes.
+ winter_storm_area_GEV is a generalised extreme value distribution
+ controlling the plan view area of each storm. S&M use 'shape': 0.,
+ which collapses the distribution to a plain extreme value
+ distribution.
+ winter_storm_interarrival_GEV : dict
+ Parameters defining a generalised extreme value
+ distribution controlling the interarrival time between each storm.
+ In HRS. The same considerations apply here as for the monsoonal
+ interstorm equivalent.
+ winter_storm_radial_weakening_gaussian : dict
+ Parameters defining a normal distribution
+ controlling the rate of intensity decline with distance from storm
+ center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
+ et al., 2005.
+
+ Yields
+ ------
+ (storm_t, interval_t) : (float, float)
+ Tuple pair of duration of a single storm, then the interstorm
+ interval that follows it. In hrs. The rainfall__flux field
+ describes the rainfall rate during the interval storm_t as the
+ tuple is yielded. In HRS.
+ Note that the rainfall__total_depth_per_year field gives the total
+ accumulated rainfall depth during the *last completed* model year,
+ not the year to the point of yield. For the latter, use the
+ property `total_rainfall_this_year`.
+ """
+ return self._run_the_process(
+ yield_storms=True,
+ yield_years=False,
+ yield_seasons=False,
+ limit=limit,
+ style=style,
+ monsoon_fraction_of_year=monsoon_fraction_of_year,
+ total_rf_trend=total_rf_trend,
+ storminess_trend=storminess_trend,
+ monsoon_total_rf_gaussian=monsoon_total_rf_gaussian,
+ monsoon_storm_duration_GEV=monsoon_storm_duration_GEV,
+ monsoon_storm_area_GEV=monsoon_storm_area_GEV,
+ monsoon_storm_interarrival_GEV=monsoon_storm_interarrival_GEV,
+ monsoon_storm_radial_weakening_gaussian=monsoon_storm_radial_weakening_gaussian,
+ winter_total_rf_gaussian=winter_total_rf_gaussian,
+ winter_storm_duration_fisk=winter_storm_duration_fisk,
+ winter_storm_area_GEV=winter_storm_area_GEV,
+ winter_storm_interarrival_GEV=winter_storm_interarrival_GEV,
+ winter_storm_radial_weakening_gaussian=winter_storm_radial_weakening_gaussian,
+ )
+
+ def yield_years(
+ self,
+ limit="total_time",
+ style="whole_year",
+ total_rf_trend=0.0,
+ storminess_trend=0.0,
+ monsoon_fraction_of_year=0.42,
+ monsoon_total_rf_gaussian=(("sigma", 64.0), ("mu", 207.0)),
+ monsoon_storm_duration_GEV=(
+ ("shape", -0.570252),
+ ("sigma", 35.7389),
+ ("mu", 34.1409),
+ ("trunc_interval", (1.0, 1040.0)),
+ ),
+ monsoon_storm_area_GEV=(
+ ("shape", 0.0),
+ ("sigma", 2.83876e07),
+ ("mu", 1.22419e08),
+ ("trunc_interval", (5.0e06, 3.0e08)),
+ ),
+ monsoon_storm_interarrival_GEV=(
+ ("shape", -0.807971),
+ ("sigma", 9.4957),
+ ("mu", 10.6108),
+ ("trunc_interval", (0.0, 720.0)),
+ ),
+ monsoon_storm_radial_weakening_gaussian=(
+ ("sigma", 0.08),
+ ("mu", 0.25),
+ ("trunc_interval", (0.15, 0.67)),
+ ),
+ winter_total_rf_gaussian=(("sigma", 52.0), ("mu", 1.65)),
+ winter_storm_duration_fisk=(
+ ("c", 1.0821),
+ ("scale", 68.4703),
+ ("trunc_interval", (1.0, 5000.0)),
+ ),
+ winter_storm_area_GEV=(
+ ("shape", 0.0),
+ ("sigma", 2.83876e07),
+ ("mu", 1.22419e08),
+ ("trunc_interval", (5.0e06, 3.0e08)),
+ ),
+ winter_storm_interarrival_GEV=(
+ ("shape", 1.1131),
+ ("sigma", 53.2671),
+ ("mu", 47.4944),
+ ("trunc_interval", (0.0, 720.0)),
+ ),
+ winter_storm_radial_weakening_gaussian=(
+ ("sigma", 0.08),
+ ("mu", 0.25),
+ ("trunc_interval", (0.15, 0.67)),
+ ),
+ ):
+ """Yield a timeseries giving the number if storms occurring each year
+ in a rainfall simulation.
+
+ All default distributions specified as parameters reflect values for
+ Walnut Gulch, see Singer & Michaelides, 2017 & Singer et al, submitted.
+
+ Parameters
+ ----------
+ limit : ('total_time', 'total_rainfall')
+ Controls whether a season is defined based on its total rainfall
+ (and can be any length), or by its duration (and can have any
+ amount of rainfall). If 'total_time', monsoon_fraction_of_year
+ sets the fraction of a year occupied by the monsoon.
+ style : ('whole_year', 'monsoonal', 'winter')
+ Controls whether the component seeks to simulate a western US-
+ style "monsoonal" climate, a western US-style winter climate,
+ or a full year combining both. These distributions are by default
+ based on Singer et al.'s calibrations. Note if 'monsoonal',
+ the total duration of a "year" will appear to be only
+ `monsoon_fraction_of_year`, and the opposite for `winter`.
+ total_rf_trend : float
+ Controls if a drift is applied to the total rainfall distribution
+ through time. If 0., no trend. If positive, rainfall totals
+ increase gradually through time. If negative, they fall through
+ time. S&M recommend +/- 0.07 for a realistic climate chage driven
+ drift at Walnut Gulch.
+ storminess_trend : float
+ Controls if a drift is applied to the expected intensity of
+ individual storms through time. If 0., no trend. If positive,
+ storms get more intense through time, if negative, less so. S&M
+ recommend +/- 0.01 for a realistic climate change driven drift at
+ Walnut Gulch.
+ monsoon_fraction_of_year : float
+ If limit == 'total_time', sets the fraction of one year occupied
+ by the monsoon season. If not, ignored. Singer's monsoon runs from
+ May to September, inclusive, and the default reflects this.
+
+ monsoon_total_rf_gaussian is a normal distribution controlling the
+ total rainfall expected in each year. S&M use 'mu' in {143., 271.}
+ for step changes up/down in rainfall totals. In mm.
+ monsoon_storm_duration_GEV is a generalised extreme value distribution
+ controlling the duration of each storm. In MIN.
+ monsoon_storm_area_GEV is a generalised extreme value distribution
+ controlling the plan view area of each storm. S&M use 'shape': 0.,
+ which collapses the distribution to a plain extreme value
+ distribution.
+ monsoon_storm_interarrival_GEV is a generalised extreme value
+ distribution controlling the interarrival time between each storm.
+ In HRS. Note that this calibration is specifically to Walnut Gulch,
+ which has an area of 275 km**2. The generator directly scales this
+ resulting distribution to the area ratio of Walnut Gulch to the
+ open cells of the grid. This crudely accounts for the fact that
+ bigger catchments will have more storms, but note that the heavy
+ tail on this distribution means the default distribution shape
+ will not be trustworthy for catchments with big differences in
+ size from Walnut Gulch.
+ monsoon_storm_radial_weakening_gaussian is a normal distribution
+ controlling the rate of intensity decline with distance from storm
+ center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
+ et al., 2005.
+
+ winter_total_rf_gaussian is a normal distribution controlling the total
+ rainfall expected in each year. S&M use 'mu' in {143., 271.} for
+ step changes up/down in rainfall totals.
+ winter_storm_duration_fisk is a Fisk (i.e., log-logistic) distribution
+ controlling the duration of each storm. Note this differs from the
+ summer scaling. In MIN.
+ winter_storm_area_GEV is a generalised extreme value distribution
+ controlling the plan view area of each storm. S&M use 'shape': 0.,
+ which collapses the distribution to a plain extreme value
+ distribution.
+ winter_storm_interarrival_GEV is a generalised extreme value
+ distribution controlling the interarrival time between each storm.
+ In HRS. The same considerations apply here as for the monsoonal
+ interstorm equivalent.
+ winter_storm_radial_weakening_gaussian is a normal distribution
+ controlling the rate of intensity decline with distance from storm
+ center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
+ et al., 2005.
+
+ Yields
+ ------
+ number_of_storms_per_year : float
+ Float that gives the number of storms simulated in the year that
+ elapsed since the last yield. The rainfall__total_depth_per_year
+ field gives the total accumulated rainfall depth during the year
+ preceding the yield. rainfall__flux gives the rainfall intensity of
+ the last storm in that year.
+ """
+ return self._run_the_process(
+ yield_storms=False,
+ yield_years=True,
+ yield_seasons=False,
+ limit=limit,
+ style=style,
+ total_rf_trend=total_rf_trend,
+ storminess_trend=storminess_trend,
+ monsoon_fraction_of_year=monsoon_fraction_of_year,
+ monsoon_total_rf_gaussian=monsoon_total_rf_gaussian,
+ monsoon_storm_duration_GEV=monsoon_storm_duration_GEV,
+ monsoon_storm_area_GEV=monsoon_storm_area_GEV,
+ monsoon_storm_interarrival_GEV=monsoon_storm_interarrival_GEV,
+ monsoon_storm_radial_weakening_gaussian=monsoon_storm_radial_weakening_gaussian,
+ winter_total_rf_gaussian=winter_total_rf_gaussian,
+ winter_storm_duration_fisk=winter_storm_duration_fisk,
+ winter_storm_area_GEV=winter_storm_area_GEV,
+ winter_storm_interarrival_GEV=winter_storm_interarrival_GEV,
+ winter_storm_radial_weakening_gaussian=winter_storm_radial_weakening_gaussian,
+ )
+
+ def yield_seasons(
+ self,
+ limit="total_time",
+ style="whole_year",
+ total_rf_trend=0.0,
+ storminess_trend=0.0,
+ monsoon_fraction_of_year=0.42,
+ monsoon_total_rf_gaussian=(("sigma", 64.0), ("mu", 207.0)),
+ monsoon_storm_duration_GEV=(
+ ("shape", -0.570252),
+ ("sigma", 35.7389),
+ ("mu", 34.1409),
+ ("trunc_interval", (1.0, 1040.0)),
+ ),
+ monsoon_storm_area_GEV=(
+ ("shape", 0.0),
+ ("sigma", 2.83876e07),
+ ("mu", 1.22419e08),
+ ("trunc_interval", (5.0e06, 3.0e08)),
+ ),
+ monsoon_storm_interarrival_GEV=(
+ ("shape", -0.807971),
+ ("sigma", 9.4957),
+ ("mu", 10.6108),
+ ("trunc_interval", (0.0, 720.0)),
+ ),
+ monsoon_storm_radial_weakening_gaussian=(
+ ("sigma", 0.08),
+ ("mu", 0.25),
+ ("trunc_interval", (0.15, 0.67)),
+ ),
+ winter_total_rf_gaussian=(("sigma", 52.0), ("mu", 1.65)),
+ winter_storm_duration_fisk=(
+ ("c", 1.0821),
+ ("scale", 68.4703),
+ ("trunc_interval", (1.0, 5000.0)),
+ ),
+ winter_storm_area_GEV=(
+ ("shape", 0.0),
+ ("sigma", 2.83876e07),
+ ("mu", 1.22419e08),
+ ("trunc_interval", (5.0e06, 3.0e08)),
+ ),
+ winter_storm_interarrival_GEV=(
+ ("shape", 1.1131),
+ ("sigma", 53.2671),
+ ("mu", 47.4944),
+ ("trunc_interval", (0.0, 720.0)),
+ ),
+ winter_storm_radial_weakening_gaussian=(
+ ("sigma", 0.08),
+ ("mu", 0.25),
+ ("trunc_interval", (0.15, 0.67)),
+ ),
+ ):
+ """Yield a timeseries giving the number if storms occurring each season
+ in a rainfall simulation. Only meaningfully different from yield_years
+ if style=='whole_year'.
+
+ All default distributions specified as parameters reflect values for
+ Walnut Gulch, see Singer & Michaelides, 2017 & Singer et al, submitted.
+
+ Parameters
+ ----------
+ limit : ('total_time', 'total_rainfall')
+ Controls whether a season is defined based on its total rainfall
+ (and can be any length), or by its duration (and can have any
+ amount of rainfall). If 'total_time', monsoon_fraction_of_year
+ sets the fraction of a year occupied by the monsoon.
+ style : ('whole_year', 'monsoonal', 'winter')
+ Controls whether the component seeks to simulate a western US-
+ style "monsoonal" climate, a western US-style winter climate,
+ or a full year combining both. These distributions are by default
+ based on Singer et al.'s calibrations. Note if 'monsoonal',
+ the total duration of a "year" will appear to be only
+ `monsoon_fraction_of_year`, and the opposite for `winter`.
+ total_rf_trend : float
+ Controls if a drift is applied to the total rainfall distribution
+ through time. If 0., no trend. If positive, rainfall totals
+ increase gradually through time. If negative, they fall through
+ time. S&M recommend +/- 0.07 for a realistic climate chage driven
+ drift at Walnut Gulch.
+ storminess_trend : float
+ Controls if a drift is applied to the expected intensity of
+ individual storms through time. If 0., no trend. If positive,
+ storms get more intense through time, if negative, less so. S&M
+ recommend +/- 0.01 for a realistic climate change driven drift at
+ Walnut Gulch.
+ monsoon_fraction_of_year : float
+ If limit == 'total_time', sets the fraction of one year occupied
+ by the monsoon season. If not, ignored. Singer's monsoon runs from
+ May to September, inclusive, and the default reflects this.
+
+ monsoon_total_rf_gaussian is a normal distribution controlling the
+ total rainfall expected in each year. S&M use 'mu' in {143., 271.}
+ for step changes up/down in rainfall totals. In mm.
+ monsoon_storm_duration_GEV is a generalised extreme value distribution
+ controlling the duration of each storm. In MIN.
+ monsoon_storm_area_GEV is a generalised extreme value distribution
+ controlling the plan view area of each storm. S&M use 'shape': 0.,
+ which collapses the distribution to a plain extreme value
+ distribution.
+ monsoon_storm_interarrival_GEV is a generalised extreme value
+ distribution controlling the interarrival time between each storm.
+ In HRS. Note that this calibration is specifically to Walnut Gulch,
+ which has an area of 275 km**2. The generator directly scales this
+ resulting distribution to the area ratio of Walnut Gulch to the
+ open cells of the grid. This crudely accounts for the fact that
+ bigger catchments will have more storms, but note that the heavy
+ tail on this distribution means the default distribution shape
+ will not be trustworthy for catchments with big differences in
+ size from Walnut Gulch.
+ monsoon_storm_radial_weakening_gaussian is a normal distribution
+ controlling the rate of intensity decline with distance from storm
+ center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
+ et al., 2005.
+
+ winter_total_rf_gaussian is a normal distribution controlling the total
+ rainfall expected in each year. S&M use 'mu' in {143., 271.} for
+ step changes up/down in rainfall totals.
+ winter_storm_duration_fisk is a Fisk (i.e., log-logistic) distribution
+ controlling the duration of each storm. Note this differs from the
+ summer scaling. In MIN.
+ winter_storm_area_GEV is a generalised extreme value distribution
+ controlling the plan view area of each storm. S&M use 'shape': 0.,
+ which collapses the distribution to a plain extreme value
+ distribution.
+ winter_storm_interarrival_GEV is a generalised extreme value
+ distribution controlling the interarrival time between each storm.
+ In HRS. The same considerations apply here as for the monsoonal
+ interstorm equivalent.
+ winter_storm_radial_weakening_gaussian is a normal distribution
+ controlling the rate of intensity decline with distance from storm
+ center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
+ et al., 2005.
+
+ Yields
+ ------
+ number_of_storms_per_season : float
+ Float that gives the number of storms simulated in the season that
+ elapsed since the last yield. The rainfall__total_depth_per_year
+ field gives the total accumulated rainfall depth during the *year*
+ preceding the yield, *so far*. rainfall__flux gives the rainfall
+ intensity of the last storm in that year.
+ NB: Use the component property total_rainfall_last_season to access
+ the *actual* amount of rainfall in the season that has the number
+ of storms that the method generates.
+ """
+ return self._run_the_process(
+ yield_storms=False,
+ yield_years=False,
+ yield_seasons=True,
+ limit=limit,
+ style=style,
+ total_rf_trend=total_rf_trend,
+ storminess_trend=storminess_trend,
+ monsoon_fraction_of_year=monsoon_fraction_of_year,
+ monsoon_total_rf_gaussian=monsoon_total_rf_gaussian,
+ monsoon_storm_duration_GEV=monsoon_storm_duration_GEV,
+ monsoon_storm_area_GEV=monsoon_storm_area_GEV,
+ monsoon_storm_interarrival_GEV=monsoon_storm_interarrival_GEV,
+ monsoon_storm_radial_weakening_gaussian=monsoon_storm_radial_weakening_gaussian,
+ winter_total_rf_gaussian=winter_total_rf_gaussian,
+ winter_storm_duration_fisk=winter_storm_duration_fisk,
+ winter_storm_area_GEV=winter_storm_area_GEV,
+ winter_storm_interarrival_GEV=winter_storm_interarrival_GEV,
+ winter_storm_radial_weakening_gaussian=winter_storm_radial_weakening_gaussian,
+ )
+
+ def _run_the_process(
+ self,
+ yield_storms=True,
+ yield_years=False,
+ yield_seasons=False,
+ limit="total_time",
+ style="whole_year",
+ monsoon_fraction_of_year=0.42,
+ total_rf_trend=0.0,
+ storminess_trend=0.0,
+ monsoon_total_rf_gaussian=(("sigma", 64.0), ("mu", 207.0)),
+ monsoon_storm_duration_GEV=(
+ ("shape", -0.570252),
+ ("sigma", 35.7389),
+ ("mu", 34.1409),
+ ("trunc_interval", (1.0, 1040.0)),
+ ),
+ monsoon_storm_area_GEV=(
+ ("shape", 0.0),
+ ("sigma", 2.83876e07),
+ ("mu", 1.22419e08),
+ ("trunc_interval", (5.0e06, 3.0e08)),
+ ),
+ monsoon_storm_interarrival_GEV=(
+ ("shape", -0.807971),
+ ("sigma", 9.4957),
+ ("mu", 10.6108),
+ ("trunc_interval", (0.0, 720.0)),
+ ),
+ monsoon_storm_radial_weakening_gaussian=(
+ ("sigma", 0.08),
+ ("mu", 0.25),
+ ("trunc_interval", (0.15, 0.67)),
+ ),
+ winter_total_rf_gaussian=(("sigma", 52.0), ("mu", 1.65)),
+ winter_storm_duration_fisk=(
+ ("c", 1.0821),
+ ("scale", 68.4703),
+ ("trunc_interval", (1.0, 5000.0)),
+ ),
+ winter_storm_area_GEV=(
+ ("shape", 0.0),
+ ("sigma", 2.83876e07),
+ ("mu", 1.22419e08),
+ ("trunc_interval", (5.0e06, 3.0e08)),
+ ),
+ winter_storm_interarrival_GEV=(
+ ("shape", 1.1131),
+ ("sigma", 53.2671),
+ ("mu", 47.4944),
+ ("trunc_interval", (0.0, 720.0)),
+ ),
+ winter_storm_radial_weakening_gaussian=(
+ ("sigma", 0.08),
+ ("mu", 0.25),
+ ("trunc_interval", (0.15, 0.67)),
+ ),
+ ):
+ """This is the underlying process that runs the component, but it
+ should be run by a user through the yield_storms and yield_years
+ methods.
+
+ Fuzz to the chosen values is now selected from a continuous
+ distribution, not from integer values.
+
+ total_rf_trend controls if a drift is applied to the total rainfall
+ distribution through time. If 0., no trend. If positive, rainfall
+ totals increase gradually through time. If negative, they fall through
+ time. S&M recommend +/- 0.07 for a realistic climate chage driven drift
+ at Walnut Gulch.
+
+ storminess_trend controls if a drift is applied to the expected
+ intensity of individual storms through time. If 0., no trend. If
+ positive, storms get more intense through time, if negative, less so.
+ S&M recommend +/- 0.01 for a realistic climate change driven drift at
+ Walnut Gulch.
+
+ All default distributions reflect values for Walnut Gulch, see Singer &
+ Michaelides, submitted:
+
+ monsoon_total_rf_gaussian is a normal distribution controlling the
+ total rainfall expected in each year. S&M use 'mu' in {143., 271.}
+ for step changes up/down in rainfall totals. In mm.
+ monsoon_storm_duration_GEV is a generalised extreme value distribution
+ controlling the duration of each storm. In MIN.
+ monsoon_storm_area_GEV is a generalised extreme value distribution
+ controlling the plan view area of each storm. S&M use 'shape': 0.,
+ which collapses the distribution to a plain extreme value
+ distribution.
+ monsoon_storm_interarrival_GEV is a generalised extreme value
+ distribution controlling the interarrival time between each storm.
+ In HRS. Note that this calibration is specifically to Walnut Gulch,
+ which has an area of 275 km**2. The generator directly scales this
+ resulting distribution to the area ratio of Walnut Gulch to the
+ open cells of the grid. This crudely accounts for the fact that
+ bigger catchments will have more storms, but note that the heavy
+ tail on this distribution means the default distribution shape
+ will not be trustworthy for catchments with big differences in
+ size from Walnut Gulch.
+ monsoon_storm_radial_weakening_gaussian is a normal distribution
+ controlling the rate of intensity decline with distance from storm
+ center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
+ et al., 2005.
+ winter_total_rf_gaussian is a normal distribution controlling the total
+ rainfall expected in each year. S&M use 'mu' in {143., 271.} for
+ step changes up/down in rainfall totals.
+ winter_storm_duration_fisk is a Fisk (i.e., log-logistic) distribution
+ controlling the duration of each storm. Note this differs from the
+ summer scaling. In MIN.
+ winter_storm_area_GEV is a generalised extreme value distribution
+ controlling the plan view area of each storm. S&M use 'shape': 0.,
+ which collapses the distribution to a plain extreme value
+ distribution.
+ winter_storm_interarrival_GEV is a generalised extreme value
+ distribution controlling the interarrival time between each storm.
+ In HRS. The same considerations apply here as for the monsoonal
+ interstorm equivalent.
+ winter_storm_radial_weakening_gaussian is a normal distribution
+ controlling the rate of intensity decline with distance from storm
+ center. For more detail see Rodriguez-Iturbe et al., 1986; Morin
+ et al., 2005.
+ """
+ monsoon_total_rf_gaussian = dict(monsoon_total_rf_gaussian)
+ monsoon_storm_duration_GEV = dict(monsoon_storm_duration_GEV)
+ monsoon_storm_area_GEV = dict(monsoon_storm_area_GEV)
+ monsoon_storm_interarrival_GEV = dict(monsoon_storm_interarrival_GEV)
+ monsoon_storm_radial_weakening_gaussian = dict(
+ monsoon_storm_radial_weakening_gaussian
+ )
+ winter_total_rf_gaussian = dict(winter_total_rf_gaussian)
+ winter_storm_duration_fisk = dict(winter_storm_duration_fisk)
+ winter_storm_area_GEV = dict(winter_storm_area_GEV)
+ winter_storm_interarrival_GEV = dict(winter_storm_interarrival_GEV)
+ winter_storm_radial_weakening_gaussian = dict(
+ winter_storm_radial_weakening_gaussian
+ )
+
+ FUZZMETHOD = "DEJH"
+ FUZZWIDTH = 5.0 # if DEJH
+ self._phantom_storm_count = 0
+ # ^this property tracks the number of storms in the run that received
+ # zero intensity (and thus didn't really exist)
+ self._opennodes = self._grid.status_at_node != self._grid.BC_NODE_IS_CLOSED
+ self._total_rainfall_last_season = self._grid.zeros(at="node")
+
+ # safety check for init conds:
+ if yield_storms:
+ assert yield_years is False
+ assert yield_seasons is False
+ if yield_years:
+ assert yield_storms is False
+ assert yield_seasons is False
+ if yield_seasons:
+ assert yield_storms is False
+ assert yield_years is False
+
+ # add variable for number of simulations of simyears
+ simyears = self._numyrs # number of years to simulate
+ numcurves = 11 # number of intensity-duration curves (see below for
+ # curve equations)
+ hrsinyr = 24.0 * 365.0
+ hrsinmonsoon = monsoon_fraction_of_year * hrsinyr
+ hrsinwinter = (1.0 - monsoon_fraction_of_year) * hrsinyr
+
+ assert limit in ("total_rainfall", "total_time")
+
+ assert style in ("whole_year", "monsoonal", "winter")
+ if style == "whole_year":
+ reps = 2
+ else:
+ reps = 1
+
+ opennodes = self._opennodes
+ num_opennodes = np.sum(opennodes)
+ IDs_open = np.where(opennodes)[0] # need this later
+ X1 = self._grid.node_x
+ Y1 = self._grid.node_y
+ Xin = X1[opennodes]
+ Yin = Y1[opennodes]
+ try:
+ Zz = self._grid.at_node["topographic__elevation"][opennodes]
+ except KeyError:
+ assert self._orographic_scenario is None
+ numgauges = Xin.size # number of rain gauges in the basin.
+ # NOTE: In this version this produces output on a grid, rather than at
+ # real gauge locations.
+
+ assert FUZZMETHOD == "DEJH", "The Singer method for fuzz is no longer supported"
+
+ # lambda_, kappa, and C are parameters of the intensity-duration curves
+ # of the form: intensity =
+ # lambda*exp(-0.508*duration)+kappa*exp(-0.008*duration)+C
+ lambda_ = [
+ 642.2,
+ 578.0,
+ 513.8,
+ 449.5,
+ 385.3,
+ 321.1,
+ 256.9,
+ 192.7,
+ 128.4,
+ 64.1,
+ 21.0,
+ ]
+ kappa = [93.1, 83.8, 74.5, 65.2, 55.9, 46.6, 37.2, 27.9, 18.6, 9.3, 0.9]
+ C = [4.5, 4.0, 3.5, 3.0, 2.5, 2.0, 1.5, 1.0, 0.5, 0.25, 0.05]
+
+ # Unlike MS's original implementation, we no longer pull ET values, as
+ # this should be a different component.
+
+ self._Ptot_ann_global = np.zeros(simyears)
+ self._Ptot_monsoon_global = np.zeros(simyears)
+
+ master_storm_count = 0
+ storm_trend = 0
+
+ for syear in range(simyears):
+ self._year = syear
+ year_time = 0.0 # tracks simulation time per year in hours
+ storm_trend += storminess_trend
+ year_storm_count = 0
+ breaker = False
+ Storm_total_local_year = np.zeros((self._max_numstorms, num_opennodes))
+ self._storm_running_sum_of_seasons = np.zeros(num_opennodes)
+ self._storm_running_sum_1st_seas = np.zeros(num_opennodes)
+
+ storms_yr_so_far = 0
+ for seas in range(reps):
+ seas_time = 0.0 # tracks elapsed season time in hours
+ Storm_running_sum_seas = np.zeros((2, num_opennodes))
+ # ^ 1st col is running total, 2nd is data to add to it
+ if seas == 0 and style != "winter":
+ self._current_season = "M"
+ # This is the pdf fitted to all available station precip
+ # data (normal dist). It will be sampled below.
+ Ptot_pdf_norm = monsoon_total_rf_gaussian
+
+ # This is the pdf fitted to all available station duration
+ # data (GEV dist). It will be sampled below.
+ # #### matlab's GEV is (shape_param, scale(sigma), pos(mu))
+ # note that in Scipy, we must add a minus to the shape
+ # param for a GEV to match Matlab's implementation
+ Duration_pdf = monsoon_storm_duration_GEV
+ # This is the pdf fitted to all available station area
+ # data (EV dist). It will be sampled below.
+ # #### matlab's EV is (mu, sigma)
+ Area_pdf_EV = monsoon_storm_area_GEV
+ # This is the pdf fitted to all available station area
+ # data (GEV dist). It will be sampled below.
+ Int_arr_pdf_GEV = monsoon_storm_interarrival_GEV
+ # This is the pdf of storm gradient recession coefficients
+ # from Morin et al, 2005 (normal dist). It will be sampled
+ # below.
+ Recess_pdf_norm = monsoon_storm_radial_weakening_gaussian
+ seas_total = hrsinmonsoon
+ else:
+ self._current_season = "W"
+ Ptot_pdf_norm = winter_total_rf_gaussian
+ Duration_pdf = winter_storm_duration_fisk
+ Area_pdf_EV = winter_storm_area_GEV
+ Int_arr_pdf_GEV = winter_storm_interarrival_GEV
+ Recess_pdf_norm = winter_storm_radial_weakening_gaussian
+ seas_total = hrsinwinter
+
+ if not np.isclose(total_rf_trend, 0.0):
+ mu = Ptot_pdf_norm.pop("mu")
+ mu += mu * total_rf_trend
+ Ptot_pdf_norm["mu"] = mu
+ # sample from normal distribution and saves global value of
+ # Ptot (that must be equalled or exceeded) for each year
+ season_rf_limit = self.calc_annual_rainfall(
+ style=style, monsoon_total_rf_gaussian=Ptot_pdf_norm
+ )[seas]
+ self._season_rf_limit = season_rf_limit
+ self._Ptot_ann_global[syear] += season_rf_limit
+ if seas == 0 and style != "winter":
+ self._Ptot_monsoon_global[syear] = season_rf_limit
+ Storm_total_local_seas = np.zeros((self._max_numstorms, num_opennodes))
+ seas_cum_Ptot_gauge = np.zeros(numgauges)
+ self._entries = 0
+
+ for seas_storm_count, storm in enumerate(range(self._max_numstorms)):
+ self._rain_int_gauge.fill(0.0)
+ int_arr_val = genextreme.rvs(
+ c=Int_arr_pdf_GEV["shape"],
+ loc=Int_arr_pdf_GEV["mu"],
+ scale=Int_arr_pdf_GEV["sigma"],
+ )
+ try:
+ int_arr_val = np.clip(
+ int_arr_val,
+ Int_arr_pdf_GEV["trunc_interval"][0],
+ Int_arr_pdf_GEV["trunc_interval"][1],
+ )
+ except KeyError:
+ # ...just in case
+ if int_arr_val < 0.0:
+ int_arr_val = 0.0
+ # now, correct the scaling relative to WG
+ int_arr_val /= self._scaling_to_WG
+ self._int_arr_val = int_arr_val
+ # ^Samples from distribution of interarrival times (hr).
+ # This can be used to develop STORM output for use in
+ # rainfall-runoff models or any water balance application.
+ # sample uniformly from storm center matrix from grid w
+ # 10 m spacings covering basin:
+
+ area_val = genextreme.rvs(
+ c=Area_pdf_EV["shape"],
+ loc=Area_pdf_EV["mu"],
+ scale=Area_pdf_EV["sigma"],
+ )
+ try:
+ area_val = np.clip(
+ area_val,
+ Area_pdf_EV["trunc_interval"][0],
+ Area_pdf_EV["trunc_interval"][1],
+ )
+ except KeyError:
+ # ...just in case
+ if area_val < 0.0:
+ area_val = 0.0
+ self._area_val = area_val
+ # ^Samples from distribution of storm areas
+
+ r = np.sqrt(area_val / np.pi) # value here shd be selected
+ rsq = r**2
+ # based on area above in meters to match the UTM values
+
+ # This way of handling storm locations is really quite
+ # different to MS's. He uses a fixed buffer width, and
+ # throws away any storm that doesn't intersect. We
+ # instead retain all storms, and *make sure* the storm
+ # intersects using a dynamic buffer. MS's method will
+ # preferentially sample larger storms, though unclear
+ # what that would mean in practice.
+ # MS also snaps his storms onto the grid. This seems
+ # unnecessary, and we don't do it here.
+ while 1:
+ cx, cy = self._locate_storm(r)
+ # Determine which gauges are hit by Euclidean geometry:
+ gdist = (Xin - cx) ** 2 + (Yin - cy) ** 2
+ mask_name = gdist <= rsq # this is defacto MS's aa
+ # this short circuits the storm loop in the case that
+ # the storm does not affect any 'gauging' location
+ if np.any(np.equal(mask_name, True)):
+ break
+
+ self._x = cx
+ self._y = cy
+ year_storm_count += 1
+ seas_storm_count += 1
+ master_storm_count += 1
+
+ # This routine below determines to which orographic group
+ # the closest gauge to the storm center belongs to, and
+ # censors the number of curves accordingly
+ # missing top curve in GR1, top and bottom curves for GR2,
+ # and bottom curve for GR3
+ # NOTE again, DEJH thinks this could be generalised a lot
+
+ # original curve# probs for 30%-20%-10%: [0.0636, 0.0727,
+ # 0.0819, 0.0909, 0.0909, 0.0909, 0.0909, 0.0909, 0.1001,
+ # 0.1090, 0.1182]
+ # original curve# probs are modified as below
+ # add weights to reflect reasonable probabilities that
+ # favor lower curves:
+ if self._orographic_scenario is not None:
+ # this routine below allows for orography in precip by
+ # first determining the closest gauge and then
+ # determining its orographic grouping
+ cc = np.argmin(gdist)
+ closest_gauge_z = Zz[cc] # this will be
+ # compared against orographic gauge groupings to
+ # determine the appropriate set of intensity-duration
+ # curves
+ if self._orographic_scenario == "Singer":
+ wgts = Singer_orographic_rainfall(closest_gauge_z)
+ else:
+ wgts = self._orographic_scenario(closest_gauge_z)
+ elif self._orographic_scenario is None:
+ wgts = [
+ 0.0636,
+ 0.0727,
+ 0.0819,
+ 0.0909,
+ 0.0909,
+ 0.0909,
+ 0.0909,
+ 0.0909,
+ 0.1001,
+ 0.1090,
+ 0.1182,
+ ]
+ if seas == 0 and style != "winter":
+ duration_val = genextreme.rvs(
+ c=Duration_pdf["shape"],
+ loc=Duration_pdf["mu"],
+ scale=Duration_pdf["sigma"],
+ )
+ else:
+ duration_val = fisk.rvs(
+ c=Duration_pdf["c"], scale=Duration_pdf["scale"]
+ )
+ # hacky fix to prevent occasional < 0 values:
+ # (I think because Matlab is able to set limits manually)
+ try:
+ duration_val = np.clip(
+ duration_val,
+ Duration_pdf["trunc_interval"][0],
+ Duration_pdf["trunc_interval"][1],
+ )
+ except KeyError:
+ # ...just in case
+ if duration_val < 0.0:
+ duration_val = 0.0
+ durationhrs = duration_val / 60.0
+ self._durationhrs = durationhrs
+ year_time += durationhrs
+ seas_time += durationhrs
+ # we will always do the next storm, even if it exceeds the
+ # specified "total" time
+
+ # which curve did we pick?:
+ int_dur_curve_val = np.random.choice(numcurves, p=wgts)
+
+ intensity_val = (
+ lambda_[int_dur_curve_val] * np.exp(-0.508 * duration_val)
+ + kappa[int_dur_curve_val] * np.exp(-0.008 * duration_val)
+ + C[int_dur_curve_val]
+ )
+ # ...these curves are based on empirical data from WG
+
+ # this dist should look identical, w/o discretisation
+ fuzz_int_val = FUZZWIDTH * 2.0 * (np.random.rand() - 0.5)
+
+ intensity_val += fuzz_int_val
+ # ^this allows for specified fuzzy tolerance around
+ # selected intensity (but it can go -ve)
+ # formerly, here MS used a rounding and threshold to
+ # prevent storms with a value < 1. We're going to remove
+ # the rounding and threshold at zero instead. (below)
+
+ # This scales the storm center intensity upward, so the
+ # values at each gauge are realistic once the gradient is
+ # applied.
+ intensity_val += intensity_val * storm_trend
+ # storminess trend is applied and its effect rises each
+ # year of simulation
+ # DEJH has removed the rounding
+ # Note that is is now possible for intensity_val to go
+ # negative, so:
+ if intensity_val < 0.0:
+ intensity_val = 0.0
+ self._phantom_storm_count += 1
+ # note storms of zero intensity are now permitted (though
+ # should hopefully remain pretty rare.)
+ self._intensity_val = intensity_val
+
+ # area to determine which gauges are hit:
+ recess_val = np.random.normal(
+ loc=Recess_pdf_norm["mu"], scale=Recess_pdf_norm["sigma"]
+ )
+ with contextlib.suppress(KeyError):
+ recess_val = np.clip(
+ recess_val,
+ Recess_pdf_norm["trunc_interval"][0],
+ Recess_pdf_norm["trunc_interval"][1],
+ )
+ self._recess_val = recess_val
+ # this pdf of recession coefficients determines how
+ # intensity declines with distance from storm center (see
+ # below)
+ # determine cartesian distances to all hit gauges and
+ # associated intensity values at each gauge hit by the
+ # storm
+ # This is a data storage solution to avoid issues that can
+ # arise with slicing grid areas with heavy tailed sizes
+ self._entries = np.sum(mask_name) # only open nodes
+ entries = self._entries
+ # NOTE _gauge_dist_km only contains nodes under the storm!
+ # The remaining entries are garbage
+ # Xin -> only the open nodes, note
+ self._gauge_dist_km[:entries] = np.sqrt(gdist[mask_name]) / 1000.0
+ self._temp_dataslots2[:entries] = gdist[mask_name] / 1.0e6
+ self._temp_dataslots2[:entries] *= -2.0 * recess_val**2
+ np.exp(
+ self._temp_dataslots2[:entries],
+ out=self._temp_dataslots2[:entries],
+ )
+ self._temp_dataslots2[:entries] *= intensity_val
+ mask_incl_closed = IDs_open[mask_name]
+ self._nodes_hit = mask_incl_closed
+ # ^note this is by ID, not bool
+ self._rain_int_gauge[mask_incl_closed] = self._temp_dataslots2[
+ :entries
+ ]
+ # calc of _rain_int_gauge follows Rodriguez-Iturbe et al.,
+ # 1986; Morin et al., 2005 but sampled from a distribution
+ # only need to add the bit that got rained on, so:
+ self._temp_dataslots2[:entries] *= duration_val / 60.0
+ seas_cum_Ptot_gauge[mask_name] += self._temp_dataslots2[:entries]
+ # collect storm totals for all gauges into rows by storm
+ Storm_total_local_seas[storm, :] = (
+ self._rain_int_gauge[opennodes] * duration_val / 60.0
+ )
+ Storm_total_local_year[(storm + storms_yr_so_far), :] = (
+ Storm_total_local_seas[storm, :]
+ )
+ self._max_storm_depth = Storm_total_local_seas[storm, :].max()
+
+ self._Storm_total_local_seas = Storm_total_local_seas
+ self._Storm_total_local_year = Storm_total_local_year
+ Storm_running_sum_seas[1, :] = Storm_total_local_seas[storm, :]
+ np.nansum(
+ Storm_running_sum_seas, axis=0, out=Storm_running_sum_seas[0, :]
+ )
+ if np.any(Storm_total_local_seas < 0.0):
+ raise ValueError(syear, storm)
+ self._median_seas_rf_total = np.nanmedian(
+ Storm_running_sum_seas[0, :]
+ )
+ self._Storm_running_sum_seas = Storm_running_sum_seas[0, :]
+
+ if limit == "total_time":
+ if seas_time + int_arr_val > seas_total:
+ int_arr_val = (seas_total - seas_time).clip(0.0)
+ breaker = True
+ else:
+ if self._median_seas_rf_total > season_rf_limit:
+ breaker = True
+ if yield_storms is True:
+ yield (durationhrs, int_arr_val)
+ seas_time += int_arr_val
+ year_time += int_arr_val
+ if breaker:
+ # Don't create Ptotal_local per MS... just
+ breaker = False
+ break
+ if storm + 1 == self._max_numstorms:
+ raise ValueError("_max_numstorms set too low for this run")
+ storms_yr_so_far = seas_storm_count
+ self._storm_running_sum_of_seasons += Storm_running_sum_seas[0, :]
+ self._total_rainfall_last_season[self._opennodes] = (
+ Storm_running_sum_seas[0, :]
+ )
+ self._storm_running_sum_1st_seas += Storm_running_sum_seas[0, :]
+ if yield_seasons:
+ yield seas_storm_count
+
+ self._total_rf_year[opennodes] = self._storm_running_sum_of_seasons
+ if yield_years is True and yield_seasons is False:
+ yield year_storm_count
+
+ def calc_annual_rainfall(
+ self,
+ style="whole_year",
+ monsoon_total_rf_gaussian=(("sigma", 64.0), ("mu", 207.0)),
+ winter_total_rf_gaussian=(("sigma", 52.0), ("mu", 1.65)),
+ ):
+ """Return a tuple of rainfall totals (mm) for the year, with entries
+ subdividing the yearly total into seasons as appropriate.
+
+ Parameters
+ ----------
+ style : ('whole_year', 'monsoonal', 'winter')
+ Whether to simulate 2 seasons, or a single season.
+ monsoon_total_rf_gaussian : dict of sigma and mu for the summer
+ distribution (if used). Defaults to Walnut Gulch.
+ winter_total_rf_gaussian : dict of sigma and mu for the summer
+ distribution (if used). Defaults to Walnut Gulch.
+
+ Returns
+ -------
+ tuple : (first_season_total, [second_season_total])
+ If style=='monsoonal' or 'winter', a len(1) tuple of the total rf.
+ If style=='whole_year', a len(2) tuple of (monsoon, winter) totals.
+
+ Examples
+ --------
+ >>> mg = RasterModelGrid((10, 10), xy_spacing=500.0)
+ >>> z = mg.add_zeros("topographic__elevation", at="node")
+ >>> rain = SpatialPrecipitationDistribution(mg)
+ >>> mytotals = []
+ >>> for yr in range(5):
+ ... mytotals.append(rain.calc_annual_rainfall(style="whole_year"))
+ ...
+ >>> [len(x) == 2 for x in mytotals]
+ [True, True, True, True, True]
+ >>> mytotals = []
+ >>> for yr in range(3):
+ ... mytotals.append(rain.calc_annual_rainfall(style="monsoonal"))
+ ...
+ >>> [len(x) == 1 for x in mytotals]
+ [True, True, True]
+ """
+ monsoon_total_rf_gaussian = dict(monsoon_total_rf_gaussian)
+ winter_total_rf_gaussian = dict(winter_total_rf_gaussian)
+
+ assert style in ("whole_year", "monsoonal", "winter")
+ if style in ("whole_year", "monsoonal"):
+ # sample from normal distribution and saves global value of Ptot
+ # (that must be equalled or exceeded) for each year
+ summer_rf_limit = np.random.normal(
+ loc=monsoon_total_rf_gaussian["mu"],
+ scale=monsoon_total_rf_gaussian["sigma"],
+ )
+ try:
+ summer_rf_limit = np.clip(
+ summer_rf_limit,
+ monsoon_total_rf_gaussian["trunc_interval"][0],
+ monsoon_total_rf_gaussian["trunc_interval"][1],
+ )
+ except KeyError:
+ # ...just in case
+ if summer_rf_limit < 0.0:
+ summer_rf_limit = 0.0
+ if style in ("whole_year", "winter"):
+ # sample from normal distribution and saves global value of Ptot
+ # (that must be equalled or exceeded) for each year
+ winter_rf_limit = np.random.normal(
+ loc=winter_total_rf_gaussian["mu"],
+ scale=winter_total_rf_gaussian["sigma"],
+ )
+ try:
+ winter_rf_limit = np.clip(
+ winter_rf_limit,
+ winter_total_rf_gaussian["trunc_interval"][0],
+ winter_total_rf_gaussian["trunc_interval"][1],
+ )
+ except KeyError:
+ # ...just in case
+ if winter_rf_limit < 0.0:
+ winter_rf_limit = 0.0
+ if style == "monsoonal":
+ return (summer_rf_limit,)
+ elif style == "winter":
+ return (winter_rf_limit,)
+ else:
+ return (summer_rf_limit, winter_rf_limit)
+
+ def _locate_storm(self, storm_radius):
+ """Because of the way the stats fall out, any simulated storm from the
+ distribution must intersect the catchment somewhere.
+
+ Note written in a grid-agnostic fashion.
+ """
+ stormposx = np.random.rand() * (self._widthx + 2.0 * storm_radius)
+ stormposy = np.random.rand() * (self._widthy + 2.0 * storm_radius)
+ stormx = self._minx - storm_radius + stormposx
+ stormy = self._miny - storm_radius + stormposy
+ return stormx, stormy
+
+ @property
+ def current_year(self):
+ """Get the current year as an int."""
+ return self._year
+
+ @property
+ def current_season(self):
+ """Get the current season.
+
+ 'M' is monsoon, 'W' is winter.
+ """
+ return self._current_season
+
+ @property
+ def storm_depth_last_storm(self):
+ """Get the maximum storm depth during the last storm (mm)."""
+ return self._max_storm_depth
+
+ @property
+ def storm_recession_value_last_storm(self):
+ """Get the recession parameter (radial die-off) for the last storm."""
+ return self._recess_val
+
+ @property
+ def storm_duration_last_storm(self):
+ """Get the duration (in hrs) of the last storm."""
+ return self._durationhrs
+
+ @property
+ def storm_area_last_storm(self):
+ """Get the area (in m**2) of the last storm."""
+ return self._area_val
+
+ @property
+ def storm_intensity_last_storm(self):
+ """Get the intensity (mm/hr) of the last storm, averaged under the
+ storm.
+
+ footprint. Note that duration * intensity != storm max depth.
+ """
+ return self._intensity_val
+
+ @property
+ def total_rainfall_last_season(self):
+ """Get the total recorded rainfall over the last (completed) simulated
+ season, spatially resolved (mm)."""
+ return self._total_rainfall_last_season
+
+ @property
+ def total_rainfall_last_year(self):
+ """Get the total recorded rainfall over the last (completed) simulated
+ year, spatially resolved (mm).
+
+ Equivalent to the field 'rainfall__total_depth_per_year'.
+ """
+ return self._total_rf_year
+
+ @property
+ def total_rainfall_this_season(self):
+ """Get the accumulated, spatially resolved total rainfall over the grid
+ for the season so far (mm)."""
+ self._running_total_rainfall_this_season[self._opennodes] = (
+ self._Storm_running_sum_seas
+ )
+ return self._running_total_rainfall_this_season
+
+ @property
+ def total_rainfall_this_year(self):
+ """Get the accumulated, spatially resolved total rainfall over the grid
+ for the year so far (mm)."""
+ self._running_total_rainfall_this_year[self._opennodes] = (
+ self._storm_running_sum_1st_seas + self._Storm_running_sum_seas
+ )
+ return self._running_total_rainfall_this_year
+
+ @property
+ def median_total_rainfall_last_season(self):
+ """Get the median total rainfall recorded over the open nodes of the
+ grid during the last (completed) simulated season (mm)."""
+ return np.nanmedian(self._total_rainfall_last_season[self._opennodes])
+
+ @property
+ def median_total_rainfall_last_year(self):
+ """Get the median total rainfall recorded over the open nodes of the
+ grid during the last (completed) simulated year (mm)."""
+ return np.nanmedian(self.total_rainfall_last_year[self._opennodes])
+
+ @property
+ def median_total_rainfall_this_season(self):
+ """Get the accumulated median total rainfall over the open nodes of the
+ grid so far this season (mm)."""
+ return self._median_seas_rf_total
+
+ @property
+ def median_total_rainfall_this_year(self):
+ """Get the accumulated median total rainfall over the open nodes of the
+ grid so far this year (mm)."""
+ return np.nanmedian(self.total_rainfall_this_year[self._opennodes])
+
+ @property
+ def number_of_nodes_under_storm(self):
+ """Get the number of nodes under the last storm."""
+ return self._entries
+
+ @property
+ def nodes_under_storm(self):
+ """Get the IDs of the nodes under the last storm."""
+ return self._nodes_hit
+
+ @property
+ def coordinates_of_last_storm_center(self):
+ """Get the coordinates of the center of the last storm as (x, y)."""
+ return (self._x, self._y)
+
+ @property
+ def target_median_total_rainfall_this_season(self):
+ """Get the stochastically generated "target" average total rainfall
+ amount over the catchment for the current season.
+
+ If limit == 'total_rainfall', this will be very close to
+ median_total_rainfall_last_season. If 'total_time', it will
+ diverge from this value.
+ """
+ return self._season_rf_limit
+
+
+def Singer_orographic_rainfall(z_closest_node_to_center):
+ """Return a set of curve weights for a provided z, assuming an orographic
+ rule following that presented in Singer & Michaelides 2017 & Singer et al.
+ 2018 and applicable specifically to Walnut Gulch. i.e., there are three
+ orographic divisions, divided at 1350 m and 1500 m.
+
+ Parameters
+ ----------
+ z_closest_node_to_center : float
+ The elevation of the node closest to the storm center.
+
+ Returns
+ -------
+ wgts : length 11 list
+ The weighting parameters to use in selecting a storm distribution
+ curve.
+ """
+ if z_closest_node_to_center <= 1350:
+ wgts = [
+ 0.0318,
+ 0.0759,
+ 0.0851,
+ 0.0941,
+ 0.0941,
+ 0.0941,
+ 0.0941,
+ 0.0941,
+ 0.1033,
+ 0.1121,
+ 0.1213,
+ ]
+ elif 1350 < z_closest_node_to_center <= 1500:
+ wgts = [
+ 0.0478,
+ 0.0778,
+ 0.0869,
+ 0.0959,
+ 0.0959,
+ 0.0959,
+ 0.0959,
+ 0.0959,
+ 0.1051,
+ 0.1141,
+ 0.0888,
+ ]
+ elif z_closest_node_to_center > 1500:
+ wgts = [
+ 0.0696,
+ 0.0786,
+ 0.0878,
+ 0.0968,
+ 0.0968,
+ 0.0968,
+ 0.0968,
+ 0.0968,
+ 0.1060,
+ 0.1149,
+ 0.0591,
+ ]
+ return wgts
+
+
+if __name__ == "__main__":
+ from matplotlib.pyplot import show
+
+ nx = 17
+ ny = 8
+ dx = 1000.0
+ mg = RasterModelGrid((nx, ny), xy_spacing=dx)
+
+ z = mg.add_zeros("topographic__elevation", at="node")
+ z += 1400.0
+ rain = SpatialPrecipitationDistribution(mg, number_of_years=1)
+ total_t = 0.0
+ for count, dt, interval_t in enumerate(
+ rain.yield_storms(style="whole_year", limit="total_time")
+ ):
+ total_t += dt + interval_t
+ print(dt, interval_t)
+ if count % 100 == 0:
+ print("Season:", rain.current_season, "of yr", rain.current_year)
+ print("Current storm:", count)
+ show()
+ print("Effective total years:")
+ print(total_t / 24.0 / 365.0)
+ print("Storms simulated:")
+ print(count)
diff --git a/src/landlab/components/species_evolution/README.md b/src/landlab/components/species_evolution/README.md
index 01a5b225d3..f9aec120dc 100644
--- a/src/landlab/components/species_evolution/README.md
+++ b/src/landlab/components/species_evolution/README.md
@@ -15,11 +15,11 @@ published February 2020 by the Journal of Open Source Software.
## Documentation and installation
-Landlab documentation is hosted on this [ReadTheDocs page](https://landlab.readthedocs.io/en/release),
+Landlab documentation is hosted on [csdms.io](https://landlab.csdms.io/),
including instructions to install Landlab. SpeciesEvolver is installed with
Landlab.
-SpeciesEvolver documentation is located [here](https://landlab.readthedocs.io/en/release/reference/components/species_evolution.html).
+SpeciesEvolver documentation is located [here](https://landlab.csdms.io/generated/api/landlab.components.species_evolution.html).
## SpeciesEvolver tutorial
@@ -28,7 +28,7 @@ through the following links:
- [Launch the tutorial](https://mybinder.org/v2/gh/landlab/landlab/release?filepath=notebooks/tutorials/species_evolution/Introduction_to_SpeciesEvolver.ipynb)
as interactive notebook in your browser, with no need to install software,
launched using Binder.
-- [A static version of the same tutorial](https://nbviewer.jupyter.org/github/landlab/landlab/blob/master/notebooks/tutorials/species_evolution/Introduction_to_SpeciesEvolver.ipynb)
+- [A static version of the same tutorial](https://landlab.csdms.io/tutorials/species_evolution/Introduction_to_SpeciesEvolver.html)
- All Landlab tutorials can be launched from [this directory](https://mybinder.org/v2/gh/landlab/landlab/release?filepath=notebooks/welcome.ipynb) using Binder.
## Get or give help
diff --git a/src/landlab/core/model_component.py b/src/landlab/core/model_component.py
index ee5ccf63b8..ade58f39cd 100644
--- a/src/landlab/core/model_component.py
+++ b/src/landlab/core/model_component.py
@@ -6,25 +6,25 @@
.. autosummary::
- ~landlab.core.model_component.Component.name
- ~landlab.core.model_component.Component.from_path
- ~landlab.core.model_component.Component.unit_agnostic
- ~landlab.core.model_component.Component.units
- ~landlab.core.model_component.Component.definitions
- ~landlab.core.model_component.Component.input_var_names
- ~landlab.core.model_component.Component.output_var_names
- ~landlab.core.model_component.Component.optional_var_names
- ~landlab.core.model_component.Component.var_type
- ~landlab.core.model_component.Component.var_units
- ~landlab.core.model_component.Component.var_definition
- ~landlab.core.model_component.Component.var_mapping
- ~landlab.core.model_component.Component.var_loc
- ~landlab.core.model_component.Component.var_help
- ~landlab.core.model_component.Component.initialize_output_fields
- ~landlab.core.model_component.Component.initialize_optional_output_fields
- ~landlab.core.model_component.Component.shape
- ~landlab.core.model_component.Component.grid
- ~landlab.core.model_component.Component.coords
+ ~Component.name
+ ~Component.from_path
+ ~Component.unit_agnostic
+ ~Component.units
+ ~Component.definitions
+ ~Component.input_var_names
+ ~Component.output_var_names
+ ~Component.optional_var_names
+ ~Component.var_type
+ ~Component.var_units
+ ~Component.var_definition
+ ~Component.var_mapping
+ ~Component.var_loc
+ ~Component.var_help
+ ~Component.initialize_output_fields
+ ~Component.initialize_optional_output_fields
+ ~Component.shape
+ ~Component.grid
+ ~Component.coords
"""
import os
diff --git a/src/landlab/core/utils.py b/src/landlab/core/utils.py
index 0f68b52568..fd2bb880b9 100644
--- a/src/landlab/core/utils.py
+++ b/src/landlab/core/utils.py
@@ -6,17 +6,17 @@
.. autosummary::
- ~landlab.core.utils.radians_to_degrees
- ~landlab.core.utils.as_id_array
- ~landlab.core.utils.make_optional_arg_into_id_array
- ~landlab.core.utils.get_functions_from_module
- ~landlab.core.utils.add_functions_to_class
- ~landlab.core.utils.add_module_functions_to_class
- ~landlab.core.utils.strip_grid_from_method_docstring
- ~landlab.core.utils.argsort_points_by_x_then_y
- ~landlab.core.utils.sort_points_by_x_then_y
- ~landlab.core.utils.anticlockwise_argsort_points
- ~landlab.core.utils.get_categories_from_grid_methods
+ ~radians_to_degrees
+ ~as_id_array
+ ~make_optional_arg_into_id_array
+ ~get_functions_from_module
+ ~add_functions_to_class
+ ~add_module_functions_to_class
+ ~strip_grid_from_method_docstring
+ ~argsort_points_by_x_then_y
+ ~sort_points_by_x_then_y
+ ~anticlockwise_argsort_points
+ ~get_categories_from_grid_methods
"""
import errno
import importlib
diff --git a/src/landlab/field/graph_field.py b/src/landlab/field/graph_field.py
index 8e2c4b56ae..7992946e6b 100644
--- a/src/landlab/field/graph_field.py
+++ b/src/landlab/field/graph_field.py
@@ -2,11 +2,14 @@
:class:`~landlab.graph.graph.Graph`.
"""
+import inspect
+import warnings
+
import numpy as np
import xarray as xr
-from .errors import FieldError
-from .errors import GroupError
+from landlab.field.errors import FieldError
+from landlab.field.errors import GroupError
def reshape_for_storage(array, field_size=None):
@@ -658,14 +661,9 @@ def has_field(self, *args, **kwds):
:meta landlab: info-field
"""
- if len(args) == 2:
- group, field = args
- elif len(args) == 1:
- group, field = kwds.pop("at", self.default_group), args[0]
- else:
- raise ValueError("number of arguments must be 1 or 2")
- if group is None:
- raise ValueError("no group provided")
+ kwds.setdefault("at", self.default_group)
+ args, group = _parse_args_and_location(1, *args, **kwds)
+ field = args[0]
try:
return field in self[group]
@@ -784,14 +782,9 @@ def field_values(self, *args, **kwds):
:meta landlab: field-io
"""
- if len(args) == 2:
- group, field = args
- elif len(args) == 1:
- group, field = kwds.pop("at", self.default_group), args[0]
- else:
- raise ValueError("number of arguments must be 1 or 2")
- if group is None:
- raise ValueError("no group provided")
+ kwds.setdefault("at", self.default_group)
+ args, group = _parse_args_and_location(1, *args, **kwds)
+ field = args[0]
try:
fields = self[group]
@@ -883,17 +876,12 @@ def return_array_or_field_values(self, *args, **kwds):
:meta landlab: field-io
"""
- if len(args) == 2:
- group, field = args
- elif len(args) == 1:
- group, field = kwds.pop("at", self.default_group), args[0]
- else:
- raise ValueError("number of arguments must be 1 or 2")
- if group is None:
- raise ValueError("no group provided")
+ kwds.setdefault("at", self.default_group)
+ args, group = _parse_args_and_location(1, *args, **kwds)
+ field = args[0]
if isinstance(field, str):
- vals = self.field_values(group, field)
+ vals = self.field_values(field, at=group)
else:
vals = np.asarray(field)
if vals.size != self[group].size:
@@ -932,14 +920,9 @@ def field_units(self, *args, **kwds):
:meta landlab: info-field
"""
- if len(args) == 2:
- group, field = args
- elif len(args) == 1:
- group, field = kwds.pop("at", self.default_group), args[0]
- else:
- raise ValueError("number of arguments must be 1 or 2")
- if group is None:
- raise ValueError("no group provided")
+ kwds.setdefault("at", self.default_group)
+ args, group = _parse_args_and_location(1, *args, **kwds)
+ field = args[0]
return self[group]._ds[field].attrs["units"]
@@ -977,10 +960,9 @@ def empty(self, *args, **kwds):
:meta landlab: field-add
"""
- if len(args) == 0:
- group = kwds.pop("at", kwds.pop("centering", "node"))
- else:
- group = args[0]
+ kwds.setdefault("at", kwds.pop("centering", "node"))
+ args, group = _parse_args_and_location(0, *args, **kwds)
+ kwds.pop("at")
if group == "grid":
raise ValueError(
@@ -1148,12 +1130,10 @@ def add_field(self, *args, **kwds):
:meta landlab: field-add
"""
- if len(args) == 3:
- at, name, value_array = args
- elif len(args) == 2:
- at, name, value_array = (kwds.pop("at", None), args[0], args[1])
- else:
- raise ValueError("number of arguments must be 2 or 3")
+ kwds.setdefault("at", "node")
+ args, at = _parse_args_and_location(2, *args, **kwds)
+ name, value_array = args
+ kwds.pop("at")
units = kwds.get("units", "?")
copy = kwds.get("copy", False)
@@ -1250,12 +1230,11 @@ def add_empty(self, *args, **kwds):
:meta landlab: field-add
"""
- if len(args) == 2:
- loc, name = args
- elif len(args) == 1:
- loc, name = kwds.pop("at"), args[0]
- else:
- raise ValueError("number of arguments must be 1 or 2")
+ kwds.setdefault("at", "node")
+ args, loc = _parse_args_and_location(1, *args, **kwds)
+ name = args[0]
+ kwds.pop("at")
+
units = kwds.pop("units", "?")
copy = kwds.pop("copy", False)
clobber = kwds.pop("clobber", False)
@@ -1397,14 +1376,65 @@ def add_full(self, *args, **kwds):
:meta landlab: field-add
"""
- if len(args) == 3:
- at, name, fill_value = args
- elif len(args) == 2:
- at = kwds.pop("at", "node")
- name, fill_value = args
- else:
- raise ValueError("number of arguments must be 2 or 3")
+ kwds.setdefault("at", "node")
+ args, at = _parse_args_and_location(2, *args, **kwds)
+ name, fill_value = args
+ kwds.pop("at")
data = self.add_empty(name, at=at, **kwds)
data.fill(fill_value)
return data
+
+
+def _parse_args_and_location(n_args: int, *args, **kwds) -> tuple[str, str]:
+ """Parse arguments for backward compatibility.
+
+ Parameters
+ ----------
+ n_args : int
+ The new number of expected arguments.
+ *args : tuple
+ The passed arguments.
+ **kwds : dict
+ The passed keyword arguments.
+
+ Returns
+ -------
+ tuple of tuple, str
+ The arguments as expect with the new signature followed by
+ the location string.
+
+ Examples
+ --------
+ >>> from landlab.field.graph_field import _parse_args_and_location
+ >>> _parse_args_and_location(0, "node")
+ ((), 'node')
+ >>> _parse_args_and_location(1, "node", "z")
+ (('z',), 'node')
+ >>> _parse_args_and_location(2, "cell", "z", [1, 2, 3])
+ (('z', [1, 2, 3]), 'cell')
+ >>> _parse_args_and_location(2, "cell", "z", [1, 2, 3], at="node")
+ (('z', [1, 2, 3]), 'cell')
+ >>> _parse_args_and_location(2, "z", [1, 2, 3], at="node")
+ (('z', [1, 2, 3]), 'node')
+ """
+ if len(args) == n_args:
+ return args, kwds.get("at", None)
+ elif len(args) == n_args + 1:
+ caller_name = inspect.stack()[1].function
+ sig = f"at={args[0]!r}"
+ if n_args > 0:
+ sig = ", ".join([f"arg{n}" for n in range(n_args)] + [sig])
+
+ warnings.warn(
+ f"Calling `{caller_name}` with the field location as the first argument"
+ " is deprecated and will be removed in future versions. Instead, please use"
+ " the `at` keyword to specify the location:"
+ f" {caller_name}({sig}).",
+ FutureWarning,
+ stacklevel=3,
+ )
+
+ return args[1:], args[0]
+ else:
+ raise ValueError(f"number of arguments must be {n_args} or {n_args + 1}")
diff --git a/src/landlab/graph/framed_voronoi/dual_framed_voronoi.py b/src/landlab/graph/framed_voronoi/dual_framed_voronoi.py
index b8634e1746..d5e9df309d 100644
--- a/src/landlab/graph/framed_voronoi/dual_framed_voronoi.py
+++ b/src/landlab/graph/framed_voronoi/dual_framed_voronoi.py
@@ -1,4 +1,4 @@
-""" Implement the DualFramedVoronoiGraph
+"""Implement the DualFramedVoronoiGraph
@author sebastien lenard
@date 2022, Aug
diff --git a/src/landlab/graph/framed_voronoi/framed_voronoi.py b/src/landlab/graph/framed_voronoi/framed_voronoi.py
index a75aa87517..cb0ae124f0 100644
--- a/src/landlab/graph/framed_voronoi/framed_voronoi.py
+++ b/src/landlab/graph/framed_voronoi/framed_voronoi.py
@@ -1,4 +1,4 @@
-""" Implementation of the FramedVoronoiGraph and its static layout:
+"""Implementation of the FramedVoronoiGraph and its static layout:
HorizontalRectVoronoiGraph. This pattern is inspired from the developments of the HexModelGrid
.. codeauthor:: sebastien lenard
diff --git a/src/landlab/grid/base.py b/src/landlab/grid/base.py
index 722e35ebef..62a747253c 100644
--- a/src/landlab/grid/base.py
+++ b/src/landlab/grid/base.py
@@ -2159,7 +2159,7 @@ def calc_hillshade_at_node(
code taken from GeospatialPython.com example from December 14th, 2014
DEJH found what looked like minor sign problems, and adjusted to follow
the `ArcGIS algorithm
- `.
+ `.
Remember when plotting that bright areas have high values. cmap='Greys'
will give an apparently inverted color scheme. *cmap='gray'* has white
diff --git a/src/landlab/grid/decorators.py b/src/landlab/grid/decorators.py
index 22e8ac7f12..90f678c2ad 100644
--- a/src/landlab/grid/decorators.py
+++ b/src/landlab/grid/decorators.py
@@ -5,9 +5,9 @@
.. autosummary::
- ~landlab.grid.decorators.override_array_setitem_and_reset
- ~landlab.grid.decorators.return_id_array
- ~landlab.grid.decorators.return_readonly_id_array
+ ~override_array_setitem_and_reset
+ ~return_id_array
+ ~return_readonly_id_array
"""
from functools import wraps
diff --git a/src/landlab/grid/gradients.py b/src/landlab/grid/gradients.py
index dac1f32b8f..f9400f351a 100644
--- a/src/landlab/grid/gradients.py
+++ b/src/landlab/grid/gradients.py
@@ -6,8 +6,8 @@
.. autosummary::
- ~landlab.grid.gradients.calc_grad_at_link
- ~landlab.grid.gradients.calc_diff_at_link
+ ~calc_grad_at_link
+ ~calc_diff_at_link
"""
import numpy as np
diff --git a/src/landlab/grid/hex_mappers.py b/src/landlab/grid/hex_mappers.py
index 7e449c4d19..5e151cdd7d 100755
--- a/src/landlab/grid/hex_mappers.py
+++ b/src/landlab/grid/hex_mappers.py
@@ -6,7 +6,7 @@
.. autosummary::
- ~landlab.grid.hex_mappers.map_link_vector_components_to_node_hex
+ ~map_link_vector_components_to_node_hex
"""
import enum
diff --git a/src/landlab/grid/mappers.py b/src/landlab/grid/mappers.py
index b47bbe53fa..ede263b446 100644
--- a/src/landlab/grid/mappers.py
+++ b/src/landlab/grid/mappers.py
@@ -6,25 +6,25 @@
.. autosummary::
- ~landlab.grid.mappers.map_link_head_node_to_link
- ~landlab.grid.mappers.map_link_tail_node_to_link
- ~landlab.grid.mappers.map_min_of_link_nodes_to_link
- ~landlab.grid.mappers.map_max_of_link_nodes_to_link
- ~landlab.grid.mappers.map_mean_of_link_nodes_to_link
- ~landlab.grid.mappers.map_value_at_min_node_to_link
- ~landlab.grid.mappers.map_value_at_max_node_to_link
- ~landlab.grid.mappers.map_node_to_cell
- ~landlab.grid.mappers.map_min_of_node_links_to_node
- ~landlab.grid.mappers.map_max_of_node_links_to_node
- ~landlab.grid.mappers.map_upwind_node_link_max_to_node
- ~landlab.grid.mappers.map_downwind_node_link_max_to_node
- ~landlab.grid.mappers.map_upwind_node_link_mean_to_node
- ~landlab.grid.mappers.map_downwind_node_link_mean_to_node
- ~landlab.grid.mappers.map_value_at_upwind_node_link_max_to_node
- ~landlab.grid.mappers.map_value_at_downwind_node_link_max_to_node
- ~landlab.grid.mappers.map_link_vector_components_to_node
- ~landlab.grid.mappers.map_node_to_link_linear_upwind
- ~landlab.grid.mappers.map_node_to_link_lax_wendroff
+ ~map_link_head_node_to_link
+ ~map_link_tail_node_to_link
+ ~map_min_of_link_nodes_to_link
+ ~map_max_of_link_nodes_to_link
+ ~map_mean_of_link_nodes_to_link
+ ~map_value_at_min_node_to_link
+ ~map_value_at_max_node_to_link
+ ~map_node_to_cell
+ ~map_min_of_node_links_to_node
+ ~map_max_of_node_links_to_node
+ ~map_upwind_node_link_max_to_node
+ ~map_downwind_node_link_max_to_node
+ ~map_upwind_node_link_mean_to_node
+ ~map_downwind_node_link_mean_to_node
+ ~map_value_at_upwind_node_link_max_to_node
+ ~map_value_at_downwind_node_link_max_to_node
+ ~map_link_vector_components_to_node
+ ~map_node_to_link_linear_upwind
+ ~map_node_to_link_lax_wendroff
Each link has a *tail* and *head* node. The *tail* nodes are located at the
start of a link, while the head nodes are located at end of a link.
diff --git a/src/landlab/grid/raster_gradients.py b/src/landlab/grid/raster_gradients.py
index 4d022670fc..e7a18353a5 100644
--- a/src/landlab/grid/raster_gradients.py
+++ b/src/landlab/grid/raster_gradients.py
@@ -6,9 +6,9 @@
.. autosummary::
- ~landlab.grid.raster_gradients.calc_grad_at_link
- ~landlab.grid.raster_gradients.calc_grad_across_cell_faces
- ~landlab.grid.raster_gradients.calc_grad_across_cell_corners
+ ~calc_grad_at_link
+ ~calc_grad_across_cell_faces
+ ~calc_grad_across_cell_corners
"""
from collections import deque
diff --git a/src/landlab/grid/raster_mappers.py b/src/landlab/grid/raster_mappers.py
index 11c781d56d..a33002fee7 100644
--- a/src/landlab/grid/raster_mappers.py
+++ b/src/landlab/grid/raster_mappers.py
@@ -6,19 +6,19 @@
.. autosummary::
- ~landlab.grid.raster_mappers.map_sum_of_inlinks_to_node
- ~landlab.grid.raster_mappers.map_mean_of_inlinks_to_node
- ~landlab.grid.raster_mappers.map_max_of_inlinks_to_node
- ~landlab.grid.raster_mappers.map_min_of_inlinks_to_node
- ~landlab.grid.raster_mappers.map_sum_of_outlinks_to_node
- ~landlab.grid.raster_mappers.map_mean_of_outlinks_to_node
- ~landlab.grid.raster_mappers.map_max_of_outlinks_to_node
- ~landlab.grid.raster_mappers.map_min_of_outlinks_to_node
- ~landlab.grid.raster_mappers.map_mean_of_links_to_node
- ~landlab.grid.raster_mappers.map_mean_of_horizontal_links_to_node
- ~landlab.grid.raster_mappers.map_mean_of_horizontal_active_links_to_node
- ~landlab.grid.raster_mappers.map_mean_of_vertical_links_to_node
- ~landlab.grid.raster_mappers.map_mean_of_vertical_active_links_to_node
+ ~map_sum_of_inlinks_to_node
+ ~map_mean_of_inlinks_to_node
+ ~map_max_of_inlinks_to_node
+ ~map_min_of_inlinks_to_node
+ ~map_sum_of_outlinks_to_node
+ ~map_mean_of_outlinks_to_node
+ ~map_max_of_outlinks_to_node
+ ~map_min_of_outlinks_to_node
+ ~map_mean_of_links_to_node
+ ~map_mean_of_horizontal_links_to_node
+ ~map_mean_of_horizontal_active_links_to_node
+ ~map_mean_of_vertical_links_to_node
+ ~map_mean_of_vertical_active_links_to_node
"""
import numpy as np
diff --git a/src/landlab/io/esri_ascii.py b/src/landlab/io/esri_ascii.py
index 7700b92f7e..4c541dd90a 100644
--- a/src/landlab/io/esri_ascii.py
+++ b/src/landlab/io/esri_ascii.py
@@ -6,12 +6,12 @@
.. autosummary::
- ~landlab.io.esri_ascii.dump
- ~landlab.io.esri_ascii.lazy_load
- ~landlab.io.esri_ascii.lazy_loads
- ~landlab.io.esri_ascii.load
- ~landlab.io.esri_ascii.loads
- ~landlab.io.esri_ascii.parse
+ ~dump
+ ~lazy_load
+ ~lazy_loads
+ ~load
+ ~loads
+ ~parse
"""
from __future__ import annotations
diff --git a/src/landlab/io/native_landlab.py b/src/landlab/io/native_landlab.py
index 4f6520a15c..e0b0f407ce 100644
--- a/src/landlab/io/native_landlab.py
+++ b/src/landlab/io/native_landlab.py
@@ -6,8 +6,8 @@
.. autosummary::
- ~landlab.io.native_landlab.load_grid
- ~landlab.io.native_landlab.save_grid
+ ~load_grid
+ ~save_grid
"""
import os
diff --git a/src/landlab/io/netcdf/read.py b/src/landlab/io/netcdf/read.py
index 1a2568ab94..4d4cb03964 100644
--- a/src/landlab/io/netcdf/read.py
+++ b/src/landlab/io/netcdf/read.py
@@ -6,7 +6,7 @@
.. autosummary::
- ~landlab.io.netcdf.read.read_netcdf
+ ~read_netcdf
"""
import contextlib
diff --git a/src/landlab/io/netcdf/write.py b/src/landlab/io/netcdf/write.py
index df497f2235..928c20712d 100644
--- a/src/landlab/io/netcdf/write.py
+++ b/src/landlab/io/netcdf/write.py
@@ -6,7 +6,7 @@
.. autosummary::
- ~landlab.io.netcdf.write.write_netcdf
+ ~write_netcdf
"""
import pathlib
diff --git a/src/landlab/io/obj.py b/src/landlab/io/obj.py
index 14e4b3a2c0..5d027cb964 100644
--- a/src/landlab/io/obj.py
+++ b/src/landlab/io/obj.py
@@ -6,7 +6,7 @@
.. autosummary::
- ~landlab.io.obj.write_obj
+ ~write_obj
"""
import os
import pathlib
diff --git a/src/landlab/plot/imshow.py b/src/landlab/plot/imshow.py
index b16d6b07d9..f0b22f81aa 100644
--- a/src/landlab/plot/imshow.py
+++ b/src/landlab/plot/imshow.py
@@ -6,9 +6,9 @@
.. autosummary::
- ~landlab.plot.imshow.imshow_grid
- ~landlab.plot.imshow.imshow_grid_at_cell
- ~landlab.plot.imshow.imshow_grid_at_node
+ ~imshow_grid
+ ~imshow_grid_at_cell
+ ~imshow_grid_at_node
"""
from warnings import warn
diff --git a/src/landlab/plot/imshowhs.py b/src/landlab/plot/imshowhs.py
index 0ee8b062a0..0b1e5705b4 100644
--- a/src/landlab/plot/imshowhs.py
+++ b/src/landlab/plot/imshowhs.py
@@ -5,8 +5,8 @@
.. autosummary::
- ~landlab.plot.imshowhs.imshowhs_grid
- ~landlab.plot.imshowhs.imshowhs_grid_at_node
+ ~imshowhs_grid
+ ~imshowhs_grid_at_node
"""
import warnings
diff --git a/src/landlab/plot/network_sediment_transporter/plot_network_and_parcels.py b/src/landlab/plot/network_sediment_transporter/plot_network_and_parcels.py
index 95c93a199f..647fa046cb 100644
--- a/src/landlab/plot/network_sediment_transporter/plot_network_and_parcels.py
+++ b/src/landlab/plot/network_sediment_transporter/plot_network_and_parcels.py
@@ -44,21 +44,23 @@ def plot_network_and_parcels(
parcel_size_max=40,
parcel_alpha=0.5,
fig=None,
+ output=None,
**kwargs,
):
"""Plot a river network and parcels on the river network.
- Intended to display the results of the NetworkSedimentTransporter component.
+ Intended to display the results of the :class:`~.NetworkSedimentTransporter`
+ component.
- The river network (an instance of NetworkModelGrid) is plotted either as
+ The river network (an instance of :class:`~.NetworkModelGrid`) is plotted either as
straight links between grid nodes, or (if the network was created using a
shapefile to set network topology) as sinuous lines representing the actual
link geometry.
- The parcels (an instance of DataRecord) are represented as dot markers
+ The parcels (an instance of :class:`~.DataRecord`) are represented as dot markers
along the links, with the marker location set by parcel attribute
`location_at_link`. The default is to plot the parcel locations at the
- last timestep in DataRecord, though any time index may be specified.
+ last timestep in :class`~.DataRecord`, though any time index may be specified.
Use of this plotting tool is described in detail in a landlab tutorial.
@@ -68,14 +70,14 @@ def plot_network_and_parcels(
Instance of NetworkModelGrid.
parcels : DataRecord
Instance of Landlab DataRecord, with the same attribute requirements as
- NetworkSedimentTransporter.
+ :class:`~.NetworkSedimentTransporter`.
parcel_time_index : int, optional
Parcel time index to plot. Default is last timestep in parcels
- DataRecord.
+ :class:`~.DataRecord`.
map_buffer : float, optional
Increase the plot extent by at least this much. Note, because of axis
equal, may be more.
- parcel_filter : array_like of boolean, shape (number_of_parcels, ), optional
+ parcel_filter : array_like of bool, shape (number_of_parcels, ), optional
Filter to plot only a selection of the parcels.
Other Parameters
@@ -83,60 +85,59 @@ def plot_network_and_parcels(
network_color : str, optional
Uniform color for network links.
link_attribute : array_like or str, optional
- Value (as either an array or the name of an at-link field) used to set
- ink color. Categorical options not supported. Must be continuous.
+ Value (as either an array or the name of an *at-link* field) used to set
+ link color. Categorical options not supported. Must be continuous.
link_attribute_title : str, optional
- String to use as the title, if link_attribute is a string, it is
+ String to use as the title, if `link_attribute` is a string, it is
used as the default.
network_cmap : str, optional
Name of colormap for network.
- network_norm : matplotlib color normalizer
- https://matplotlib.org/3.1.1/tutorials/colors/colormapnorms.html
- Default is linear between min and max of `link_attribute`.
+ network_norm : matplotlib.colors.Normalize, optional
+ Default is linear between minimum and maximum of `link_attribute`.
network_linewidth : float, optional
Width of network lines.
parcel_color : str, optional
Constant color used for parcel markers.
parcel_color_attribute : str, optional
- Parcel attribute name, Categorical options not supported. Must be continuous.
+ Parcel attribute name, categorical options not supported. Must be continuous.
parcel_color_attribute_title : str, optional
- String to use as the legend title. If parcel_color_attribute is a
+ String to use as the legend title. If `parcel_color_attribute` is a
string, it is used as the default.
parcel_color_cmap : str, optional
Name of colormap for variable parcel color.
- parcel_color_norm : matplotlib color normalizer.
- https://matplotlib.org/3.1.1/tutorials/colors/colormapnorms.html
- Default is linear between min and max of parcel_color_attribute.
+ parcel_color_norm : matplotlib.colors.Normalize, optional
+ Default is linear between minimum and maximum of `parcel_color_attribute`.
parcel_size : float, optional
- Marker size, in points.
+ Marker size in points.
parcel_size_attribute: str, optional
- Parcel attribute name, Categorical options not supported. Must be continuous.
+ Parcel attribute name, categorical options not supported. Must be continuous.
parcel_size_attribute_title : str, optional
String to use as the title, if `parcel_size_attribute` is a string, it is
used as the default.
- parcel_size_norm : par
- matplotlib color normalizer.
- https://matplotlib.org/3.1.1/tutorials/colors/colormapnorms.html
- Default is linear between min and max of `parcel_size_attribute`.
+ parcel_size_norm : matplotlib.colors.Normalize, optional
+ Default is linear between minimum and maximum of `parcel_size_attribute`.
parcel_size_min : float, optional
Specify the smallest size of the dot markers plotted, in
- units of points (default 5). Use with parcel_size_max. They will be
- aligned with the limits of parcel_size_norm.
+ units of points (default 5). Use with `parcel_size_max`. They will be
+ aligned with the limits of `parcel_size_norm`.
parcel_size_max : float, optional
Specify the largest size of the dot markers plotted, in
units of points (default 40). Use with `parcel_size_min`. They will be
- aligned with the limits of parcel_size_norm.
+ aligned with the limits of `parcel_size_norm`.
parcel_alpha : float, optional
Specify parcel marker transparency between 0.0 and 1.0.
- fig : figure, optional
+ fig : matplotlib.figure.Figure, optional
Default is to create a new figure object.
+ output : bool, str, optional
+ If not provided (or ``False``), the image is sent to the imaging buffer to await
+ an explicit call to :func:`~matplotlib.pyplot.show` or
+ :func:`~matplotlib.pyplot.savefig` from outside this function.
+ If a string, `output` should be the path to a file (with file extension) to
+ save the figure to. The function will then call
+ :func:`~matplotlib.pyplot.savefig` itself. If ``True``, the function will call
+ :func:`~matplotlib.pyplot.show` itself once plotting is complete.
**kwargs :
Anything else to pass to figure creation.
-
- Returns
- -------
- fig
- Figure object.
"""
# part 0 checking and default setting.
@@ -198,7 +199,11 @@ def plot_network_and_parcels(
# set up figure, label and legend gridspecs.
if fig is None:
+ fresh_fig = True
fig = plt.figure(**kwargs)
+ else:
+ # we'll be adding this plot to existing axes
+ fresh_fig = False
spec = gridspec.GridSpec(
ncols=1,
@@ -210,7 +215,14 @@ def plot_network_and_parcels(
figure=fig,
height_ratios=[1, 0.1, 0.2],
)
- ax = fig.add_subplot(spec[0, 0])
+
+ if fresh_fig:
+ ax = fig.add_subplot(spec[0, 0])
+ else:
+ plt.figure(fig)
+ ax = plt.gca()
+ ax.set_subplotspec(spec[0, 0])
+
if n_legends > 0:
label_spec = spec[1, 0].subgridspec(
ncols=2 * n_legends - 1,
@@ -435,7 +447,11 @@ def plot_network_and_parcels(
# make axes equal
ax.axis("equal")
- return fig
+ if isinstance(output, str):
+ plt.savefig(output, bbox_inches="tight")
+ plt.clf()
+ elif output:
+ plt.show()
def _get_xy_of_polylines(x_of_polylines, y_of_polylines):
diff --git a/src/landlab/utils/decorators.py b/src/landlab/utils/decorators.py
index 8cd8870af8..b674d8914b 100644
--- a/src/landlab/utils/decorators.py
+++ b/src/landlab/utils/decorators.py
@@ -5,9 +5,9 @@
.. autosummary::
- ~landlab.utils.decorators.use_field_name_or_array
- ~landlab.utils.decorators.make_return_array_immutable
- ~landlab.utils.decorators.deprecated
+ ~use_field_name_or_array
+ ~make_return_array_immutable
+ ~deprecated
"""
import inspect
diff --git a/src/landlab/utils/source_tracking_algorithm.py b/src/landlab/utils/source_tracking_algorithm.py
index 2d9edac6ab..0a9d059d05 100644
--- a/src/landlab/utils/source_tracking_algorithm.py
+++ b/src/landlab/utils/source_tracking_algorithm.py
@@ -4,9 +4,9 @@
+++++++++++++++++++++++++
.. autosummary::
- ~landlab.utils.source_tracking_algorithm.convert_arc_flow_directions_to_landlab_node_ids
- ~landlab.utils.source_tracking_algorithm.track_source
- ~landlab.utils.source_tracking_algorithm.find_unique_upstream_hsd_ids_and_fractions
+ ~convert_arc_flow_directions_to_landlab_node_ids
+ ~track_source
+ ~find_unique_upstream_hsd_ids_and_fractions
Authors: Sai Nudurupati & Erkan Istanbulluoglu
diff --git a/tests/components/concentration_tracker/test_concentration_tracker_for_space.py b/tests/components/concentration_tracker/test_concentration_tracker_for_space.py
new file mode 100644
index 0000000000..ce4e43615a
--- /dev/null
+++ b/tests/components/concentration_tracker/test_concentration_tracker_for_space.py
@@ -0,0 +1,350 @@
+"""
+Created on Wed Jul 12 12:25:27 2023
+
+@author: LaurentRoberge
+"""
+
+import numpy as np
+import pytest
+
+from landlab import FieldError
+from landlab import NodeStatus
+from landlab import RasterModelGrid
+from landlab.components import ConcentrationTrackerForSpace
+
+
+class TestInputParameters:
+ """Test input errors"""
+
+ def setup_method(self):
+ self.mg = RasterModelGrid((3, 3))
+ self.mg.add_zeros("soil__depth", at="node")
+ self.mg.add_zeros("sediment__outflux", at="node")
+ self.mg.add_zeros("bedrock__erosion_flux", at="node")
+ self.mg.add_zeros("sediment__erosion_flux", at="node")
+ self.mg.add_zeros("sediment__deposition_flux", at="node")
+ self.mg.add_zeros("topographic__elevation", at="node")
+
+ def test_inputs_phi_fraction_fines(self):
+ """
+ ConcentrationTrackerForSpace should throw an error when phi,
+ fraction_fines < 0 or > 1.
+ """
+ for phi in [-0.2, 1.2]:
+ with pytest.raises(ValueError):
+ ConcentrationTrackerForSpace(
+ self.mg,
+ phi=phi,
+ fraction_fines=0,
+ settling_velocity=1,
+ )
+ for fraction_fines in [-0.2, 1.2]:
+ with pytest.raises(ValueError):
+ ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=fraction_fines,
+ settling_velocity=1,
+ )
+
+ @pytest.mark.parametrize(
+ "at,required_field",
+ [
+ ("node", "soil__depth"),
+ ("node", "sediment__outflux"),
+ ("node", "bedrock__erosion_flux"),
+ ("node", "sediment__erosion_flux"),
+ ("node", "sediment__deposition_flux"),
+ ("node", "topographic__elevation"),
+ ],
+ )
+ def test_input_fields_soil(self, at, required_field):
+ """
+ ConcentrationTrackerForSpace should throw an error when input fields
+ are not provided (soil__depth, sediment__outflux, bedrock__erosion_flux,
+ sediment__erosion_flux, sediment__deposition_flux, topographic__elevation)
+ """
+ self.mg[at].pop(required_field)
+ with pytest.raises(FieldError):
+ ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=0,
+ settling_velocity=1,
+ )
+
+ def test_field_instantiation(self):
+ """
+ ConcentrationTrackerForSpace should instantiate the following fields
+ when they do not already exist ('bedrock_property__concentration' and
+ 'sediment_property__concentration')
+ """
+ ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=0,
+ settling_velocity=1,
+ )
+
+ missing_fields = {
+ "bedrock_property__concentration",
+ "sediment_property__concentration",
+ } - set(self.mg.at_node)
+ assert not missing_fields
+
+ @pytest.mark.parametrize(
+ "name",
+ ["sediment_property__concentration", "bedrock_property__concentration"],
+ )
+ def test_fields_for_default_input(self, name):
+ """Check default input produces correct fields with no pre-existing fields"""
+ ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=0,
+ settling_velocity=1,
+ )
+
+ assert np.allclose(self.mg.at_node[name], 0.0)
+
+ @pytest.mark.parametrize(
+ "name",
+ ["sediment_property__concentration", "bedrock_property__concentration"],
+ )
+ def test_fields_for_default_input_with_preexisting_fields(self, name):
+ """Check default input uses correct fields with pre-existing fields"""
+ initial = self.mg.add_field(
+ name, np.random.uniform(size=self.mg.number_of_nodes), at="node"
+ ).copy()
+
+ ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=0,
+ settling_velocity=1,
+ )
+
+ assert np.allclose(self.mg.at_node[name], initial)
+
+ @pytest.mark.parametrize(
+ "field,keyword",
+ [
+ ("sediment_property__concentration", "concentration_initial"),
+ ("bedrock_property__concentration", "concentration_in_bedrock"),
+ ],
+ )
+ def test_fields_for_user_value_input(self, field, keyword):
+ """Check user input of single values produces the correct fields"""
+ ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=0,
+ settling_velocity=1,
+ **{keyword: (initial_value := np.random.uniform())},
+ )
+
+ assert np.allclose(self.mg.at_node[field], initial_value)
+
+ @pytest.mark.parametrize(
+ "field,keyword",
+ [
+ ("sediment_property__concentration", "concentration_initial"),
+ ("bedrock_property__concentration", "concentration_in_bedrock"),
+ ],
+ )
+ def test_fields_for_user_array_input(self, field, keyword):
+ """Check user input of arrays produces the correct fields"""
+ ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=0,
+ settling_velocity=1,
+ **{
+ keyword: (
+ initial_value := np.random.uniform(size=self.mg.number_of_nodes)
+ )
+ },
+ )
+
+ assert np.allclose(self.mg.at_node[field], initial_value)
+
+ @pytest.mark.parametrize(
+ "keyword",
+ [
+ "concentration_initial",
+ "concentration_in_bedrock",
+ ],
+ )
+ def test_properties_concentrations(self, keyword):
+ """
+ ConcentrationTrackerForSpace should throw an error when input
+ concentration values are negative.
+ """
+ with pytest.raises(ValueError):
+ ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=0,
+ settling_velocity=1,
+ **{keyword: -1.0},
+ )
+
+
+class TestAnalytical:
+ """Test against analytical solution"""
+
+ def setup_method(self):
+ self.mg = RasterModelGrid((3, 5), xy_spacing=1.0)
+ self.mg.axis_units = ("m", "m")
+ self.mg.set_status_at_node_on_edges(
+ right=NodeStatus.CLOSED,
+ top=NodeStatus.CLOSED,
+ left=NodeStatus.CLOSED,
+ bottom=NodeStatus.CLOSED,
+ )
+ self.mg.status_at_node[5] = NodeStatus.FIXED_VALUE
+
+ # Grid fields
+ self.mg.add_zeros("soil__depth", at="node")
+ self.mg.at_node["soil__depth"][:] += 2
+ self.mg.add_zeros("bedrock__elevation", at="node")
+ self.mg.at_node["bedrock__elevation"][:] += self.mg.node_x
+ self.mg.add_field(
+ "topographic__elevation",
+ self.mg.at_node["bedrock__elevation"] + self.mg.at_node["soil__depth"],
+ at="node",
+ )
+ self.mg.add_zeros("sediment_property__concentration", at="node")
+ self.mg.add_zeros("bedrock_property__concentration", at="node")
+
+ # Add forced flow router and flux fields to grid and apply values.
+ flow_us_node_order = [5, 6, 7, 8, 3, 2, 1, 0, 4, 9, 10, 11, 12, 13, 14]
+ flow_receiver_ids = [
+ [0, 1, 2, 3, 4],
+ [5, 5, 6, 7, 8],
+ [10, 11, 12, 13, 14],
+ ]
+ discharge = [
+ [0.0, 0.0, 0.0, 0.0, 0.0],
+ [1.0, 1.0, 1.0, 1.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0, 0.0],
+ ]
+ Qs_out = [
+ [0.0, 0.0, 0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0, 1.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0, 0.0],
+ ]
+ Er = [
+ [0.0, 0.0, 0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0, 1.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0, 0.0],
+ ]
+ Es = [
+ [0.0, 0.0, 0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0, 1.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0, 0.0],
+ ]
+ Dsw = [
+ [0.0, 0.0, 0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0, 1.0, 0.0],
+ [0.0, 0.0, 0.0, 0.0, 0.0],
+ ]
+
+ self.mg.add_field("flow__receiver_node", flow_receiver_ids, at="node")
+ self.mg.add_field("flow__upstream_node_order", flow_us_node_order, at="node")
+ self.mg.add_field("surface_water__discharge", discharge, at="node")
+ self.mg.add_field("sediment__outflux", Qs_out, at="node")
+ self.mg.add_field("bedrock__erosion_flux", Er, at="node")
+ self.mg.add_field("sediment__erosion_flux", Es, at="node")
+ self.mg.add_field("sediment__deposition_flux", Dsw, at="node")
+
+ def test_not_implemented(self):
+ """Test that private run_one_step is not implemented"""
+
+ ct = ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=0,
+ settling_velocity=1,
+ )
+ with pytest.raises(NotImplementedError):
+ ct.run_one_step()
+
+ @pytest.mark.parametrize(
+ "Cs, Cr, expected, expected_sw",
+ [
+ (0.0, 0.0, 0.0, 0.0),
+ (1.0, 0.0, 3.0 / 4.0, 1.0 / 2.0),
+ (0.0, 1.0, 1.0 / 4.0, 1.0 / 2.0),
+ (1.0, 1.0, 1.0, 1.0),
+ ],
+ )
+ def test_Es_Er_Dsw(self, Cs, Cr, expected, expected_sw):
+ self.mg.at_node["sediment_property__concentration"][:] = Cs
+ self.mg.at_node["bedrock_property__concentration"][:] = Cr
+
+ ct = ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=0,
+ settling_velocity=1,
+ )
+
+ ct.start_tracking()
+ self.mg.at_node["soil__depth"][:] -= self.mg.at_node["sediment__erosion_flux"][
+ :
+ ]
+ self.mg.at_node["soil__depth"][:] += self.mg.at_node[
+ "sediment__deposition_flux"
+ ][:]
+ self.mg.at_node["topographic__elevation"][:] = (
+ self.mg.at_node["bedrock__elevation"][:] + self.mg.at_node["soil__depth"][:]
+ )
+ ct.stop_tracking(1)
+
+ assert np.allclose(ct._C_sw[8], expected_sw)
+ assert np.allclose(
+ self.mg.at_node["sediment_property__concentration"][8], expected
+ )
+
+
+# %%
+class TestFieldCopy:
+ """Test that copied field is a copy, but not a reference."""
+
+ def setup_method(self):
+ self.mg = RasterModelGrid((3, 3))
+ self.mg.add_zeros("soil__depth", at="node")
+ self.mg.add_zeros("sediment__outflux", at="node")
+ self.mg.add_zeros("bedrock__erosion_flux", at="node")
+ self.mg.add_zeros("sediment__erosion_flux", at="node")
+ self.mg.add_zeros("sediment__deposition_flux", at="node")
+ self.mg.add_zeros("topographic__elevation", at="node")
+
+ def test_copy_is_equal(self):
+ """Test that copied values are equal to copied field."""
+
+ ct = ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=0,
+ settling_velocity=1,
+ )
+ ct._copy_old_soil_depth()
+
+ assert np.allclose(ct._soil__depth_old, self.mg.at_node["soil__depth"])
+
+ def test_copy_is_not_reference(self):
+ """Test that copy not a reference."""
+
+ ct = ConcentrationTrackerForSpace(
+ self.mg,
+ phi=0,
+ fraction_fines=0,
+ settling_velocity=1,
+ )
+ ct._copy_old_soil_depth()
+
+ self.mg.at_node["soil__depth"] += 1
+
+ assert not np.allclose(ct._soil__depth_old, self.mg.at_node["soil__depth"])
diff --git a/tests/components/flexure/test_flexure.py b/tests/components/flexure/test_flexure.py
index d94663f064..c2e5b2b0ab 100644
--- a/tests/components/flexure/test_flexure.py
+++ b/tests/components/flexure/test_flexure.py
@@ -12,10 +12,9 @@
from landlab.components.flexure._ext.flexure2d import subside_loads
-@pytest.mark.benchmark(group="grid-size")
@pytest.mark.parametrize("n", [4, 5, 6, 7, 8, 9, 10])
@pytest.mark.parametrize("method", ["old", "new", "cython"])
-def test_one_load_bench(benchmark, n, method):
+def test_one_load_bench(n, method):
load_0 = 1e9
size = 2**n + 1
@@ -53,7 +52,7 @@ def test_one_load_bench(benchmark, n, method):
)
kwds = {}
- benchmark(func, *args, **kwds)
+ func(*args, **kwds)
assert_array_almost_equal(w, w[:, ::-1])
assert_array_almost_equal(w, w[::-1, :])
@@ -63,146 +62,8 @@ def test_one_load_bench(benchmark, n, method):
)
-@pytest.mark.slow
-@pytest.mark.benchmark(group="number-of-loads")
-@pytest.mark.parametrize("n_loads", [0, 1, 2, 3, 4, 5, 6, 7, 8])
-@pytest.mark.parametrize("method", ["old", "new", "cython"])
-def test_number_of_loads_bench(benchmark, n_loads, method):
- load_0 = 1e9
-
- n = 8
- size = 2**n + 1
-
- grid = RasterModelGrid((size, size), xy_spacing=10.0)
- grid.add_zeros("lithosphere__overlying_pressure_increment", at="node")
- flex = Flexure(grid, method="flexure")
-
- w = np.zeros((size, size))
-
- nodes = np.arange(0, size * size, 2 ** (n - n_loads))
- n_loads = len(nodes)
-
- loads = np.full(n_loads, load_0)
- row_col_of_load = np.unravel_index(nodes, w.shape)
-
- if method == "old":
- load_grid = grid.zeros(at="node").reshape(grid.shape)
- load_grid[row_col_of_load] = load_0
-
- func = flex.subside_loads_slow
- args = (load_grid,)
- kwds = {"out": w}
- elif method == "new":
- func = flex.subside_loads
- args = (loads, row_col_of_load)
- kwds = {"out": w}
- else:
- func = subside_loads
- args = (
- w,
- flex._r,
- loads,
- row_col_of_load[0],
- row_col_of_load[1],
- flex.alpha,
- flex.gamma_mantle,
- )
- kwds = {}
-
- benchmark(func, *args, **kwds)
-
-
-@pytest.mark.benchmark(group="row-col-of-grid")
-@pytest.mark.parametrize("n_loads", [0, 1, 2, 3, 4, 5, 6, 7, 8])
-def test_subside_loads_with_row_col_bench(benchmark, n_loads):
- n, load_0 = 8, 1e9
-
- size = 2**n + 1
-
- grid = RasterModelGrid((size, size), xy_spacing=10.0)
- grid.add_zeros("lithosphere__overlying_pressure_increment", at="node")
- flex = Flexure(grid, method="flexure")
-
- nodes = np.arange(0, size * size, 2 ** (n - n_loads))
- n_loads = len(nodes)
-
- loads = np.full(n_loads, load_0)
- row_col_of_load = np.unravel_index(nodes, grid.shape)
-
- dz = grid.zeros(at="node")
- benchmark(flex.subside_loads, loads, row_col_of_load=row_col_of_load, out=dz)
-
-
-@pytest.mark.benchmark(group="row-col-of-grid")
-@pytest.mark.parametrize("n_loads", [0, 1, 2, 3, 4, 5, 6, 7, 8])
-def test_subside_loads_without_row_col_bench(benchmark, n_loads):
- n, load_0 = 8, 1e9
-
- size = 2**n + 1
-
- grid = RasterModelGrid((size, size), xy_spacing=10.0)
- grid.add_zeros("lithosphere__overlying_pressure_increment", at="node")
- flex = Flexure(grid, method="flexure")
-
- loads = grid.zeros(at="node")
-
- nodes = np.arange(0, size * size, 2 ** (n - n_loads))
- n_loads = len(nodes)
- loads[nodes] = load_0
-
- actual = grid.zeros(at="node")
- benchmark(
- flex.subside_loads, loads.reshape(grid.shape), row_col_of_load=None, out=actual
- )
-
-
-@pytest.mark.slow
-@pytest.mark.benchmark(group="speedup")
@pytest.mark.parametrize("method", ["subside_loads", "subside_loads_slow"])
-@pytest.mark.parametrize("n_loads", [0, 1, 2, 3, 4, 5, 6, 7, 8])
-def test_flexure_loads_everywhere(benchmark, method, n_loads):
- n, load_0 = 8, 1e9
-
- size = 2**n + 1
-
- grid = RasterModelGrid((size, size), xy_spacing=10.0)
- grid.add_zeros("lithosphere__overlying_pressure_increment", at="node")
- flex = Flexure(grid, method="flexure")
-
- loads = grid.zeros(at="node")
- nodes = np.arange(0, size * size, 2 ** (n - n_loads))
- n_loads = len(nodes)
- loads[nodes] = load_0
-
- dz = np.zeros((size, size))
- benchmark(getattr(flex, method), loads, out=dz)
-
- # assert_array_almost_equal(dz, dz[:, ::-1])
- # assert_array_almost_equal(dz, dz[::-1, :])
-
-
-# @pytest.mark.benchmark(group="speedup")
-# @pytest.mark.parametrize("method", ["subside_loads", "subside_loads_slow"])
-# def test_flexure_loads_somewhere(benchmark, method):
-# n, load_0 = 8, 1e9
-
-# size = 2**n + 1
-
-# grid = RasterModelGrid((size, size), xy_spacing=10.0)
-# grid.add_zeros("lithosphere__overlying_pressure_increment", at="node")
-# flex = Flexure(grid, method="flexure")
-
-# loads = grid.zeros(at="node").reshape(grid.shape)
-# loads[:size//2, :size//2] = load_0
-# # loads.fill(load_0)
-
-# dz = np.zeros((size, size))
-# benchmark(getattr(flex, method), loads, out=dz)
-
-
-@pytest.mark.benchmark(group="speedup")
-@pytest.mark.parametrize("method", ["subside_loads", "subside_loads_slow"])
-def test_flexure_deflection_is_proportional_to_load(benchmark, method):
+def test_flexure_deflection_is_proportional_to_load(method):
n, load_0 = 8, 1e9
size = 2**n + 1
@@ -223,7 +84,7 @@ def test_flexure_deflection_is_proportional_to_load(benchmark, method):
assert_array_almost_equal(actual, expected * 10.0)
-def test_update_bench(benchmark):
+def test_update_bench():
n, load_0 = 10, 1e9
n_rows = 2**n + 1
@@ -236,7 +97,7 @@ def test_update_bench(benchmark):
grid.at_node["lithosphere__overlying_pressure_increment"].reshape(grid.shape)[
2 ** (n - 1), 2 ** (n - 1)
] = load_0
- benchmark(flex.update)
+ flex.update()
dz = flex.grid.at_node["lithosphere_surface__elevation_increment"].reshape(
grid.shape
)
diff --git a/tests/components/network_sediment_transporter/test_sediment_pulser.py b/tests/components/network_sediment_transporter/test_sediment_pulser.py
index e77eac92e7..0121927742 100644
--- a/tests/components/network_sediment_transporter/test_sediment_pulser.py
+++ b/tests/components/network_sediment_transporter/test_sediment_pulser.py
@@ -1,670 +1,670 @@
-import numpy as np
-import pandas as pd
-import pytest
-from numpy.testing import assert_allclose
-from numpy.testing import assert_array_equal
-from pytest import approx
-
-from landlab.components.network_sediment_transporter.sediment_pulser_at_links import (
- SedimentPulserAtLinks,
-)
-from landlab.components.network_sediment_transporter.sediment_pulser_base import (
- SedimentPulserBase,
-)
-from landlab.components.network_sediment_transporter.sediment_pulser_each_parcel import (
- SedimentPulserEachParcel,
-)
-
-
-def always_time_to_pulse(time):
- return True
-
-
-def time_to_pulse_list(time):
- Ptime = [19, 20, 22, 23, 24, 75, 76]
- return time in Ptime
-
-
-def test_call_SedimentPulserBase(example_nmg2):
- """test exception raised if SedimentPulserBase is called"""
- grid = example_nmg2
- make_pulse = SedimentPulserBase(grid)
-
- with pytest.raises(NotImplementedError) as exc_info:
- make_pulse()
- assert exc_info.match("the base component has no call method")
-
-
-class Test_SedimentPulserAtLinks:
- def test_normal_1(self, example_nmg2):
- """only time specified, links and number parcels specified,
- should use defaults in base class"""
- grid = example_nmg2
- time_to_pulse = always_time_to_pulse
-
- make_pulse = SedimentPulserAtLinks(grid, time_to_pulse=time_to_pulse, rng=1947)
-
- time = 11.0
- links = [0]
- n_parcels_at_link = [10]
- parcels = make_pulse(
- time=time, links=links, n_parcels_at_link=n_parcels_at_link
- )
-
- D50 = 0.05 # default grain size parameters
- D84_D50 = 2.1
- D_sd = D50 * D84_D50 - D50
-
- assert np.all(parcels.dataset["grid_element"] == "link")
- assert np.all(parcels.dataset["element_id"] == 0)
- assert np.all(parcels.dataset["starting_link"] == 0)
- assert np.all(parcels.dataset["abrasion_rate"] == 0)
- assert np.all(parcels.dataset["density"] == approx(2650.0))
- assert np.all(parcels.dataset["time_arrival_in_link"] == approx(time))
- assert np.all(parcels.dataset["active_layer"] == approx(1.0))
- assert np.all(parcels.dataset["volume"] == approx(0.5))
-
- assert np.all(
- (parcels.dataset["location_in_link"] >= 0.0)
- & (parcels.dataset["location_in_link"] <= 1.0)
- )
- # check mean randomly selected grain size with within 3 standard deviations
- # of specified mean
- assert np.abs(parcels.dataset["D"].mean() - D50) < 3 * D_sd
-
- def test_normal_2(self, example_nmg2):
- """only D50 specified, all other parcel attributes should
- use defaults in base class"""
-
- grid = example_nmg2
- time_to_pulse = always_time_to_pulse
-
- make_pulse = SedimentPulserAtLinks(grid, time_to_pulse=time_to_pulse, rng=2001)
- time = 11
- links = [2, 6]
- n_parcels_at_link = [2, 3]
- D50 = [0.3, 0.12]
- parcels = make_pulse(
- time=time, links=links, n_parcels_at_link=n_parcels_at_link, D50=D50
- )
-
- D50_1 = D50[0] # grain size
- D84_D50_1 = 2.1
- D_sd_1 = D50_1 * D84_D50_1 - D50_1
-
- D50_2 = D50[1] # grain size
- D84_D50_2 = 2.1
- D_sd_2 = D50_2 * D84_D50_2 - D50_2
-
- D = parcels.dataset["D"]
-
- assert np.all(parcels.dataset["grid_element"] == "link")
- assert np.all(parcels.dataset["element_id"] == [[2], [2], [6], [6], [6]])
- assert np.all(parcels.dataset["starting_link"] == [2, 2, 6, 6, 6])
- assert np.all(parcels.dataset["abrasion_rate"] == 0)
- assert np.all(parcels.dataset["density"] == approx(2650.0))
- assert np.all(parcels.dataset["time_arrival_in_link"] == approx(time))
- assert np.all(parcels.dataset["active_layer"] == approx(1.0))
- assert np.all(parcels.dataset["volume"] == approx(0.5))
-
- assert np.all(
- (parcels.dataset["location_in_link"] >= 0.0)
- & (parcels.dataset["location_in_link"] <= 1.0)
- )
- # check mean randomly selected grain size with within 3 standard deviations
- # of specified mean
- assert np.abs(D[0:2].mean() - D50_1) < 3 * D_sd_1
- assert np.abs(D[2:].mean() - D50_2) < 3 * D_sd_2
-
- def test_normal_3(self, example_nmg2):
- """two pulses. First, only time, links and number of parcels specified,
- uses defaults in base class for all other parcel attributes
- second, two parcels in link two and three parcels in link six
- are added and all attributes specified"""
-
- grid = example_nmg2
- time_to_pulse = always_time_to_pulse
-
- make_pulse = SedimentPulserAtLinks(grid, time_to_pulse=time_to_pulse, rng=1776)
-
- time = 11
- links = [0]
- n_parcels_at_link = [2]
- parcels = make_pulse(
- time=time, links=links, n_parcels_at_link=n_parcels_at_link
- )
-
- time = 12
- links = [2, 6]
- n_parcels_at_link = [2, 3]
- D50 = [0.3, 0.12]
- D84_D50 = [2.1, 1.5]
- parcel_volume = [1, 0.5]
- rho_sediment = [2650, 2500]
- abrasion_rate = [0.1, 0.3]
- parcels = make_pulse(
- time=time,
- links=links,
- n_parcels_at_link=n_parcels_at_link,
- D50=D50,
- D84_D50=D84_D50,
- parcel_volume=parcel_volume,
- rho_sediment=rho_sediment,
- abrasion_rate=abrasion_rate,
- )
-
- assert_array_equal(
- parcels.dataset["grid_element"].values.tolist(),
- [
- ["link", np.nan],
- ["link", np.nan],
- [np.nan, "link"],
- [np.nan, "link"],
- [np.nan, "link"],
- [np.nan, "link"],
- [np.nan, "link"],
- ],
- )
- assert_allclose(
- parcels.dataset["element_id"],
- [
- [0.0, np.nan],
- [0.0, np.nan],
- [np.nan, 2.0],
- [np.nan, 2.0],
- [np.nan, 6.0],
- [np.nan, 6.0],
- [np.nan, 6.0],
- ],
- )
- assert_allclose(
- parcels.dataset["starting_link"], [0.0, 0.0, 2.0, 2.0, 6.0, 6.0, 6.0]
- )
- assert_allclose(
- parcels.dataset["abrasion_rate"], [0.0, 0.0, 0.1, 0.1, 0.3, 0.3, 0.3]
- )
- assert_allclose(
- parcels.dataset["density"],
- [2650.0, 2650.0, 2650.0, 2650.0, 2500.0, 2500.0, 2500.0],
- )
- assert_allclose(
- parcels.dataset["time_arrival_in_link"],
- [
- [11.0, np.nan],
- [11.0, np.nan],
- [np.nan, 12.0],
- [np.nan, 12.0],
- [np.nan, 12.0],
- [np.nan, 12.0],
- [np.nan, 12.0],
- ],
- )
- assert_allclose(
- parcels.dataset["active_layer"],
- [
- [1.0, np.nan],
- [1.0, np.nan],
- [np.nan, 1.0],
- [np.nan, 1.0],
- [np.nan, 1.0],
- [np.nan, 1.0],
- [np.nan, 1.0],
- ],
- )
- assert_allclose(
- parcels.dataset["volume"],
- [
- [0.5, np.nan],
- [0.5, np.nan],
- [np.nan, 1.0],
- [np.nan, 1.0],
- [np.nan, 0.5],
- [np.nan, 0.5],
- [np.nan, 0.5],
- ],
- )
-
- assert np.all(
- (
- (parcels.dataset["location_in_link"] >= 0.0)
- & (parcels.dataset["location_in_link"] <= 1.0)
- )
- | np.isnan(parcels.dataset["location_in_link"])
- )
- assert np.all((parcels.dataset["D"] > 0.0) | np.isnan(parcels.dataset["D"]))
-
- def test_special_1(self, example_nmg2):
- """user entered time is not a pulse time, calling instance returns
- the original parcels datarecord, which is None if there is no
- original datarecord"""
-
- grid = example_nmg2
- time_to_pulse = time_to_pulse_list
-
- make_pulse = SedimentPulserAtLinks(grid, time_to_pulse=time_to_pulse, rng=1492)
-
- time = 11
- links = [0]
- n_parcels_at_link = [2]
- parcels = make_pulse(
- time=time, links=links, n_parcels_at_link=n_parcels_at_link
- )
-
- assert parcels is None
-
-
-# @pytest.mark.xfail(reason = "TDD, test class is not yet implemented")
-class Test_SedimentPulserEachParcel:
- def test_normal_1(self, example_nmg2):
- """minimum attributes specified in Pulse, attributes should use
- defaults specified at instantiation"""
-
- grid = example_nmg2
-
- make_pulse = SedimentPulserEachParcel(grid, rng=1975)
-
- PulseDF = pd.DataFrame(
- {
- "pulse_volume": [0.2, 1, 1.1, 0.5],
- "link_#": [1, 3, 5, 2],
- "normalized_downstream_distance": [0.8, 0.7, 0.5, 0.2],
- }
- )
- time = 7
- parcels = make_pulse(time, PulseDF)
-
- D50 = 0.05 # default grain size parameters
- D84_D50 = 2.1
- D_sd = D50 * D84_D50 - D50
- D = parcels.dataset["D"]
-
- assert np.all(parcels.dataset["grid_element"] == "link")
- assert np.all(
- parcels.dataset["element_id"] == [[1], [3], [3], [5], [5], [5], [2]]
- )
- assert np.all(parcels.dataset["starting_link"] == [1, 3, 3, 5, 5, 5, 2])
- assert np.all(parcels.dataset["abrasion_rate"] == approx(0.0))
- assert np.all(parcels.dataset["density"] == approx(2650.0))
- assert np.all(parcels.dataset["time_arrival_in_link"] == approx(time))
- assert np.all(parcels.dataset["active_layer"] == approx(1.0))
- assert_allclose(
- parcels.dataset["location_in_link"],
- [[0.8], [0.7], [0.7], [0.5], [0.5], [0.5], [0.2]],
- )
- assert_allclose(
- parcels.dataset["volume"], [[0.2], [0.5], [0.5], [0.5], [0.5], [0.1], [0.5]]
- )
-
- assert np.abs(D.mean() - D50) < 3 * D_sd
-
- def test_normal_2(self, example_nmg2):
- """all attributes specified in Pulse"""
-
- grid = example_nmg2
-
- make_pulse = SedimentPulserEachParcel(grid, rng=1066)
-
- PulseDF = pd.DataFrame(
- {
- "pulse_volume": [0.2, 1, 1.1, 0.5],
- "link_#": [1, 3, 5, 2],
- "normalized_downstream_distance": [0.8, 0.7, 0.5, 0.2],
- "D50": [0.15, 0.2, 0.22, 0.1],
- "D84_D50": [1, 1, 1, 1],
- "abrasion_rate": [0.01, 0.02, 0.005, 0.03],
- "rho_sediment": [2650, 2300, 2750, 2100],
- "parcel_volume": [0.1, 1, 1, 0.2],
- }
- )
- time = 7.0
- parcels = make_pulse(time, PulseDF)
-
- assert np.all(parcels.dataset["grid_element"] == "link")
- assert np.all(
- parcels.dataset["element_id"] == [[1], [1], [3], [5], [5], [2], [2], [2]]
- )
- assert np.all(parcels.dataset["starting_link"] == [1, 1, 3, 5, 5, 2, 2, 2])
- assert_allclose(
- parcels.dataset["abrasion_rate"],
- [0.01, 0.01, 0.02, 0.005, 0.005, 0.03, 0.03, 0.03],
- )
- assert_allclose(
- parcels.dataset["density"],
- [2650.0, 2650.0, 2300.0, 2750.0, 2750.0, 2100.0, 2100.0, 2100.0],
- )
- assert np.all(parcels.dataset["time_arrival_in_link"] == approx(time))
- assert np.all(parcels.dataset["active_layer"] == approx(1.0))
- assert_allclose(
- parcels.dataset["location_in_link"],
- [[0.8], [0.8], [0.7], [0.5], [0.5], [0.2], [0.2], [0.2]],
- )
- assert_allclose(
- parcels.dataset["D"],
- [[0.15], [0.15], [0.2], [0.22], [0.22], [0.1], [0.1], [0.1]],
- )
- assert_allclose(
- parcels.dataset["volume"],
- [[0.1], [0.1], [1], [1], [0.1], [0.2], [0.2], [0.1]],
- )
-
- def test_normal_3(self, example_nmg2):
- """two pulses. First, only minimum attributes specified,
- second, two parcels in link two and three parcels in link six
- are added and all attributes specified"""
-
- grid = example_nmg2
- np.random.seed(seed=5)
-
- make_pulse = SedimentPulserEachParcel(grid, rng=1945)
-
- PulseDF = pd.DataFrame(
- {
- "pulse_volume": [0.2, 1],
- "link_#": [1, 3],
- "normalized_downstream_distance": [0.8, 0.7],
- }
- )
- time = 7
- parcels = make_pulse(time, PulseDF)
-
- PulseDF = pd.DataFrame(
- {
- "pulse_volume": [1.1, 0.5],
- "link_#": [5, 2],
- "normalized_downstream_distance": [0.5, 0.2],
- "D50": [0.22, 0.1],
- "D84_D50": [2.1, 1.5],
- "abrasion_rate": [0.005, 0.03],
- "density": [2750, 2100],
- "parcel_volume": [1, 0.2],
- }
- )
- time = 8
- parcels = make_pulse(time, PulseDF)
-
- assert_array_equal(
- parcels.dataset["grid_element"].values.tolist(),
- [
- ["link", np.nan],
- ["link", np.nan],
- ["link", np.nan],
- [np.nan, "link"],
- [np.nan, "link"],
- [np.nan, "link"],
- [np.nan, "link"],
- [np.nan, "link"],
- ],
- )
- assert_allclose(
- parcels.dataset["element_id"],
- [
- [1.0, np.nan],
- [3.0, np.nan],
- [3.0, np.nan],
- [np.nan, 5.0],
- [np.nan, 5.0],
- [np.nan, 2.0],
- [np.nan, 2.0],
- [np.nan, 2.0],
- ],
- )
- assert_array_equal(parcels.dataset["starting_link"], [1, 3, 3, 5, 5, 2, 2, 2])
- assert_allclose(
- parcels.dataset["abrasion_rate"],
- [0.0, 0.0, 0.0, 0.005, 0.005, 0.03, 0.03, 0.03],
- )
- assert_allclose(parcels.dataset["density"], 2650.0)
- assert_allclose(
- parcels.dataset["time_arrival_in_link"],
- [
- [7.0, np.nan],
- [7.0, np.nan],
- [7.0, np.nan],
- [np.nan, 8.0],
- [np.nan, 8.0],
- [np.nan, 8.0],
- [np.nan, 8.0],
- [np.nan, 8.0],
- ],
- )
- assert_allclose(
- parcels.dataset["active_layer"],
- [
- [1.0, np.nan],
- [1.0, np.nan],
- [1.0, np.nan],
- [np.nan, 1.0],
- [np.nan, 1.0],
- [np.nan, 1.0],
- [np.nan, 1.0],
- [np.nan, 1.0],
- ],
- )
- assert_allclose(
- parcels.dataset["location_in_link"],
- [
- [0.8, np.nan],
- [0.7, np.nan],
- [0.7, np.nan],
- [np.nan, 0.5],
- [np.nan, 0.5],
- [np.nan, 0.2],
- [np.nan, 0.2],
- [np.nan, 0.2],
- ],
- )
- assert_allclose(
- parcels.dataset["volume"],
- [
- [0.2, np.nan],
- [0.5, np.nan],
- [0.5, np.nan],
- [np.nan, 1.0],
- [np.nan, 0.1],
- [np.nan, 0.2],
- [np.nan, 0.2],
- [np.nan, 0.1],
- ],
- )
-
- assert np.all((parcels.dataset["D"] > 0.0) | np.isnan(parcels.dataset["D"]))
-
- def test_normal_4(self, example_nmg2):
- """Series of pulses using both the SedimentPulserAtlinks and
- SedimentPulserEachParcel."""
-
- grid = example_nmg2
-
- # define the initial parcels datarecord
- make_pulse_links = SedimentPulserAtLinks(
- grid, time_to_pulse=always_time_to_pulse, rng=5
- )
-
- # pulse 1
- time = 7
- links = [0]
- n_parcels_at_link = [2]
- parcels = make_pulse_links(
- time=time, links=links, n_parcels_at_link=n_parcels_at_link
- )
-
- # datarecord is input to SedimentPulserEachParcel, now both pulser
- # instances will point to the same datarecord when called
- make_pulse_pulseDF = SedimentPulserEachParcel(
- parcels=parcels, grid=grid, rng=1863
- )
-
- # pulse 2
- PulseDF = pd.DataFrame(
- {
- "pulse_volume": [1.1],
- "link_#": [5],
- "normalized_downstream_distance": [0.5],
- "D50": [0.22],
- "D84_D50": [1],
- "abrasion_rate": [0.005],
- "density": [2750],
- "parcel_volume": [1],
- }
- )
- time = 8
- parcels = make_pulse_pulseDF(time, PulseDF)
-
- # pulse 3
- time = 9
- links = [5]
- n_parcels_at_link = [1]
- parcels = make_pulse_links(
- time=time, links=links, n_parcels_at_link=n_parcels_at_link
- )
-
- # pulse 4
- PulseDF = pd.DataFrame(
- {
- "pulse_volume": [0.5],
- "link_#": [6],
- "normalized_downstream_distance": [0.2],
- }
- )
- time = 10
- parcels = make_pulse_pulseDF(time, PulseDF)
-
- assert_array_equal(
- parcels.dataset["grid_element"].values.tolist(),
- [
- ["link", np.nan, np.nan, np.nan],
- ["link", np.nan, np.nan, np.nan],
- [np.nan, "link", np.nan, np.nan],
- [np.nan, "link", np.nan, np.nan],
- [np.nan, np.nan, "link", np.nan],
- [np.nan, np.nan, np.nan, "link"],
- ],
- )
- assert_allclose(
- parcels.dataset["element_id"],
- [
- [0.0, np.nan, np.nan, np.nan],
- [0.0, np.nan, np.nan, np.nan],
- [np.nan, 5.0, np.nan, np.nan],
- [np.nan, 5.0, np.nan, np.nan],
- [np.nan, np.nan, 5.0, np.nan],
- [np.nan, np.nan, np.nan, 6.0],
- ],
- )
- assert_array_equal(parcels.dataset["starting_link"], [0, 0, 5, 5, 5, 6])
- assert_allclose(
- parcels.dataset["abrasion_rate"], [0.0, 0.0, 0.005, 0.005, 0.0, 0.0]
- )
- assert_allclose(parcels.dataset["density"], 2650.0)
- assert_allclose(
- parcels.dataset["time_arrival_in_link"],
- [
- [7.0, np.nan, np.nan, np.nan],
- [7.0, np.nan, np.nan, np.nan],
- [np.nan, 8.0, np.nan, np.nan],
- [np.nan, 8.0, np.nan, np.nan],
- [np.nan, np.nan, 9.0, np.nan],
- [np.nan, np.nan, np.nan, 10.0],
- ],
- )
- assert_allclose(
- parcels.dataset["active_layer"],
- [
- [1.0, np.nan, np.nan, np.nan],
- [1.0, np.nan, np.nan, np.nan],
- [np.nan, 1.0, np.nan, np.nan],
- [np.nan, 1.0, np.nan, np.nan],
- [np.nan, np.nan, 1.0, np.nan],
- [np.nan, np.nan, np.nan, 1.0],
- ],
- )
- assert_allclose(
- parcels.dataset["location_in_link"],
- [
- [0.51532556, np.nan, np.nan, np.nan],
- [0.28580138, np.nan, np.nan, np.nan],
- [np.nan, 0.5, np.nan, np.nan],
- [np.nan, 0.5, np.nan, np.nan],
- [np.nan, np.nan, 0.38336888, np.nan],
- [np.nan, np.nan, np.nan, 0.2],
- ],
- )
- assert_allclose(
- parcels.dataset["volume"],
- [
- [0.5, np.nan, np.nan, np.nan],
- [0.5, np.nan, np.nan, np.nan],
- [np.nan, 1.0, np.nan, np.nan],
- [np.nan, 0.1, np.nan, np.nan],
- [np.nan, np.nan, 0.5, np.nan],
- [np.nan, np.nan, np.nan, 0.5],
- ],
- )
-
- # grain size must be greater than 0
- assert np.all((parcels.dataset["D"] > 0.0) | np.isnan(parcels.dataset["D"]))
-
- def test_bad_1(self, example_nmg2):
- """test exception raised if instance is called without specifying the
- pulserDF"""
-
- grid = example_nmg2
- make_pulse = SedimentPulserEachParcel(grid)
- PulseDF = None
- time = 7
-
- with pytest.raises(ValueError) as exc_info:
- make_pulse(time, PulseDF)
- assert exc_info.match("PulseDF was not specified")
-
- def test_special_1(self, example_nmg2):
- """test that calling with an empty PulseDF returns the existing
- datarecord"""
-
- grid = example_nmg2
-
- make_pulse = SedimentPulserEachParcel(grid, rng=5)
-
- PulseDF = pd.DataFrame(
- {
- "pulse_volume": [0.2, 1, 1.1, 0.5],
- "link_#": [1, 3, 5, 2],
- "normalized_downstream_distance": [0.8, 0.7, 0.5, 0.2],
- }
- )
- # call SedimentPulserEachParcel using setup in normal_test_1
- time1 = 7.0
- parcels = make_pulse(time1, PulseDF)
-
- # call again, using an empty PulserDF
- time2 = 8.0
- parcels = make_pulse(time2, pd.DataFrame([]))
-
- assert np.all(parcels.dataset["grid_element"] == "link")
- assert np.all(
- parcels.dataset["element_id"] == [[1], [3], [3], [5], [5], [5], [2]]
- )
- assert np.all(parcels.dataset["starting_link"] == [1, 3, 3, 5, 5, 5, 2])
- assert np.all(parcels.dataset["abrasion_rate"] == approx(0.0))
- assert np.all(parcels.dataset["time_arrival_in_link"] == approx(time1))
- assert np.all(parcels.dataset["active_layer"] == approx(1.0))
- assert_allclose(
- parcels.dataset["location_in_link"],
- [[0.8], [0.7], [0.7], [0.5], [0.5], [0.5], [0.2]],
- )
- assert_allclose(
- parcels.dataset["D"],
- [
- [0.0275786],
- [0.01871699],
- [0.04158561],
- [0.06830391],
- [0.11615185],
- [0.05423998],
- [0.03318153],
- ],
- )
- assert_allclose(
- parcels.dataset["volume"],
- np.array([[0.2], [0.5], [0.5], [0.5], [0.5], [0.1], [0.5]]),
- )
+import numpy as np
+import pandas as pd
+import pytest
+from numpy.testing import assert_allclose
+from numpy.testing import assert_array_equal
+from pytest import approx
+
+from landlab.components.network_sediment_transporter.sediment_pulser_at_links import (
+ SedimentPulserAtLinks,
+)
+from landlab.components.network_sediment_transporter.sediment_pulser_base import (
+ SedimentPulserBase,
+)
+from landlab.components.network_sediment_transporter.sediment_pulser_each_parcel import (
+ SedimentPulserEachParcel,
+)
+
+
+def always_time_to_pulse(time):
+ return True
+
+
+def time_to_pulse_list(time):
+ Ptime = [19, 20, 22, 23, 24, 75, 76]
+ return time in Ptime
+
+
+def test_call_SedimentPulserBase(example_nmg2):
+ """test exception raised if SedimentPulserBase is called"""
+ grid = example_nmg2
+ make_pulse = SedimentPulserBase(grid)
+
+ with pytest.raises(NotImplementedError) as exc_info:
+ make_pulse()
+ assert exc_info.match("the base component has no call method")
+
+
+class Test_SedimentPulserAtLinks:
+ def test_normal_1(self, example_nmg2):
+ """only time specified, links and number parcels specified,
+ should use defaults in base class"""
+ grid = example_nmg2
+ time_to_pulse = always_time_to_pulse
+
+ make_pulse = SedimentPulserAtLinks(grid, time_to_pulse=time_to_pulse, rng=1947)
+
+ time = 11.0
+ links = [0]
+ n_parcels_at_link = [10]
+ parcels = make_pulse(
+ time=time, links=links, n_parcels_at_link=n_parcels_at_link
+ )
+
+ D50 = 0.05 # default grain size parameters
+ D84_D50 = 2.1
+ D_sd = D50 * D84_D50 - D50
+
+ assert np.all(parcels.dataset["grid_element"] == "link")
+ assert np.all(parcels.dataset["element_id"] == 0)
+ assert np.all(parcels.dataset["starting_link"] == 0)
+ assert np.all(parcels.dataset["abrasion_rate"] == 0)
+ assert np.all(parcels.dataset["density"] == approx(2650.0))
+ assert np.all(parcels.dataset["time_arrival_in_link"] == approx(time))
+ assert np.all(parcels.dataset["active_layer"] == approx(1.0))
+ assert np.all(parcels.dataset["volume"] == approx(0.5))
+
+ assert np.all(
+ (parcels.dataset["location_in_link"] >= 0.0)
+ & (parcels.dataset["location_in_link"] <= 1.0)
+ )
+ # check mean randomly selected grain size with within 3 standard deviations
+ # of specified mean
+ assert np.abs(parcels.dataset["D"].mean() - D50) < 3 * D_sd
+
+ def test_normal_2(self, example_nmg2):
+ """only D50 specified, all other parcel attributes should
+ use defaults in base class"""
+
+ grid = example_nmg2
+ time_to_pulse = always_time_to_pulse
+
+ make_pulse = SedimentPulserAtLinks(grid, time_to_pulse=time_to_pulse, rng=2001)
+ time = 11
+ links = [2, 6]
+ n_parcels_at_link = [2, 3]
+ D50 = [0.3, 0.12]
+ parcels = make_pulse(
+ time=time, links=links, n_parcels_at_link=n_parcels_at_link, D50=D50
+ )
+
+ D50_1 = D50[0] # grain size
+ D84_D50_1 = 2.1
+ D_sd_1 = D50_1 * D84_D50_1 - D50_1
+
+ D50_2 = D50[1] # grain size
+ D84_D50_2 = 2.1
+ D_sd_2 = D50_2 * D84_D50_2 - D50_2
+
+ D = parcels.dataset["D"]
+
+ assert np.all(parcels.dataset["grid_element"] == "link")
+ assert np.all(parcels.dataset["element_id"] == [[2], [2], [6], [6], [6]])
+ assert np.all(parcels.dataset["starting_link"] == [2, 2, 6, 6, 6])
+ assert np.all(parcels.dataset["abrasion_rate"] == 0)
+ assert np.all(parcels.dataset["density"] == approx(2650.0))
+ assert np.all(parcels.dataset["time_arrival_in_link"] == approx(time))
+ assert np.all(parcels.dataset["active_layer"] == approx(1.0))
+ assert np.all(parcels.dataset["volume"] == approx(0.5))
+
+ assert np.all(
+ (parcels.dataset["location_in_link"] >= 0.0)
+ & (parcels.dataset["location_in_link"] <= 1.0)
+ )
+ # check mean randomly selected grain size with within 3 standard deviations
+ # of specified mean
+ assert np.abs(D[0:2].mean() - D50_1) < 3 * D_sd_1
+ assert np.abs(D[2:].mean() - D50_2) < 3 * D_sd_2
+
+ def test_normal_3(self, example_nmg2):
+ """two pulses. First, only time, links and number of parcels specified,
+ uses defaults in base class for all other parcel attributes
+ second, two parcels in link two and three parcels in link six
+ are added and all attributes specified"""
+
+ grid = example_nmg2
+ time_to_pulse = always_time_to_pulse
+
+ make_pulse = SedimentPulserAtLinks(grid, time_to_pulse=time_to_pulse, rng=1776)
+
+ time = 11
+ links = [0]
+ n_parcels_at_link = [2]
+ parcels = make_pulse(
+ time=time, links=links, n_parcels_at_link=n_parcels_at_link
+ )
+
+ time = 12
+ links = [2, 6]
+ n_parcels_at_link = [2, 3]
+ D50 = [0.3, 0.12]
+ D84_D50 = [2.1, 1.5]
+ parcel_volume = [1, 0.5]
+ rho_sediment = [2650, 2500]
+ abrasion_rate = [0.1, 0.3]
+ parcels = make_pulse(
+ time=time,
+ links=links,
+ n_parcels_at_link=n_parcels_at_link,
+ D50=D50,
+ D84_D50=D84_D50,
+ parcel_volume=parcel_volume,
+ rho_sediment=rho_sediment,
+ abrasion_rate=abrasion_rate,
+ )
+
+ assert_array_equal(
+ parcels.dataset["grid_element"].values.tolist(),
+ [
+ ["link", np.nan],
+ ["link", np.nan],
+ [np.nan, "link"],
+ [np.nan, "link"],
+ [np.nan, "link"],
+ [np.nan, "link"],
+ [np.nan, "link"],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["element_id"],
+ [
+ [0.0, np.nan],
+ [0.0, np.nan],
+ [np.nan, 2.0],
+ [np.nan, 2.0],
+ [np.nan, 6.0],
+ [np.nan, 6.0],
+ [np.nan, 6.0],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["starting_link"], [0.0, 0.0, 2.0, 2.0, 6.0, 6.0, 6.0]
+ )
+ assert_allclose(
+ parcels.dataset["abrasion_rate"], [0.0, 0.0, 0.1, 0.1, 0.3, 0.3, 0.3]
+ )
+ assert_allclose(
+ parcels.dataset["density"],
+ [2650.0, 2650.0, 2650.0, 2650.0, 2500.0, 2500.0, 2500.0],
+ )
+ assert_allclose(
+ parcels.dataset["time_arrival_in_link"],
+ [
+ [11.0, np.nan],
+ [11.0, np.nan],
+ [np.nan, 12.0],
+ [np.nan, 12.0],
+ [np.nan, 12.0],
+ [np.nan, 12.0],
+ [np.nan, 12.0],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["active_layer"],
+ [
+ [1.0, np.nan],
+ [1.0, np.nan],
+ [np.nan, 1.0],
+ [np.nan, 1.0],
+ [np.nan, 1.0],
+ [np.nan, 1.0],
+ [np.nan, 1.0],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["volume"],
+ [
+ [0.5, np.nan],
+ [0.5, np.nan],
+ [np.nan, 1.0],
+ [np.nan, 1.0],
+ [np.nan, 0.5],
+ [np.nan, 0.5],
+ [np.nan, 0.5],
+ ],
+ )
+
+ assert np.all(
+ (
+ (parcels.dataset["location_in_link"] >= 0.0)
+ & (parcels.dataset["location_in_link"] <= 1.0)
+ )
+ | np.isnan(parcels.dataset["location_in_link"])
+ )
+ assert np.all((parcels.dataset["D"] > 0.0) | np.isnan(parcels.dataset["D"]))
+
+ def test_special_1(self, example_nmg2):
+ """user entered time is not a pulse time, calling instance returns
+ the original parcels datarecord, which is None if there is no
+ original datarecord"""
+
+ grid = example_nmg2
+ time_to_pulse = time_to_pulse_list
+
+ make_pulse = SedimentPulserAtLinks(grid, time_to_pulse=time_to_pulse, rng=1492)
+
+ time = 11
+ links = [0]
+ n_parcels_at_link = [2]
+ parcels = make_pulse(
+ time=time, links=links, n_parcels_at_link=n_parcels_at_link
+ )
+
+ assert parcels is None
+
+
+# @pytest.mark.xfail(reason = "TDD, test class is not yet implemented")
+class Test_SedimentPulserEachParcel:
+ def test_normal_1(self, example_nmg2):
+ """minimum attributes specified in Pulse, attributes should use
+ defaults specified at instantiation"""
+
+ grid = example_nmg2
+
+ make_pulse = SedimentPulserEachParcel(grid, rng=1975)
+
+ PulseDF = pd.DataFrame(
+ {
+ "pulse_volume": [0.2, 1, 1.1, 0.5],
+ "link_#": [1, 3, 5, 2],
+ "normalized_downstream_distance": [0.8, 0.7, 0.5, 0.2],
+ }
+ )
+ time = 7
+ parcels = make_pulse(time, PulseDF)
+
+ D50 = 0.05 # default grain size parameters
+ D84_D50 = 2.1
+ D_sd = D50 * D84_D50 - D50
+ D = parcels.dataset["D"]
+
+ assert np.all(parcels.dataset["grid_element"] == "link")
+ assert np.all(
+ parcels.dataset["element_id"] == [[1], [3], [3], [5], [5], [5], [2]]
+ )
+ assert np.all(parcels.dataset["starting_link"] == [1, 3, 3, 5, 5, 5, 2])
+ assert np.all(parcels.dataset["abrasion_rate"] == approx(0.0))
+ assert np.all(parcels.dataset["density"] == approx(2650.0))
+ assert np.all(parcels.dataset["time_arrival_in_link"] == approx(time))
+ assert np.all(parcels.dataset["active_layer"] == approx(1.0))
+ assert_allclose(
+ parcels.dataset["location_in_link"],
+ [[0.8], [0.7], [0.7], [0.5], [0.5], [0.5], [0.2]],
+ )
+ assert_allclose(
+ parcels.dataset["volume"], [[0.2], [0.5], [0.5], [0.5], [0.5], [0.1], [0.5]]
+ )
+
+ assert np.abs(D.mean() - D50) < 3 * D_sd
+
+ def test_normal_2(self, example_nmg2):
+ """all attributes specified in Pulse"""
+
+ grid = example_nmg2
+
+ make_pulse = SedimentPulserEachParcel(grid, rng=1066)
+
+ PulseDF = pd.DataFrame(
+ {
+ "pulse_volume": [0.2, 1, 1.1, 0.5],
+ "link_#": [1, 3, 5, 2],
+ "normalized_downstream_distance": [0.8, 0.7, 0.5, 0.2],
+ "D50": [0.15, 0.2, 0.22, 0.1],
+ "D84_D50": [1, 1, 1, 1],
+ "abrasion_rate": [0.01, 0.02, 0.005, 0.03],
+ "rho_sediment": [2650, 2300, 2750, 2100],
+ "parcel_volume": [0.1, 1, 1, 0.2],
+ }
+ )
+ time = 7.0
+ parcels = make_pulse(time, PulseDF)
+
+ assert np.all(parcels.dataset["grid_element"] == "link")
+ assert np.all(
+ parcels.dataset["element_id"] == [[1], [1], [3], [5], [5], [2], [2], [2]]
+ )
+ assert np.all(parcels.dataset["starting_link"] == [1, 1, 3, 5, 5, 2, 2, 2])
+ assert_allclose(
+ parcels.dataset["abrasion_rate"],
+ [0.01, 0.01, 0.02, 0.005, 0.005, 0.03, 0.03, 0.03],
+ )
+ assert_allclose(
+ parcels.dataset["density"],
+ [2650.0, 2650.0, 2300.0, 2750.0, 2750.0, 2100.0, 2100.0, 2100.0],
+ )
+ assert np.all(parcels.dataset["time_arrival_in_link"] == approx(time))
+ assert np.all(parcels.dataset["active_layer"] == approx(1.0))
+ assert_allclose(
+ parcels.dataset["location_in_link"],
+ [[0.8], [0.8], [0.7], [0.5], [0.5], [0.2], [0.2], [0.2]],
+ )
+ assert_allclose(
+ parcels.dataset["D"],
+ [[0.15], [0.15], [0.2], [0.22], [0.22], [0.1], [0.1], [0.1]],
+ )
+ assert_allclose(
+ parcels.dataset["volume"],
+ [[0.1], [0.1], [1], [1], [0.1], [0.2], [0.2], [0.1]],
+ )
+
+ def test_normal_3(self, example_nmg2):
+ """two pulses. First, only minimum attributes specified,
+ second, two parcels in link two and three parcels in link six
+ are added and all attributes specified"""
+
+ grid = example_nmg2
+ np.random.seed(seed=5)
+
+ make_pulse = SedimentPulserEachParcel(grid, rng=1945)
+
+ PulseDF = pd.DataFrame(
+ {
+ "pulse_volume": [0.2, 1],
+ "link_#": [1, 3],
+ "normalized_downstream_distance": [0.8, 0.7],
+ }
+ )
+ time = 7
+ parcels = make_pulse(time, PulseDF)
+
+ PulseDF = pd.DataFrame(
+ {
+ "pulse_volume": [1.1, 0.5],
+ "link_#": [5, 2],
+ "normalized_downstream_distance": [0.5, 0.2],
+ "D50": [0.22, 0.1],
+ "D84_D50": [2.1, 1.5],
+ "abrasion_rate": [0.005, 0.03],
+ "density": [2750, 2100],
+ "parcel_volume": [1, 0.2],
+ }
+ )
+ time = 8
+ parcels = make_pulse(time, PulseDF)
+
+ assert_array_equal(
+ parcels.dataset["grid_element"].values.tolist(),
+ [
+ ["link", np.nan],
+ ["link", np.nan],
+ ["link", np.nan],
+ [np.nan, "link"],
+ [np.nan, "link"],
+ [np.nan, "link"],
+ [np.nan, "link"],
+ [np.nan, "link"],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["element_id"],
+ [
+ [1.0, np.nan],
+ [3.0, np.nan],
+ [3.0, np.nan],
+ [np.nan, 5.0],
+ [np.nan, 5.0],
+ [np.nan, 2.0],
+ [np.nan, 2.0],
+ [np.nan, 2.0],
+ ],
+ )
+ assert_array_equal(parcels.dataset["starting_link"], [1, 3, 3, 5, 5, 2, 2, 2])
+ assert_allclose(
+ parcels.dataset["abrasion_rate"],
+ [0.0, 0.0, 0.0, 0.005, 0.005, 0.03, 0.03, 0.03],
+ )
+ assert_allclose(parcels.dataset["density"], 2650.0)
+ assert_allclose(
+ parcels.dataset["time_arrival_in_link"],
+ [
+ [7.0, np.nan],
+ [7.0, np.nan],
+ [7.0, np.nan],
+ [np.nan, 8.0],
+ [np.nan, 8.0],
+ [np.nan, 8.0],
+ [np.nan, 8.0],
+ [np.nan, 8.0],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["active_layer"],
+ [
+ [1.0, np.nan],
+ [1.0, np.nan],
+ [1.0, np.nan],
+ [np.nan, 1.0],
+ [np.nan, 1.0],
+ [np.nan, 1.0],
+ [np.nan, 1.0],
+ [np.nan, 1.0],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["location_in_link"],
+ [
+ [0.8, np.nan],
+ [0.7, np.nan],
+ [0.7, np.nan],
+ [np.nan, 0.5],
+ [np.nan, 0.5],
+ [np.nan, 0.2],
+ [np.nan, 0.2],
+ [np.nan, 0.2],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["volume"],
+ [
+ [0.2, np.nan],
+ [0.5, np.nan],
+ [0.5, np.nan],
+ [np.nan, 1.0],
+ [np.nan, 0.1],
+ [np.nan, 0.2],
+ [np.nan, 0.2],
+ [np.nan, 0.1],
+ ],
+ )
+
+ assert np.all((parcels.dataset["D"] > 0.0) | np.isnan(parcels.dataset["D"]))
+
+ def test_normal_4(self, example_nmg2):
+ """Series of pulses using both the SedimentPulserAtlinks and
+ SedimentPulserEachParcel."""
+
+ grid = example_nmg2
+
+ # define the initial parcels datarecord
+ make_pulse_links = SedimentPulserAtLinks(
+ grid, time_to_pulse=always_time_to_pulse, rng=5
+ )
+
+ # pulse 1
+ time = 7
+ links = [0]
+ n_parcels_at_link = [2]
+ parcels = make_pulse_links(
+ time=time, links=links, n_parcels_at_link=n_parcels_at_link
+ )
+
+ # datarecord is input to SedimentPulserEachParcel, now both pulser
+ # instances will point to the same datarecord when called
+ make_pulse_pulseDF = SedimentPulserEachParcel(
+ parcels=parcels, grid=grid, rng=1863
+ )
+
+ # pulse 2
+ PulseDF = pd.DataFrame(
+ {
+ "pulse_volume": [1.1],
+ "link_#": [5],
+ "normalized_downstream_distance": [0.5],
+ "D50": [0.22],
+ "D84_D50": [1],
+ "abrasion_rate": [0.005],
+ "density": [2750],
+ "parcel_volume": [1],
+ }
+ )
+ time = 8
+ parcels = make_pulse_pulseDF(time, PulseDF)
+
+ # pulse 3
+ time = 9
+ links = [5]
+ n_parcels_at_link = [1]
+ parcels = make_pulse_links(
+ time=time, links=links, n_parcels_at_link=n_parcels_at_link
+ )
+
+ # pulse 4
+ PulseDF = pd.DataFrame(
+ {
+ "pulse_volume": [0.5],
+ "link_#": [6],
+ "normalized_downstream_distance": [0.2],
+ }
+ )
+ time = 10
+ parcels = make_pulse_pulseDF(time, PulseDF)
+
+ assert_array_equal(
+ parcels.dataset["grid_element"].values.tolist(),
+ [
+ ["link", np.nan, np.nan, np.nan],
+ ["link", np.nan, np.nan, np.nan],
+ [np.nan, "link", np.nan, np.nan],
+ [np.nan, "link", np.nan, np.nan],
+ [np.nan, np.nan, "link", np.nan],
+ [np.nan, np.nan, np.nan, "link"],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["element_id"],
+ [
+ [0.0, np.nan, np.nan, np.nan],
+ [0.0, np.nan, np.nan, np.nan],
+ [np.nan, 5.0, np.nan, np.nan],
+ [np.nan, 5.0, np.nan, np.nan],
+ [np.nan, np.nan, 5.0, np.nan],
+ [np.nan, np.nan, np.nan, 6.0],
+ ],
+ )
+ assert_array_equal(parcels.dataset["starting_link"], [0, 0, 5, 5, 5, 6])
+ assert_allclose(
+ parcels.dataset["abrasion_rate"], [0.0, 0.0, 0.005, 0.005, 0.0, 0.0]
+ )
+ assert_allclose(parcels.dataset["density"], 2650.0)
+ assert_allclose(
+ parcels.dataset["time_arrival_in_link"],
+ [
+ [7.0, np.nan, np.nan, np.nan],
+ [7.0, np.nan, np.nan, np.nan],
+ [np.nan, 8.0, np.nan, np.nan],
+ [np.nan, 8.0, np.nan, np.nan],
+ [np.nan, np.nan, 9.0, np.nan],
+ [np.nan, np.nan, np.nan, 10.0],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["active_layer"],
+ [
+ [1.0, np.nan, np.nan, np.nan],
+ [1.0, np.nan, np.nan, np.nan],
+ [np.nan, 1.0, np.nan, np.nan],
+ [np.nan, 1.0, np.nan, np.nan],
+ [np.nan, np.nan, 1.0, np.nan],
+ [np.nan, np.nan, np.nan, 1.0],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["location_in_link"],
+ [
+ [0.51532556, np.nan, np.nan, np.nan],
+ [0.28580138, np.nan, np.nan, np.nan],
+ [np.nan, 0.5, np.nan, np.nan],
+ [np.nan, 0.5, np.nan, np.nan],
+ [np.nan, np.nan, 0.38336888, np.nan],
+ [np.nan, np.nan, np.nan, 0.2],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["volume"],
+ [
+ [0.5, np.nan, np.nan, np.nan],
+ [0.5, np.nan, np.nan, np.nan],
+ [np.nan, 1.0, np.nan, np.nan],
+ [np.nan, 0.1, np.nan, np.nan],
+ [np.nan, np.nan, 0.5, np.nan],
+ [np.nan, np.nan, np.nan, 0.5],
+ ],
+ )
+
+ # grain size must be greater than 0
+ assert np.all((parcels.dataset["D"] > 0.0) | np.isnan(parcels.dataset["D"]))
+
+ def test_bad_1(self, example_nmg2):
+ """test exception raised if instance is called without specifying the
+ pulserDF"""
+
+ grid = example_nmg2
+ make_pulse = SedimentPulserEachParcel(grid)
+ PulseDF = None
+ time = 7
+
+ with pytest.raises(ValueError) as exc_info:
+ make_pulse(time, PulseDF)
+ assert exc_info.match("PulseDF was not specified")
+
+ def test_special_1(self, example_nmg2):
+ """test that calling with an empty PulseDF returns the existing
+ datarecord"""
+
+ grid = example_nmg2
+
+ make_pulse = SedimentPulserEachParcel(grid, rng=5)
+
+ PulseDF = pd.DataFrame(
+ {
+ "pulse_volume": [0.2, 1, 1.1, 0.5],
+ "link_#": [1, 3, 5, 2],
+ "normalized_downstream_distance": [0.8, 0.7, 0.5, 0.2],
+ }
+ )
+ # call SedimentPulserEachParcel using setup in normal_test_1
+ time1 = 7.0
+ parcels = make_pulse(time1, PulseDF)
+
+ # call again, using an empty PulserDF
+ time2 = 8.0
+ parcels = make_pulse(time2, pd.DataFrame([]))
+
+ assert np.all(parcels.dataset["grid_element"] == "link")
+ assert np.all(
+ parcels.dataset["element_id"] == [[1], [3], [3], [5], [5], [5], [2]]
+ )
+ assert np.all(parcels.dataset["starting_link"] == [1, 3, 3, 5, 5, 5, 2])
+ assert np.all(parcels.dataset["abrasion_rate"] == approx(0.0))
+ assert np.all(parcels.dataset["time_arrival_in_link"] == approx(time1))
+ assert np.all(parcels.dataset["active_layer"] == approx(1.0))
+ assert_allclose(
+ parcels.dataset["location_in_link"],
+ [[0.8], [0.7], [0.7], [0.5], [0.5], [0.5], [0.2]],
+ )
+ assert_allclose(
+ parcels.dataset["D"],
+ [
+ [0.0275786],
+ [0.01871699],
+ [0.04158561],
+ [0.06830391],
+ [0.11615185],
+ [0.05423998],
+ [0.03318153],
+ ],
+ )
+ assert_allclose(
+ parcels.dataset["volume"],
+ np.array([[0.2], [0.5], [0.5], [0.5], [0.5], [0.1], [0.5]]),
+ )
diff --git a/tests/components/overland_flow/test_dealmeida_overland_flow.py b/tests/components/overland_flow/test_dealmeida_overland_flow.py
index 7418c1ae27..6dd1713edc 100644
--- a/tests/components/overland_flow/test_dealmeida_overland_flow.py
+++ b/tests/components/overland_flow/test_dealmeida_overland_flow.py
@@ -5,6 +5,7 @@
"""
import numpy as np
+import pytest
from landlab import RasterModelGrid
from landlab.components.overland_flow import OverlandFlow
@@ -149,6 +150,25 @@ def test_deAlm_analytical_imposed_dt_long():
np.testing.assert_almost_equal(h_analytical, hdeAlm, decimal=1)
+@pytest.mark.parametrize("slope", (0.0, 0.1, 0.2, 0.3, 0.4, 0.5))
+def test_mass_balance(slope):
+ grid = RasterModelGrid((8, 32), xy_spacing=25.0)
+
+ grid.add_zeros("surface_water__depth", at="node")
+ grid.add_field("topographic__elevation", -slope * grid.x_of_node, at="node")
+ grid.set_closed_boundaries_at_grid_edges(True, True, True, True)
+
+ overland_flow = OverlandFlow(
+ grid, mannings_n=0.01, h_init=1e-9, rainfall_intensity=0.001, steep_slopes=True
+ )
+ overland_flow.run_one_step(900.0)
+
+ expected = (900.0 * 0.001 + 1e-9) * len(grid.core_nodes)
+ actual = grid.at_node["surface_water__depth"][grid.core_nodes].sum()
+
+ assert actual == pytest.approx(expected)
+
+
def test_deAlm_rainfall_array():
"""
Make sure that rainfall_intensity can be set with an array, and confirm
diff --git a/tests/components/overland_flow/test_kinwave_implicit.py b/tests/components/overland_flow/test_kinwave_implicit.py
index 27e189fdcc..ff88bf7309 100644
--- a/tests/components/overland_flow/test_kinwave_implicit.py
+++ b/tests/components/overland_flow/test_kinwave_implicit.py
@@ -8,6 +8,7 @@
"""
import numpy as np
+import pytest
from landlab import RasterModelGrid
from landlab.components import KinwaveImplicitOverlandFlow
@@ -31,6 +32,64 @@ def test_initialization():
kw = KinwaveImplicitOverlandFlow(rg)
+def test_zero_runoff_rate():
+ grid = RasterModelGrid((5, 5))
+ grid.add_field("topographic__elevation", 0.1 * grid.node_y, at="node")
+
+ kw = KinwaveImplicitOverlandFlow(grid, runoff_rate=0.0)
+ kw.run_one_step(1.0)
+
+ assert np.all(grid.at_node["surface_water__depth"] == 0.0)
+
+
+@pytest.mark.parametrize("var", ("runoff_rate", "roughness"))
+@pytest.mark.parametrize("bad_value", (-1.0, [-1.0] * 25))
+def test_negative_runoff_and_roughness(var, bad_value):
+ grid = RasterModelGrid((5, 5))
+ grid.add_field("topographic__elevation", 0.1 * grid.node_y, at="node")
+
+ with pytest.raises(ValueError):
+ KinwaveImplicitOverlandFlow(grid, **{var: bad_value})
+
+ kw = KinwaveImplicitOverlandFlow(grid, **{var: 1.0})
+ with pytest.raises(ValueError):
+ setattr(kw, var, bad_value)
+
+
+@pytest.mark.parametrize("var", ("runoff_rate", "roughness"))
+@pytest.mark.parametrize("value", (2.0, [2.0] * 25))
+def test_runoff_and_roughness_setter(var, value):
+ grid = RasterModelGrid((5, 5))
+ grid.add_field("topographic__elevation", 0.1 * grid.node_y, at="node")
+
+ kw = KinwaveImplicitOverlandFlow(grid, **{var: 2.0})
+ kw.run_one_step(1.0)
+ expected = grid.at_node["surface_water__depth"].copy()
+
+ grid.at_node["surface_water__depth"].fill(0.0)
+
+ kw = KinwaveImplicitOverlandFlow(grid, **{var: 1.0})
+ setattr(kw, var, value)
+ kw.run_one_step(1.0)
+
+ assert np.all(grid.at_node["surface_water__depth"] == expected)
+
+
+@pytest.mark.parametrize("var", ("runoff_rate", "roughness"))
+def test_runoff_rate_is_read_only(var):
+ grid = RasterModelGrid((5, 5))
+ grid.add_field("topographic__elevation", 0.1 * grid.node_y, at="node")
+
+ kwargs = {var: np.full(grid.number_of_nodes, 2.0)}
+ kw = KinwaveImplicitOverlandFlow(grid, **kwargs)
+ assert (
+ np.all(getattr(kw, var) == kwargs[var]) and getattr(kw, var) is not kwargs[var]
+ )
+
+ with pytest.raises(ValueError):
+ getattr(kw, var)[:] = 1.0
+
+
def test_first_iteration():
"""Test stuff that happens only on first iteration"""
@@ -89,9 +148,9 @@ def test_steady_basic_ramp():
assert round(kw._disch_in[25], 4) == 0.0024
assert round(kw._disch_in[15], 4) == 0.0028
- # Try with default runoff rate of 1 mm/hr = 2.78e-7 m/s
+ # Try with default runoff rate of 1 mm/hr
kw = KinwaveImplicitOverlandFlow(rg)
- assert round(kw.runoff_rate * 1.0e7, 2) == 2.78
+ assert kw.runoff_rate == 1.0
kw.depth[:] = 0.0
for _ in range(18):
kw.run_one_step(10.0)
@@ -133,8 +192,60 @@ def test_curved_surface():
)
-if __name__ == "__main__":
- test_initialization()
- test_first_iteration()
- test_steady_basic_ramp()
- test_curved_surface()
+def test_kinwave_runoff_array():
+ """
+ Make sure that runoff_rate can be set with an array, and confirm that this
+ returns the same result as setting with a float of the same magnitude.
+ """
+ # Set runoff_rate as float
+ mg1 = RasterModelGrid((10, 10), xy_spacing=25)
+ mg1.add_zeros("surface_water__depth", at="node")
+ mg1.add_zeros("topographic__elevation", at="node")
+ mg1.set_closed_boundaries_at_grid_edges(True, True, True, True)
+ r1 = 1.0
+ kinwave1 = KinwaveImplicitOverlandFlow(
+ mg1, runoff_rate=r1, roughness=0.03, depth_exp=5 / 3
+ )
+
+ # Set runoff_rate as array
+ mg2 = RasterModelGrid((10, 10), xy_spacing=25)
+ mg2.add_zeros("surface_water__depth", at="node")
+ mg2.add_zeros("topographic__elevation", at="node")
+ mg2.set_closed_boundaries_at_grid_edges(True, True, True, True)
+ r2 = 1.0 * np.ones(100)
+ kinwave2 = KinwaveImplicitOverlandFlow(
+ mg2, runoff_rate=r2, roughness=0.03, depth_exp=5 / 3
+ )
+
+ kinwave1.run_one_step(100)
+ kinwave2.run_one_step(100)
+ np.testing.assert_equal(kinwave1.depth, kinwave2.depth)
+
+
+def test_kinwave_roughness_array():
+ """
+ Make sure that roughness can be set with an array, and confirm that this
+ returns the same result as setting with a float of the same magnitude.
+ """
+
+ mg1 = RasterModelGrid((10, 10), xy_spacing=25)
+ mg1.add_zeros("surface_water__depth", at="node")
+ mg1.add_zeros("topographic__elevation", at="node")
+ mg1.set_closed_boundaries_at_grid_edges(True, True, True, True)
+ r1 = 0.03
+ kinwave1 = KinwaveImplicitOverlandFlow(
+ mg1, runoff_rate=1.0, roughness=r1, depth_exp=5 / 3
+ )
+
+ mg2 = RasterModelGrid((10, 10), xy_spacing=25)
+ mg2.add_zeros("surface_water__depth", at="node")
+ mg2.add_zeros("topographic__elevation", at="node")
+ mg2.set_closed_boundaries_at_grid_edges(True, True, True, True)
+ r2 = 0.03 * np.ones(100)
+ kinwave2 = KinwaveImplicitOverlandFlow(
+ mg2, runoff_rate=1.0, roughness=r2, depth_exp=5 / 3
+ )
+
+ kinwave1.run_one_step(100)
+ kinwave2.run_one_step(100)
+ np.testing.assert_equal(kinwave1.depth, kinwave2.depth)
diff --git a/tests/components/profiler/test_profiler.py b/tests/components/profiler/test_profiler.py
index fce4e774d3..0717026218 100644
--- a/tests/components/profiler/test_profiler.py
+++ b/tests/components/profiler/test_profiler.py
@@ -1,6 +1,5 @@
# ! /usr/env/python
-"""Tests for Profiler.
-"""
+"""Tests for Profiler."""
import numpy as np
import pytest
diff --git a/tests/components/river_flow_dynamics/__init__.py b/tests/components/river_flow_dynamics/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/components/river_flow_dynamics/test_river_flow_dynamics.py b/tests/components/river_flow_dynamics/test_river_flow_dynamics.py
new file mode 100644
index 0000000000..9e83e61b2a
--- /dev/null
+++ b/tests/components/river_flow_dynamics/test_river_flow_dynamics.py
@@ -0,0 +1,514 @@
+"""
+Unit tests for landlab.components.river_flow_dynamics.RiverFlowDynamics
+
+last updated: 11/11/2024
+"""
+
+import numpy as np
+import pytest
+
+from landlab import RasterModelGrid
+from landlab.components import RiverFlowDynamics
+
+
+@pytest.fixture
+def rfd():
+ grid = RasterModelGrid((10, 10), xy_spacing=0.1)
+ grid.add_zeros("topographic__elevation", at="node")
+ grid.add_zeros("surface_water__depth", at="node")
+ grid.add_zeros("surface_water__elevation", at="node")
+ grid.add_zeros("surface_water__velocity", at="link")
+ return RiverFlowDynamics(grid)
+
+
+def test_name(rfd):
+ """Test component name"""
+ print(rfd.name)
+ assert rfd.name == "RiverFlowDynamics"
+
+
+def test_input_var_names(rfd):
+ """Test input variable names"""
+ assert rfd.input_var_names == (
+ "surface_water__depth",
+ "surface_water__elevation",
+ "surface_water__velocity",
+ "topographic__elevation",
+ )
+
+
+def test_output_var_names(rfd):
+ """Test output variable names"""
+ assert rfd.output_var_names == (
+ "surface_water__depth",
+ "surface_water__elevation",
+ "surface_water__velocity",
+ )
+
+
+def test_var_units(rfd):
+ assert rfd.var_units("surface_water__depth") == "m"
+ assert rfd.var_units("surface_water__elevation") == "m"
+ assert rfd.var_units("surface_water__velocity") == "m/s"
+ assert rfd.var_units("topographic__elevation") == "m"
+
+
+def test_initialization():
+ """Test initialization with various parameters."""
+ grid = RasterModelGrid((10, 10), xy_spacing=0.1)
+ grid.add_zeros("topographic__elevation", at="node")
+ grid.add_zeros("surface_water__depth", at="node")
+ grid.add_zeros("surface_water__elevation", at="node")
+ grid.add_zeros("surface_water__velocity", at="link")
+ rfd = RiverFlowDynamics(grid)
+
+ # Making sure fields have been created
+ for field_name in rfd._info:
+ if rfd._info[field_name]["mapping"] == "node":
+ assert field_name in rfd.grid.at_node
+ elif rfd._info[field_name]["mapping"] == "link":
+ assert field_name in rfd.grid.at_link
+
+ # Re-initialize, this time with fields already existing in the grid
+ # (this triggers the "if" instead of "else" in the field setup in init)
+ rfd = RiverFlowDynamics(grid)
+
+
+def test_mass_conservation():
+ """Test that water volume is conserved in a closed system."""
+ grid = RasterModelGrid((10, 10), xy_spacing=0.1)
+ grid.add_zeros("topographic__elevation", at="node")
+ grid.add_zeros("surface_water__depth", at="node")
+ grid.add_zeros("surface_water__elevation", at="node")
+ grid.add_zeros("surface_water__velocity", at="link")
+
+ # Create a bowl-shaped topography for more interesting flow
+ x = grid.x_of_node - 0.5 # Center at 0.5
+ y = grid.y_of_node - 0.5 # Center at 0.5
+ grid.at_node["topographic__elevation"] = 0.1 * (x**2 + y**2)
+
+ # Set water surface elevation to 0.5 everywhere
+ grid.at_node["surface_water__elevation"][:] = 0.5
+
+ # Calculate water depth as difference between surface elevation and topography
+ topo = grid.at_node["topographic__elevation"]
+ water_surface = grid.at_node["surface_water__elevation"]
+ grid.at_node["surface_water__depth"] = np.maximum(water_surface - topo, 0.0)
+
+ # Set up model with closed boundaries to ensure mass conservation
+ rfd = RiverFlowDynamics(grid)
+
+ # Calculate initial volume
+ initial_volume = np.sum(grid.at_node["surface_water__depth"]) * grid.dx * grid.dy
+
+ # Run model for several time steps
+ n_steps = 100
+ volumes = np.zeros(n_steps + 1)
+ volumes[0] = initial_volume
+
+ for i in range(n_steps):
+ rfd.run_one_step()
+ volumes[i + 1] = (
+ np.sum(grid.at_node["surface_water__depth"]) * grid.dx * grid.dy
+ )
+
+ # Calculate volume change
+ volume_changes = np.abs(volumes - initial_volume) / initial_volume
+ max_volume_change = np.max(volume_changes)
+
+ # Assert volume is conserved within a more realistic tolerance (0.1%)
+ assert max_volume_change < 1e-3
+
+ # Check for physically reasonable results
+ depths = grid.at_node["surface_water__depth"]
+ initial_max_depth = np.max(grid.at_node["surface_water__depth"])
+ assert np.all(depths >= 0)
+ assert np.max(depths) < initial_max_depth * 1.001
+
+
+def test_open_boundaries():
+ """Test that water properly exits through open boundaries."""
+ grid = RasterModelGrid((10, 10), xy_spacing=0.1)
+ grid.add_zeros("topographic__elevation", at="node")
+ grid.add_zeros("surface_water__depth", at="node")
+ grid.add_zeros("surface_water__elevation", at="node")
+ grid.add_zeros("surface_water__velocity", at="link")
+
+ # Sloped channel
+ grid.at_node["topographic__elevation"] = grid.x_of_node * 0.05
+
+ # Set up inflow conditions
+ fixed_entry_nodes = grid.nodes_at_left_edge
+ fixed_entry_links = grid.links_at_node[fixed_entry_nodes][:, 0]
+ entry_nodes_h_values = 0.5 * np.ones_like(fixed_entry_nodes)
+ entry_links_vel_values = 0.3 * np.ones_like(fixed_entry_links)
+
+ rfd = RiverFlowDynamics(
+ grid,
+ fixed_entry_nodes=fixed_entry_nodes,
+ fixed_entry_links=fixed_entry_links,
+ entry_nodes_h_values=entry_nodes_h_values,
+ entry_links_vel_values=entry_links_vel_values,
+ )
+
+ # Run to steady state
+ for _ in range(200):
+ rfd.run_one_step()
+
+ # Check that water exits smoothly (no backing up at boundary)
+ right_depths = grid.at_node["surface_water__depth"][grid.nodes_at_right_edge]
+ near_right_depths = grid.at_node["surface_water__depth"][
+ grid.nodes_at_right_edge - 1
+ ]
+
+ # Water depth should decrease or stay similar near boundary
+ assert np.all(right_depths <= near_right_depths * 1.1)
+
+
+def test_still_water():
+ """Test that still water stays still."""
+ grid = RasterModelGrid((10, 10), xy_spacing=0.1)
+ grid.add_zeros("topographic__elevation", at="node")
+ grid.add_zeros("surface_water__depth", at="node")
+ grid.add_zeros("surface_water__elevation", at="node")
+ grid.add_zeros("surface_water__velocity", at="link")
+
+ # Flat bottom with uniform water depth
+ grid.at_node["surface_water__depth"][:] = 0.5
+ grid.at_node["surface_water__elevation"][:] = 0.5
+
+ rfd = RiverFlowDynamics(grid)
+
+ # Initial conditions
+ initial_volume = np.sum(grid.at_node["surface_water__depth"]) * grid.dx * grid.dy
+
+ # Run model
+ rfd.run_one_step()
+
+ # Check volume conservation
+ final_volume = np.sum(grid.at_node["surface_water__depth"]) * grid.dx * grid.dy
+ volume_change = abs(final_volume - initial_volume) / initial_volume
+ assert volume_change < 1e-4 # Allow 0.01% volume change
+
+ # Check surface stays flat (no gradients)
+ depth_gradients = np.abs(
+ np.diff(grid.at_node["surface_water__depth"].reshape(10, 10), axis=1)
+ )
+ assert np.all(depth_gradients < 1e-4) # Maximum gradient of 0.1 mm per cell
+
+
+def test_run_one_step():
+ grid = RasterModelGrid((10, 10), xy_spacing=0.1)
+ grid.add_zeros("topographic__elevation", at="node")
+ grid.add_zeros("surface_water__depth", at="node")
+ grid.add_zeros("surface_water__elevation", at="node")
+ grid.add_zeros("surface_water__velocity", at="link")
+
+ # We set fixed boundary conditions, specifying the nodes and links in which
+ # the water is flowing into the grid
+ fixed_entry_nodes = grid.nodes_at_left_edge
+ fixed_entry_links = grid.links_at_node[fixed_entry_nodes][:, 0]
+
+ # We set the fixed values in the entry nodes/links
+ entry_nodes_h_values = 0.5 * np.ones_like(fixed_entry_nodes)
+ entry_links_vel_values = 0.5 * np.ones_like(fixed_entry_links)
+
+ # We specify the time step duration and we run it
+ dt = 0.1
+ rfd = RiverFlowDynamics(
+ grid,
+ dt=dt,
+ fixed_entry_nodes=fixed_entry_nodes,
+ fixed_entry_links=fixed_entry_links,
+ entry_nodes_h_values=entry_nodes_h_values,
+ entry_links_vel_values=entry_links_vel_values,
+ )
+
+ for _ in range(100):
+ rfd.run_one_step()
+
+ water_depth_solution = np.round(
+ np.array(
+ [
+ 0.4357753,
+ 0.4357753,
+ 0.43611027,
+ 0.43624251,
+ 0.43626605,
+ 0.43595278,
+ 0.43534349,
+ 0.43491662,
+ 0.43342158,
+ 0.43342158,
+ ]
+ ),
+ 3,
+ )
+ water_depth_obtained = grid.at_node["surface_water__depth"][
+ grid.nodes_at_right_edge
+ ]
+
+ water_depth_obtained = np.round(water_depth_obtained, 3)
+ np.testing.assert_array_almost_equal(
+ water_depth_solution, water_depth_obtained, decimal=3
+ )
+
+
+def test_downhill_flow():
+ """Test that water flows downhill."""
+ grid = RasterModelGrid((10, 10), xy_spacing=0.1)
+ grid.add_zeros("topographic__elevation", at="node")
+ grid.add_zeros("surface_water__depth", at="node")
+ grid.add_zeros("surface_water__elevation", at="node")
+ grid.add_zeros("surface_water__velocity", at="link")
+
+ # Create sloped surface
+ grid.at_node["topographic__elevation"] = grid.x_of_node * 0.1
+
+ # Set water surface elevation at upstream end
+ upstream_water_level = 0.5
+ grid.at_node["surface_water__elevation"][
+ grid.nodes_at_left_edge
+ ] = upstream_water_level
+
+ # Calculate initial water depth at upstream end
+ upstream_topo = grid.at_node["topographic__elevation"][grid.nodes_at_left_edge]
+ grid.at_node["surface_water__depth"][grid.nodes_at_left_edge] = (
+ upstream_water_level - upstream_topo
+ )
+
+ # Set up inflow conditions
+ fixed_entry_nodes = grid.nodes_at_left_edge
+ fixed_entry_links = grid.links_at_node[fixed_entry_nodes][:, 0]
+ entry_links_vel_values = 0.3 * np.ones_like(fixed_entry_links)
+
+ rfd = RiverFlowDynamics(
+ grid,
+ fixed_entry_nodes=fixed_entry_nodes,
+ fixed_entry_links=fixed_entry_links,
+ entry_nodes_h_values=grid.at_node["surface_water__depth"][fixed_entry_nodes],
+ entry_links_vel_values=entry_links_vel_values,
+ )
+
+ # Run model
+ for _ in range(50):
+ rfd.run_one_step()
+
+ # Check mean flow direction
+ horizontal_links = grid.horizontal_links
+ mean_velocity = np.mean(grid.at_link["surface_water__velocity"][horizontal_links])
+ assert mean_velocity > 0 # Overall flow should be positive (downhill)
+
+ # Check water depths are physically reasonable
+ assert np.all(grid.at_node["surface_water__depth"] >= 0)
+
+ # Check water surface elevation is consistent with depth and topography
+ # but allow for small numerical differences
+ calculated_elevation = (
+ grid.at_node["surface_water__depth"] + grid.at_node["topographic__elevation"]
+ )
+ elevation_difference = np.abs(
+ grid.at_node["surface_water__elevation"] - calculated_elevation
+ )
+ assert np.max(elevation_difference) < 0.1 # Allow differences up to 10cm
+
+ # Check that water has moved downstream
+ outlet_depths = grid.at_node["surface_water__depth"][grid.nodes_at_right_edge]
+ assert np.any(outlet_depths > 0.01)
+
+
+def test_time_step_sensitivity():
+ """Test that results are not heavily dependent on time step choice for
+ relatively similar systems."""
+ grid1 = RasterModelGrid((10, 10), xy_spacing=0.1)
+ grid2 = RasterModelGrid((10, 10), xy_spacing=0.1)
+
+ # Set up identical grids
+ for grid in [grid1, grid2]:
+ grid.add_zeros("topographic__elevation", at="node")
+ grid.add_zeros("surface_water__depth", at="node")
+ grid.add_zeros("surface_water__elevation", at="node")
+ grid.add_zeros("surface_water__velocity", at="link")
+
+ # Create a sloped surface
+ grid.at_node["topographic__elevation"] = grid.x_of_node * 0.1
+
+ # Set the water surface elevation
+ water_level = 0.5
+ grid.at_node["surface_water__elevation"][grid.nodes_at_left_edge] = water_level
+
+ # Calculate initial water depth
+ topo = grid.at_node["topographic__elevation"][grid.nodes_at_left_edge]
+ grid.at_node["surface_water__depth"][grid.nodes_at_left_edge] = (
+ water_level - topo
+ )
+
+ # Set up identical boundary conditions for both grids
+ fixed_entry_nodes = grid1.nodes_at_left_edge
+ fixed_entry_links = grid1.links_at_node[fixed_entry_nodes][:, 0]
+ entry_nodes_h_values = grid1.at_node["surface_water__depth"][fixed_entry_nodes]
+ entry_links_vel_values = 0.3 * np.ones_like(fixed_entry_links)
+
+ # Create two models with different time steps
+ rfd1 = RiverFlowDynamics(
+ grid1,
+ dt=0.1,
+ fixed_entry_nodes=fixed_entry_nodes,
+ fixed_entry_links=fixed_entry_links,
+ entry_nodes_h_values=entry_nodes_h_values,
+ entry_links_vel_values=entry_links_vel_values,
+ )
+
+ rfd2 = RiverFlowDynamics(
+ grid2,
+ dt=0.05,
+ fixed_entry_nodes=fixed_entry_nodes,
+ fixed_entry_links=fixed_entry_links,
+ entry_nodes_h_values=entry_nodes_h_values,
+ entry_links_vel_values=entry_links_vel_values,
+ )
+
+ # Run to same total time
+ for _ in range(100):
+ rfd1.run_one_step()
+ for _ in range(200):
+ rfd2.run_one_step()
+
+ # Compare results with reasonable tolerances
+ depth_difference = np.abs(
+ grid1.at_node["surface_water__depth"] - grid2.at_node["surface_water__depth"]
+ )
+ assert np.max(depth_difference) < 0.1 # Max difference in depths
+
+ # Check both solutions maintain physical consistency
+ for grid in [grid1, grid2]:
+ # Water depth should be non-negative
+ assert np.all(grid.at_node["surface_water__depth"] >= 0)
+
+ # Check water surface elevation consistency
+ calculated_elevation = (
+ grid.at_node["surface_water__depth"]
+ + grid.at_node["topographic__elevation"]
+ )
+ elevation_difference = np.abs(
+ grid.at_node["surface_water__elevation"] - calculated_elevation
+ )
+ assert np.max(elevation_difference) < 0.1
+
+ # Check water has propagated downstream
+ outlet_depths = grid.at_node["surface_water__depth"][grid.nodes_at_right_edge]
+ assert np.any(outlet_depths > 0.01)
+
+
+def test_numerical_stability():
+ """Test numerical stability under various conditions."""
+
+ def create_test_grid():
+ """Helper function to create a grid with initial conditions."""
+ grid = RasterModelGrid((10, 10), xy_spacing=0.1)
+ grid.add_zeros("topographic__elevation", at="node")
+ grid.add_zeros("surface_water__depth", at="node")
+ grid.add_zeros("surface_water__elevation", at="node")
+ grid.add_zeros("surface_water__velocity", at="link")
+
+ # Create challenging conditions
+ grid.at_node["topographic__elevation"] = grid.x_of_node * 0.1
+
+ # Set initial conditions
+ grid.at_node["surface_water__depth"][:] = 0.5
+ grid.at_node["surface_water__elevation"] = (
+ grid.at_node["surface_water__depth"]
+ + grid.at_node["topographic__elevation"]
+ )
+
+ return grid
+
+ time_steps = [0.1, 0.05, 0.01]
+ max_velocities = []
+ final_depths = []
+
+ for dt in time_steps:
+ grid_test = create_test_grid()
+ rfd = RiverFlowDynamics(grid_test, dt=dt)
+
+ try:
+ for _ in range(int(5.0 / dt)):
+ rfd.run_one_step()
+
+ assert np.all(np.isfinite(grid_test.at_node["surface_water__depth"]))
+ assert np.all(grid_test.at_node["surface_water__depth"] >= 0)
+ assert np.all(np.isfinite(grid_test.at_link["surface_water__velocity"]))
+
+ max_velocities.append(
+ np.max(np.abs(grid_test.at_link["surface_water__velocity"]))
+ )
+ final_depths.append(grid_test.at_node["surface_water__depth"].copy())
+
+ except AssertionError as err:
+ raise AssertionError(f"Instability detected with dt={dt}") from err
+
+ depth_variations = [
+ np.max(np.abs(d1 - d2)) for d1, d2 in zip(final_depths[:-1], final_depths[1:])
+ ]
+ assert np.all(np.array(depth_variations) < 0.1)
+ assert np.all(np.array(max_velocities) < 10.0)
+
+ depth_variations = [
+ np.max(np.abs(d1 - d2)) for d1, d2 in zip(final_depths[:-1], final_depths[1:])
+ ]
+ assert np.all(np.array(depth_variations) < 0.1)
+ assert np.all(np.array(max_velocities) < 1.0)
+
+
+def test_analytical_solution():
+ """Test numerical and analytical solutions."""
+
+ # Creating a grid
+ grid = RasterModelGrid((6, 6), xy_spacing=0.1)
+ grid.add_zeros("topographic__elevation", at="node")
+ grid.add_zeros("surface_water__depth", at="node")
+ grid.add_zeros("surface_water__elevation", at="node")
+ grid.add_zeros("surface_water__velocity", at="link")
+
+ # We set fixed boundary conditions, specifying the nodes and links in which
+ # the water is flowing into the grid
+ fixed_entry_nodes = grid.nodes_at_left_edge
+ fixed_entry_links = grid.links_at_node[fixed_entry_nodes][:, 0]
+
+ # We set the fixed values in the entry nodes/links
+ entry_nodes_h_values = 0.5 * np.ones_like(fixed_entry_nodes)
+ # entry_nodes_h_values = np.repeat(0.5, 6)
+ entry_links_vel_values = 0.6 * np.ones_like(fixed_entry_links)
+ # entry_links_vel_values = np.repeat(0.6, 6)
+
+ # We specify the time step duration and we run it
+ dt = 0.1
+ rfd = RiverFlowDynamics(
+ grid,
+ dt=dt,
+ mannings_n=0.0010,
+ fixed_entry_nodes=fixed_entry_nodes,
+ fixed_entry_links=fixed_entry_links,
+ entry_nodes_h_values=entry_nodes_h_values,
+ entry_links_vel_values=entry_links_vel_values,
+ )
+
+ for _ in range(300):
+ rfd.run_one_step()
+
+ # Comparing the uniform outlet with the obtained water depth
+ water_depth_solution = 0.5 * np.ones_like(fixed_entry_nodes)
+ water_depth_obtained = grid.at_node["surface_water__depth"][
+ grid.nodes_at_right_edge
+ ]
+
+ water_depth_difference = np.abs(water_depth_solution - water_depth_obtained)
+ assert np.max(water_depth_difference) < 0.001 # Max difference in vel
+
+ vel_solution = 0.6 * np.ones_like(fixed_entry_links)[1:5]
+ vel_obtained = grid.at_link["surface_water__velocity"][
+ grid.links_at_node[grid.nodes_at_right_edge][:, 2]
+ ][1:5]
+ vel_difference = np.abs(vel_solution - vel_obtained)
+
+ assert np.max(vel_difference) < 0.01 # Max difference in vel
diff --git a/tests/components/space/test_space_large_scale_eroder.py b/tests/components/space/test_space_large_scale_eroder.py
index 6d7f889721..13a7a50379 100644
--- a/tests/components/space/test_space_large_scale_eroder.py
+++ b/tests/components/space/test_space_large_scale_eroder.py
@@ -705,6 +705,7 @@ def test_can_run_with_hex():
z[mg.core_nodes] += U * dt
+@pytest.mark.richdem
@pytest.mark.skipif(not with_richdem, reason="richdem is not installed")
def test_matches_detachment_solution_PF():
# %%
@@ -790,6 +791,7 @@ def test_matches_detachment_solution_PF():
# %%
@pytest.mark.slow
+@pytest.mark.richdem
@pytest.mark.skipif(not with_richdem, reason="richdem is not installed")
def test_matches_transport_solution_PF():
"""
@@ -906,6 +908,7 @@ def test_matches_transport_solution_PF():
# %%
@pytest.mark.slow
+@pytest.mark.richdem
@pytest.mark.skipif(not with_richdem, reason="richdem is not installed")
def test_matches_bedrock_alluvial_solution_PF():
"""
@@ -1020,6 +1023,7 @@ def test_matches_bedrock_alluvial_solution_PF():
# %%
@pytest.mark.slow
+@pytest.mark.richdem
@pytest.mark.skipif(not with_richdem, reason="richdem is not installed")
def test_matches_bedrock_alluvial_solution_PF_extended_range():
"""
@@ -1129,6 +1133,7 @@ def test_matches_bedrock_alluvial_solution_PF_extended_range():
# %%
@pytest.mark.slow
+@pytest.mark.richdem
@pytest.mark.skipif(not with_richdem, reason="richdem is not installed")
def test_matches_bedrock_alluvial_solution_PF_high_v_high_hstar():
"""
diff --git a/tests/components/test_components.py b/tests/components/test_components.py
index c1316647b6..826540a2cd 100644
--- a/tests/components/test_components.py
+++ b/tests/components/test_components.py
@@ -28,6 +28,7 @@
"BedParcelInitializerUserD50",
"SedimentPulserEachParcel",
"SedimentPulserAtLinks",
+ "ConcentrationTrackerForSpace",
}
diff --git a/tests/components/threshold_eroder/test_threshold_eroder.py b/tests/components/threshold_eroder/test_threshold_eroder.py
index d06683a2f4..ce57a4d662 100644
--- a/tests/components/threshold_eroder/test_threshold_eroder.py
+++ b/tests/components/threshold_eroder/test_threshold_eroder.py
@@ -19,6 +19,7 @@
with_richdem = True
+@pytest.mark.richdem
@pytest.mark.skipif(not with_richdem, reason="richdem is not installed")
def test_topography_rasterGrid():
# %%
@@ -51,6 +52,7 @@ def test_topography_rasterGrid():
)
+@pytest.mark.richdem
@pytest.mark.skipif(not with_richdem, reason="richdem is not installed")
def test_topo_soil_rasterGrid():
# %%
diff --git a/tests/conftest.py b/tests/conftest.py
index 4215680a17..bebb558f28 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -2,5 +2,5 @@
from hypothesis import settings
-settings.register_profile("ci", deadline=None)
+settings.register_profile("ci", deadline=None, max_examples=10)
settings.load_profile(os.getenv("HYPOTHESIS_PROFILE", "default"))
diff --git a/tests/data_record/test_aggregators.py b/tests/data_record/test_aggregators.py
index ea611a44b5..234c7e0605 100644
--- a/tests/data_record/test_aggregators.py
+++ b/tests/data_record/test_aggregators.py
@@ -16,58 +16,56 @@
from landlab.data_record.aggregators import aggregate_items_as_sum
-def test_count_bench_cython(benchmark):
+def test_count_bench_cython():
n_links = 1000
n_parcels = 100000
out = np.empty(n_links, dtype=int)
link_of_parcel = np.zeros(n_parcels, dtype=int)
- benchmark(_aggregate_items_as_count, out, link_of_parcel)
+ _aggregate_items_as_count(out, link_of_parcel)
assert_array_equal(out[0], 100000)
assert_array_equal(out[1:], 0)
@pytest.mark.slow
-def test_count_bench(benchmark):
+def test_count_bench():
n_links = 1000
n_parcels = 100000
link_of_parcel = np.zeros(n_parcels, dtype=int)
- out = benchmark(aggregate_items_as_count, link_of_parcel, size=n_links)
+ out = aggregate_items_as_count(link_of_parcel, size=n_links)
assert_array_equal(out[0], 100000)
assert_array_equal(out[1:], 0)
-def test_sum_bench_cython(benchmark):
+def test_sum_bench_cython():
n_links = 1000
n_parcels = 100000
out = np.empty(n_links, dtype=float)
value_of_parcel = np.ones(n_parcels, dtype=float)
link_of_parcel = np.zeros(n_parcels, dtype=int)
- benchmark(_aggregate_items_as_sum, out, link_of_parcel, value_of_parcel)
+ _aggregate_items_as_sum(out, link_of_parcel, value_of_parcel)
assert_array_equal(out[0], 100000.0)
assert_array_equal(out[1:], 0.0)
-def test_sum_bench(benchmark):
+def test_sum_bench():
n_links = 1000
n_parcels = 100000
value_of_parcel = np.ones(n_parcels, dtype=float)
link_of_parcel = np.zeros(n_parcels, dtype=int)
- out = benchmark(
- aggregate_items_as_sum, link_of_parcel, value_of_parcel, size=n_links
- )
+ out = aggregate_items_as_sum(link_of_parcel, value_of_parcel, size=n_links)
assert_array_equal(out[0], 100000.0)
assert_array_equal(out[1:], 0.0)
-def test_mean_bench_cython(benchmark):
+def test_mean_bench_cython():
n_links = 100
n_parcels = 100000
out = np.empty(n_links, dtype=float)
@@ -75,23 +73,20 @@ def test_mean_bench_cython(benchmark):
weight_of_parcel = np.ones(n_parcels, dtype=float)
link_of_parcel = np.zeros(n_parcels, dtype=int)
- benchmark(
- _aggregate_items_as_mean, out, link_of_parcel, value_of_parcel, weight_of_parcel
- )
+ _aggregate_items_as_mean(out, link_of_parcel, value_of_parcel, weight_of_parcel)
assert_array_equal(out[0], 1.0)
assert_array_equal(out[1:], 0.0)
-def test_mean_bench(benchmark):
+def test_mean_bench():
n_links = 100
n_parcels = 100000
value_of_parcel = np.ones(n_parcels, dtype=float)
weight_of_parcel = np.ones(n_parcels, dtype=float)
link_of_parcel = np.zeros(n_parcels, dtype=int)
- out = benchmark(
- aggregate_items_as_mean,
+ out = aggregate_items_as_mean(
link_of_parcel,
value_of_parcel,
weights=weight_of_parcel,
diff --git a/tests/graph/framed_voronoi/test_framed_voronoi.py b/tests/graph/framed_voronoi/test_framed_voronoi.py
index b85a9c8f95..6d843e430f 100644
--- a/tests/graph/framed_voronoi/test_framed_voronoi.py
+++ b/tests/graph/framed_voronoi/test_framed_voronoi.py
@@ -125,7 +125,7 @@ def test_rect_patches_at_node():
)
-@pytest.mark.parametrize("n_cols", [(3)])
+@pytest.mark.parametrize("n_cols", [3])
@pytest.mark.parametrize("n_rows", (1, 3))
def test_xy_of_node_rect_horizontal(n_rows, n_cols):
expected = {
diff --git a/tests/graph/quantity/test_of_element.py b/tests/graph/quantity/test_of_element.py
index dec63ff6b2..48a58daf19 100644
--- a/tests/graph/quantity/test_of_element.py
+++ b/tests/graph/quantity/test_of_element.py
@@ -51,8 +51,7 @@ def numpy_diff(children_at_parent, value_at_parent, value_at_child, out):
@pytest.mark.parametrize("impl", ["numpy", "cython"])
-@pytest.mark.benchmark(group="diff")
-def test_diff_of_elements_bench(benchmark, impl):
+def test_diff_of_elements_bench(impl):
rng = np.random.default_rng(seed=1973)
elements_at_element = rng.integers(-1, 1000, size=(10000, 10))
@@ -65,9 +64,7 @@ def test_diff_of_elements_bench(benchmark, impl):
else:
func = diff_of_children_at_parent
- benchmark(
- func, np.asarray(elements_at_element), value_at_parent, value_at_child, actual
- )
+ func(np.asarray(elements_at_element), value_at_parent, value_at_child, actual)
expected = np.full_like(actual, -999)
numpy_diff(
@@ -131,8 +128,7 @@ def test_max_of_elements():
@pytest.mark.parametrize("impl", ["numpy", "cython"])
-@pytest.mark.benchmark(group="min")
-def test_min_of_elements_bench(benchmark, impl):
+def test_min_of_elements_bench(impl):
rng = np.random.default_rng(seed=1973)
elements_at_element = rng.integers(-1, 1000, size=(10000, 10))
@@ -144,7 +140,7 @@ def test_min_of_elements_bench(benchmark, impl):
else:
func = min_of_children_at_parent
- benchmark(func, np.asarray(elements_at_element), values, actual)
+ func(np.asarray(elements_at_element), values, actual)
expected = np.full_like(actual, -999)
numpy_min(np.asarray(elements_at_element), values, expected)
@@ -153,8 +149,7 @@ def test_min_of_elements_bench(benchmark, impl):
@pytest.mark.parametrize("impl", ["numpy", "cython"])
-@pytest.mark.benchmark(group="max")
-def test_max_of_elements_bench(benchmark, impl):
+def test_max_of_elements_bench(impl):
rng = np.random.default_rng(seed=1973)
elements_at_element = rng.integers(-1, 1000, size=(10000, 10))
@@ -166,7 +161,7 @@ def test_max_of_elements_bench(benchmark, impl):
else:
func = max_of_children_at_parent
- benchmark(func, np.asarray(elements_at_element), values, actual)
+ func(np.asarray(elements_at_element), values, actual)
expected = np.full_like(actual, -999)
numpy_max(np.asarray(elements_at_element), values, expected)
@@ -175,8 +170,7 @@ def test_max_of_elements_bench(benchmark, impl):
@pytest.mark.parametrize("impl", ["numpy", "cython"])
-@pytest.mark.benchmark(group="mean")
-def test_mean_of_elements_bench(benchmark, impl):
+def test_mean_of_elements_bench(impl):
rng = np.random.default_rng(seed=1973)
elements_at_element = rng.integers(-1, 1000, size=(10000, 10))
@@ -188,7 +182,7 @@ def test_mean_of_elements_bench(benchmark, impl):
else:
func = mean_of_children_at_parent
- benchmark(func, np.asarray(elements_at_element), values, actual)
+ func(np.asarray(elements_at_element), values, actual)
expected = np.empty_like(actual)
numpy_mean(np.asarray(elements_at_element), values, expected)
@@ -226,7 +220,7 @@ def test_count_of_elements_with_missing():
@pytest.mark.parametrize("impl", ["numpy", "cython"])
-def test_count_of_elements_benchmark(benchmark, impl):
+def test_count_of_elements_benchmark(impl):
elements_at_element = np.random.randint(-1, 2, size=10000).reshape((1000, 10))
actual = np.empty(len(elements_at_element), dtype=int)
@@ -235,7 +229,7 @@ def test_count_of_elements_benchmark(benchmark, impl):
else:
func = count_of_children_at_parent
- benchmark(func, elements_at_element, actual)
+ func(elements_at_element, actual)
expected = np.sum(elements_at_element != -1, axis=1)
diff --git a/tests/graph/structured_quad/test_quad.py b/tests/graph/structured_quad/test_quad.py
index 87bbb60867..2744ec1d72 100644
--- a/tests/graph/structured_quad/test_quad.py
+++ b/tests/graph/structured_quad/test_quad.py
@@ -132,45 +132,6 @@ def test_layouts_match(method):
)
-@mark.skip("speed tests")
-@mark.parametrize(
- "method",
- (
- "links_at_patch",
- "nodes_at_link",
- "horizontal_links",
- "vertical_links",
- "perimeter_nodes",
- "links_at_node",
- "patches_at_link",
- "link_dirs_at_node",
- "patches_at_node",
- ),
-)
-@mark.parametrize("size", (10, 11))
-def test_layouts_cython_is_faster(method, size):
- from timeit import timeit
-
- n_rows, n_cols = 3 * 2**size, 4 * 2**size
-
- def time_method(impl):
- return timeit(
- "{impl}.{method}(({n_rows}, {n_cols}))".format(
- impl=impl, method=method, n_rows=n_rows, n_cols=n_cols
- ),
- setup="from landlab.graph.structured_quad.structured_quad import {impl}".format(
- impl=impl
- ),
- number=1,
- )
-
- benchmark = time_method("StructuredQuadLayoutPython")
- time = time_method("StructuredQuadLayoutCython")
- speedup = benchmark / time
-
- assert speedup > 1 # or time < 1e-2
-
-
def test_create():
"""Test creating a quad graph."""
y = [0, 1, 3, 0, 1, 3, 0, 1, 3]
diff --git a/tests/grid/test_create/4_x_3_no_nodata_value.asc b/tests/grid/test_create/4_x_3_no_nodata_value.asc
index ab2a1e5c6f..ac67dd29dd 100644
--- a/tests/grid/test_create/4_x_3_no_nodata_value.asc
+++ b/tests/grid/test_create/4_x_3_no_nodata_value.asc
@@ -1,9 +1,9 @@
-ncols 3
-nrows 4
-xllcorner 1.
-yllcorner 2.
-cellsize 10.
-0. 1. 2.
-3. 4. 5.
-6. 7. 8.
-9. 10. 11.
+ncols 3
+nrows 4
+xllcorner 1.
+yllcorner 2.
+cellsize 10.
+0. 1. 2.
+3. 4. 5.
+6. 7. 8.
+9. 10. 11.
diff --git a/tests/grid/test_create/bad_boundary.yaml b/tests/grid/test_create/bad_boundary.yaml
index 50980da6f6..f34e7a8191 100644
--- a/tests/grid/test_create/bad_boundary.yaml
+++ b/tests/grid/test_create/bad_boundary.yaml
@@ -1,13 +1,13 @@
-grid:
- RasterModelGrid:
- - [4, 5]
- - xy_spacing: [3, 4]
- - fields:
- node:
- topographic__elevation:
- plane:
- - point: [1, 1, 1]
- normal: [-2, -1, 1]
- - boundary_conditions:
- - this_is_not_a_method:
- - [True, True, True, True]
+grid:
+ RasterModelGrid:
+ - [4, 5]
+ - xy_spacing: [3, 4]
+ - fields:
+ node:
+ topographic__elevation:
+ plane:
+ - point: [1, 1, 1]
+ normal: [-2, -1, 1]
+ - boundary_conditions:
+ - this_is_not_a_method:
+ - [True, True, True, True]
diff --git a/tests/grid/test_create_network.py b/tests/grid/test_create_network.py
index a777fc7891..4aa2e7190c 100644
--- a/tests/grid/test_create_network.py
+++ b/tests/grid/test_create_network.py
@@ -98,7 +98,15 @@ def test_channel_segment_add_upstream_node():
assert upstream.downstream is segment
-@given(segments=lists(lists(integers(), min_size=2, max_size=1024), min_size=1))
+@given(segment=lists(integers(), min_size=2, max_size=1024))
+def test_channel_one_segment(segment):
+ root = ChannelSegment(segment)
+
+ assert root.count_segments(direction="upstream") == 0
+ assert root.count_segments(direction="downstream") == 0
+
+
+@given(segments=lists(lists(integers(), min_size=2, max_size=1024), min_size=2))
def test_channel_segment_many_upstream(segments):
segments = [ChannelSegment(segment) for segment in segments]
root = segments[0]
@@ -109,7 +117,7 @@ def test_channel_segment_many_upstream(segments):
assert root.count_segments(direction="downstream") == 0
-@given(segments=lists(lists(integers(), min_size=2, max_size=1024), min_size=1))
+@given(segments=lists(lists(integers(), min_size=2, max_size=1024), min_size=2))
def test_channel_segment_many_flat_upstream(segments):
segments = [ChannelSegment(segment) for segment in segments]
root = segments[0]
@@ -122,7 +130,7 @@ def test_channel_segment_many_flat_upstream(segments):
assert root.count_segments(direction="downstream") == 0
-@given(segments=lists(lists(integers(), min_size=2, max_size=1024), min_size=1))
+@given(segments=lists(lists(integers(), min_size=2, max_size=1024), min_size=2))
def test_channel_segment_many_downstream(segments):
segments = [ChannelSegment(segment) for segment in segments]
root = segments[0]
@@ -473,8 +481,9 @@ def test_reduce_to_fewest_nodes_stay_the_same(x, spacing):
def test_reduce_nodes_min_max_spacing(spacing):
distance_along_segment = np.cumsum(spacing)
- if np.any(np.diff(distance_along_segment) <= 0):
- raise ValueError(f"array not sorted ({distance_along_segment})")
+ assert np.all(
+ np.diff(distance_along_segment) > 0
+ ), f"array not sorted ({distance_along_segment})"
nodes = _reduce_nodes(distance_along_segment, spacing=spacing.min())
assert np.all(nodes == np.arange(len(spacing)))
@@ -496,8 +505,9 @@ def test_reduce_nodes_min_max_spacing(spacing):
def test_reduce_to_fewest_nodes_min_max_spacing(spacing):
distance_along_segment = np.cumsum(spacing)
- if np.any(np.diff(distance_along_segment) <= 0):
- raise ValueError(f"array not sorted ({distance_along_segment})")
+ assert np.all(
+ np.diff(distance_along_segment) > 0
+ ), f"array not sorted ({distance_along_segment})"
xy_of_node = list(zip(distance_along_segment, [0.0] * len(distance_along_segment)))
min_spacing = np.diff(distance_along_segment).min()
diff --git a/tests/grid/test_raster_divergence.py b/tests/grid/test_raster_divergence.py
index 94773f2bf2..50a08d55eb 100644
--- a/tests/grid/test_raster_divergence.py
+++ b/tests/grid/test_raster_divergence.py
@@ -3,9 +3,6 @@
from numpy.testing import assert_array_almost_equal
from landlab import RasterModelGrid
-from landlab.grid.divergence import (
- _calc_net_face_flux_at_cell as calc_net_face_flux_at_cell_slow,
-)
from landlab.grid.divergence import calc_flux_div_at_node as calc_flux_div_at_node_slow
from landlab.grid.raster_divergence import calc_flux_div_at_node
from landlab.grid.raster_divergence import calc_net_face_flux_at_cell
@@ -32,52 +29,6 @@ def test_calc_net_face_flux_at_cell():
assert_array_almost_equal(out, expected)
-@pytest.mark.benchmark(group="large")
-def test_net_face_flux_at_cell_bench(benchmark):
- grid = RasterModelGrid((400, 5000), xy_spacing=(1.0, 2.0))
-
- value_at_face = np.random.uniform(size=grid.number_of_faces)
- actual = grid.empty(at="node")
-
- benchmark(calc_net_face_flux_at_cell, grid, value_at_face, out=actual)
-
-
-@pytest.mark.benchmark(group="large")
-def test_net_face_flux_at_cell_slow_bench(benchmark):
- grid = RasterModelGrid((400, 5000), xy_spacing=(1.0, 2.0))
-
- value_at_face = np.random.uniform(size=grid.number_of_faces)
- actual = grid.empty(at="node")
-
- benchmark(calc_net_face_flux_at_cell_slow, grid, value_at_face, out=actual)
-
-
-@pytest.mark.benchmark(group="small")
-def test_flux_div_at_node_bench(benchmark):
- grid = RasterModelGrid((40, 50), xy_spacing=(1.0, 2.0))
-
- value_at_link = np.random.uniform(size=grid.number_of_links)
- actual = grid.empty(at="node")
-
- benchmark(calc_flux_div_at_node, grid, value_at_link, out=actual)
-
-
-@pytest.mark.slow
-@pytest.mark.benchmark(group="large")
-@pytest.mark.parametrize(
- "func",
- [calc_flux_div_at_node, calc_flux_div_at_node_slow],
- ids=["raster-specific", "general"],
-)
-def test_flux_div_at_node_large_bench(benchmark, func):
- grid = RasterModelGrid((400, 5000), xy_spacing=(1.0, 2.0))
-
- value_at_link = np.random.uniform(size=grid.number_of_links)
- actual = grid.empty(at="node")
-
- benchmark(func, grid, value_at_link, out=actual)
-
-
@pytest.mark.parametrize("shape", [(4, 5), (40, 50), (50, 40), (3, 3)])
@pytest.mark.parametrize("spacing", [(1.0, 3.0), (3.0, 1.0)])
def test_flux_div_at_node_matches(shape, spacing):
diff --git a/tests/grid/test_raster_gradients.py b/tests/grid/test_raster_gradients.py
index c0f301a57a..9e914aeab3 100644
--- a/tests/grid/test_raster_gradients.py
+++ b/tests/grid/test_raster_gradients.py
@@ -10,34 +10,6 @@
from landlab.grid.raster_gradients import calc_grad_at_link
-@pytest.mark.benchmark(group="calc_diff_at_link")
-@pytest.mark.parametrize(
- "func",
- [calc_diff_at_link, calc_diff_at_link_slow],
- ids=["raster-specific", "general"],
-)
-def test_calc_diff_at_link_bench(benchmark, func):
- grid = RasterModelGrid((400, 5000), (1.0, 2.0))
- value_at_node = np.random.uniform(size=grid.number_of_links)
- out = grid.empty(at="link")
-
- benchmark(func, grid, value_at_node, out=out)
-
-
-@pytest.mark.benchmark(group="calc_grad_at_link")
-@pytest.mark.parametrize(
- "func",
- [calc_diff_at_link, calc_diff_at_link_slow],
- ids=["raster-specific", "general"],
-)
-def test_calc_grad_at_link_bench(benchmark, func):
- grid = RasterModelGrid((400, 5000), (1.0, 2.0))
- value_at_node = np.random.uniform(size=grid.number_of_links)
- out = grid.empty(at="link")
-
- benchmark(func, grid, value_at_node, out=out)
-
-
@pytest.mark.parametrize("shape", [(4, 5), (40, 50), (50, 40), (3, 3)])
@pytest.mark.parametrize("spacing", [(1.0, 3.0), (3.0, 1.0)])
def test_calc_diff_at_link_matches(shape, spacing):
diff --git a/tests/io/test_read_esri_ascii/4_x_3.asc b/tests/io/test_read_esri_ascii/4_x_3.asc
index bef6cec993..da35c21c3f 100644
--- a/tests/io/test_read_esri_ascii/4_x_3.asc
+++ b/tests/io/test_read_esri_ascii/4_x_3.asc
@@ -1,10 +1,10 @@
-ncols 3
-nrows 4
-xllcorner 1.
-yllcorner 2.
-cellsize 10.
-NODATA_value -9999
-0. 1. 2.
-3. 4. 5.
-6. 7. 8.
-9. 10. 11.
+ncols 3
+nrows 4
+xllcorner 1.
+yllcorner 2.
+cellsize 10.
+NODATA_value -9999
+0. 1. 2.
+3. 4. 5.
+6. 7. 8.
+9. 10. 11.
diff --git a/tests/io/test_read_esri_ascii/4_x_3_no_nodata_value.asc b/tests/io/test_read_esri_ascii/4_x_3_no_nodata_value.asc
index ab2a1e5c6f..ac67dd29dd 100644
--- a/tests/io/test_read_esri_ascii/4_x_3_no_nodata_value.asc
+++ b/tests/io/test_read_esri_ascii/4_x_3_no_nodata_value.asc
@@ -1,9 +1,9 @@
-ncols 3
-nrows 4
-xllcorner 1.
-yllcorner 2.
-cellsize 10.
-0. 1. 2.
-3. 4. 5.
-6. 7. 8.
-9. 10. 11.
+ncols 3
+nrows 4
+xllcorner 1.
+yllcorner 2.
+cellsize 10.
+0. 1. 2.
+3. 4. 5.
+6. 7. 8.
+9. 10. 11.
diff --git a/tests/io/test_read_esri_ascii/hugo_site.asc b/tests/io/test_read_esri_ascii/hugo_site.asc
index 8d37cafd42..61c8e89340 100644
--- a/tests/io/test_read_esri_ascii/hugo_site.asc
+++ b/tests/io/test_read_esri_ascii/hugo_site.asc
@@ -1,61 +1,61 @@
-ncols 76
-nrows 55
-xllcorner 0
-yllcorner 0
-cellsize 10
-NODATA_value -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1708 -9999 1707 1708 -9999 1708 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1709 1708 1708 1708 1707 1708 1708 1707 1707 1707 1706 1705 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1708 1708 1707 1707 1707 1708 1707 1707 1706 1706 1705 1705 1707 1706 1705 1706 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1706 1707 1707 1707 1707 1707 1707 1707 1706 1706 1705 1705 1705 1705 1705 1706 1707 1706 1705 1705 1705 1705 1707 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1705 1705 1706 1706 1707 1706 1706 1707 1706 1706 1705 1704 1704 1703 1704 1704 1703 1704 1705 1704 1704 1705 1706 1705 1706 1704 1704 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1704 1704 1704 1704 1705 1704 1705 1705 1705 1706 1704 1704 1704 1703 1702 1702 1701 1702 1702 1704 1704 1705 1704 1704 1704 1705 1705 1703 1705 1704 1704 1704 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1704 1703 1702 1702 1703 1702 1703 1704 1703 1704 1704 1703 1702 1701 1700 1699 1699 1698 1700 1701 1702 1703 1703 1704 1704 1704 1704 1704 1705 1703 1702 1702 1702 1703 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1702 1702 1701 1700 1701 1701 1701 1702 1702 1702 1703 1702 1701 1699 1698 1696 1697 1695 1696 1699 1700 1699 1700 1700 1702 1702 1702 1702 1703 1702 1701 1701 1701 1701 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1700 1699 1698 1698 1698 1699 1698 1700 1699 1699 1699 1700 1699 1697 1696 1693 1693 1693 1694 1696 1698 1698 1698 1698 1699 1699 1700 1701 1700 1700 1699 1698 1699 1699 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1699 1698 1697 1696 1696 1695 1695 1696 1697 1697 1697 1697 1696 1696 1695 1693 1691 1689 1689 1691 1692 1695 1696 1695 1695 1695 1696 1697 1698 1698 1697 1695 1695 1696 1698 1698 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1702 1700 1698 1695 1694 1693 1692 1692 1693 1693 1693 1694 1693 1694 1693 1692 1692 1690 1688 1686 1686 1688 1691 1692 1693 1691 1692 1692 1694 1694 1695 1694 1693 1692 1692 1693 1695 1696 1697 1698 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1701 1699 1696 1694 1692 1690 1689 1689 1689 1690 1690 1690 1690 1690 1690 1690 1689 1688 1685 1684 1683 1686 1688 1689 1689 1689 1689 1689 1690 1691 1692 1692 1691 1690 1690 1691 1692 1694 1696 1696 1697 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1698 1696 1694 1691 1688 1687 1686 1686 1687 1687 1686 1687 1687 1687 1686 1686 1685 1683 1681 1681 1683 1685 1686 1686 1686 1686 1686 1687 1688 1689 1689 1688 1687 1686 1688 1689 1691 1694 1695 1695 1696 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1699 1696 1694 1691 1688 1685 1684 1684 1684 1684 1683 1683 1684 1683 1683 1683 1682 1681 1679 1678 1681 1683 1683 1683 1683 1682 1683 1684 1686 1687 1686 1685 1684 1684 1685 1687 1689 1691 1693 1693 1695 1694 1694 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1704 1703 1702 1700 1696 1695 1692 1689 1686 1684 1682 1682 1682 1681 1681 1681 1680 1680 1680 1680 1679 1677 1677 1679 1680 1680 1681 1680 1679 1680 1681 1683 1684 1684 1683 1681 1681 1682 1685 1687 1689 1691 1693 1694 1691 1693 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1702 1700 1698 1696 1692 1690 1688 1685 1685 1684 1681 1680 1680 1679 1678 1678 1678 1677 1677 1676 1675 1677 1677 1677 1678 1678 1677 1677 1679 1681 1682 1682 1681 1679 1678 1680 1683 1686 1688 1689 1690 1692 1691 1691 1692 1692 1692 1692 1691 1690 1692 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1706 1705 1705 1703 1701 1699 1696 1694 1692 1691 1690 1688 1687 1685 1683 1682 1681 1680 1678 1679 1676 1676 1676 1675 1675 1675 1675 1675 1675 1674 1676 1677 1678 1679 1679 1679 1677 1676 1678 1681 1684 1686 1688 1688 1689 1691 1691 1691 1690 1691 1689 1690 1690 1690 1689 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1705 1704 1702 1700 1698 1696 1695 1694 1692 1691 1691 1688 1687 1686 1685 1684 1682 1682 1680 1678 1677 1675 1675 1674 1674 1673 1673 1673 1674 1675 1675 1676 1676 1677 1676 1675 1677 1680 1683 1684 1687 1686 1687 1688 1687 1688 1687 1688 1687 1687 1687 1687 1686 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1706 1705 1705 1703 1701 1700 1699 1697 1696 1695 1694 1693 1691 1690 1688 1688 1687 1685 1685 1683 1682 1680 1678 1678 1677 1675 1673 1672 1671 1672 1673 1673 1673 1674 1675 1673 1673 1676 1679 1680 1682 1683 1684 1683 1684 1684 1683 1684 1684 1684 1683 1684 1683 1682 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1704 1703 1702 1700 1700 1699 1698 1697 1696 1694 1693 1692 1691 1689 1689 1688 1687 1684 1683 1681 1681 1679 1677 1677 1674 1673 1670 1670 1670 1670 1671 1672 1671 1672 1674 1678 1678 1680 1680 1680 1679 1680 1680 1680 1680 1680 1681 1680 1680 1679 1679 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1706 1706 1705 1703 1703 1703 1702 1701 1699 1698 1696 1696 1695 1695 1694 1692 1691 1689 1688 1685 1685 1683 1682 1680 1679 1678 1676 1675 1673 1671 1670 1669 1669 1670 1671 1674 1675 1676 1676 1677 1676 1676 1677 1676 1677 1677 1676 1677 1676 1678 1676 1675 1676
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1705 1705 1704 1704 1703 1702 1701 1700 1699 1698 1698 1697 1696 1695 1695 1693 1691 1690 1688 1687 1685 1683 1681 1680 1679 1677 1675 1673 1672 1669 1668 1669 1670 1671 1673 1674 1674 1674 1673 1673 1673 1673 1673 1672 1672 1673 1673 1673 1672 1672 1672
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1705 1705 1704 1704 1704 1703 1702 1701 1701 1701 1700 1697 1697 1697 1694 1693 1692 1690 1689 1686 1685 1682 1681 1679 1678 1676 1674 1674 1670 1668 1668 1669 1670 1670 1672 1672 1671 1671 1670 1670 1670 1669 1669 1669 1669 1669 1669 1669 1668 1669
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1706 1706 1705 1705 1705 1704 1703 1702 1701 1701 1700 1698 1697 1696 1695 1694 1692 1690 1689 1687 1684 1683 1682 1679 1679 1677 1675 1674 1672 1670 1668 1667 1668 1668 1669 1669 1669 1668 1668 1668 1667 1666 1666 1665 1665 1665 1665 1665 1665 1665
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1707 1707 1707 1706 1705 1705 1704 1703 1703 1702 1701 1700 1700 1697 1697 1695 1694 1692 1691 1689 1687 1686 1683 1681 1679 1678 1677 1675 1674 1673 1671 1669 1668 1666 1666 1667 1667 1667 1667 1666 1666 1665 1665 1664 1663 1663 1663 1663 1663 1662 1662 1662
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1708 1706 1706 1705 1704 1704 1702 1702 1701 1700 1699 1698 1696 1695 1694 1692 1690 1689 1688 1685 1684 1681 1679 1676 1675 1673 1673 1672 1670 1669 1669 1667 1667 1667 1666 1666 1666 1666 1665 1665 1665 1664 1663 1663 1663 1662 1662 1662 1661 1661 1661
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1706 1706 1706 1705 1705 1704 1702 1702 1700 1700 1699 1697 1696 1694 1693 1691 1690 1688 1686 1685 1683 1681 1678 1676 1673 1672 1671 1670 1670 1669 1668 1668 1668 1667 1667 1666 1666 1665 1665 1664 1664 1664 1664 1664 1663 1663 1663 1662 1662 1662 1661 1660
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1705 1706 1705 1704 1704 1702 1701 1701 1699 1698 1697 1695 1694 1692 1691 1689 1687 1686 1684 1682 1680 1678 1676 1674 1672 1671 1670 1671 1669 1670 1670 1670 1669 1668 1670 1667 1666 1665 1666 1664 1665 1665 1665 1665 1664 1664 1664 1663 1664 1663 1662 1661
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1705 1704 1705 1704 1704 1703 1702 1701 1700 1698 1697 1696 1695 1694 1692 1690 1688 1686 1684 1682 1681 1679 1678 1676 1674 1672 1672 1673 1672 1673 1672 1672 1672 1673 1671 1671 1673 1673 1669 1667 1665 1666 1666 1668 1668 1667 1666 1667 1665 1664 1666 1665 1663 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1704 1703 1703 1702 1701 1701 1700 1698 1696 1695 1693 1692 1691 1690 1687 1685 1683 1681 1680 1678 1677 1675 1674 1673 1673 1673 1675 1676 1677 1675 1676 1675 1675 1673 1673 1674 1675 1673 1672 1672 1672 1670 1671 1670 1669 1668 1668 1666 1665 1666 1665 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1703 1702 1701 1700 1700 1699 1699 1698 1696 1694 1692 1691 1690 1688 1687 1685 1682 1681 1679 1678 1676 1675 1675 1674 1674 1676 1674 1676 1678 1679 1679 1679 1679 1677 1675 1674 1676 1679 1679 1679 1678 1674 1674 1673 1671 1670 1669 1668 1666 1666 1668 1668 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1699 1698 1697 1697 1697 1696 1695 1692 1691 1689 1686 1685 1684 1682 1680 1679 1676 1676 1675 1675 1676 1677 1678 1677 1676 1678 1681 1682 1681 1683 1682 1679 1677 1678 1679 1681 1682 1682 1680 1678 1677 1675 1673 1671 1669 1668 1666 1668 1671 1671 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1701 1699 1697 1696 1694 1695 1694 1694 1693 1691 1688 1686 1683 1683 1681 1680 1679 1677 1676 1676 1678 1680 1681 1680 1678 1679 1677 1678 1681 1683 1684 1685 1684 1682 1678 1680 1682 1684 1684 1684 1683 1680 1678 1676 1673 1671 1669 1668 1668 1671 1673 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1698 1696 1694 1692 1691 1691 1692 1691 1690 1687 1685 1682 1680 1679 1678 1677 1677 1677 1681 1682 1682 1683 1683 1684 1682 1682 1680 1683 1686 1685 1687 1686 1683 1681 1681 1684 1686 1687 1686 1685 1681 1679 1676 1673 1671 1669 1671 1672 1675 1676 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1703 1701 1700 1698 1696 1693 1691 1689 1689 1690 1689 1687 1685 1684 1681 1679 1679 1680 1681 1682 1684 1684 1687 1685 1686 1687 1687 1684 1682 1681 1684 1687 1688 1689 1687 1685 1682 1685 1688 1688 1688 1687 1685 1681 1678 1676 1673 1671 1672 1673 1677 1678 1679 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1697 1694 1692 1688 1687 1687 1686 1685 1684 1682 1680 1680 1681 1683 1684 1685 1688 1688 1689 1688 1688 1689 1687 1685 1684 1683 1684 1688 1689 1690 1689 1686 1686 1688 1691 1690 1689 1687 1685 1681 1678 1675 1673 1673 1674 1676 1678 1680 1682 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1699 1699 1696 1694 1692 1689 1686 1685 1684 1683 1682 1681 1680 1682 1684 1686 1687 1687 1690 1692 1691 1690 1692 1691 1690 1689 1686 1685 1687 1689 1692 1692 1691 1689 1689 1691 1692 1693 1691 1688 1686 1682 1677 1675 1675 1676 1677 1680 1681 1683 1684 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1698 1696 1694 1691 1689 1687 1685 1684 1683 1682 1682 1682 1684 1686 1690 1690 1691 1694 1694 1694 1695 1694 1693 1691 1691 1689 1689 1690 1692 1693 1694 1693 1692 1693 1693 1695 1694 1692 1688 1685 1682 1678 1676 1679 1679 1680 1683 1684 1685 1686 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1698 1697 1695 1693 1690 1689 1687 1686 1685 1685 1685 1684 1685 1687 1691 1693 1694 1696 1696 1698 1698 1697 1696 1694 1693 1693 1692 1692 1694 1695 1696 1695 1696 1695 1696 1696 1693 1692 1690 1687 1683 1680 1679 1681 1684 1683 1686 1688 1688 1690 1688 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1695 1694 1692 1690 1689 1689 1689 1688 1687 1686 1686 1689 1692 1694 1696 1698 1699 1700 1700 1700 1699 1697 1696 1696 1695 1694 1697 1697 1699 1698 1698 1696 1698 1697 1696 1694 1691 1689 1685 1683 1681 1686 1687 1688 1687 1691 1689 1691 1691 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1700 1700 1697 1696 1694 1693 1692 1691 1690 1690 1690 1688 1687 1690 1692 1694 1697 1699 1701 1700 1701 1701 1702 1698 1700 1698 1698 1697 1699 1699 1700 1700 1699 1701 1700 1699 1699 1696 1693 1690 1687 1685 1687 1689 1691 1691 1691 1693 1693 1692 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1698 1698 1698 1693 1693 1694 1693 1692 1692 1691 1689 1690 1693 1695 1697 1700 1701 1702 1702 1704 1702 1702 1703 1703 1701 1700 1699 1701 1702 1702 1705 1704 1702 1702 1700 1697 1695 1693 1691 1690 1690 1694 1694 1696 1696 1695 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1697 1698 1696 1695 1695 1695 1694 1694 1693 1693 1696 1698 1699 1701 1702 1705 1704 1704 1703 1704 1704 1702 1702 1702 1703 1704 1703 1706 1706 1705 1702 1703 1701 1698 1695 1694 1695 1696 1697 1697 1699 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1697 1697 1696 1697 1697 1696 1696 1694 1695 1697 1699 1700 1703 1704 1705 1704 1706 1705 1706 1702 1703 1705 1705 1708 1707 1703 1708 1708 1706 1706 1705 1703 1701 1699 1699 1699 1698 1700 1700 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1697 1698 1698 1700 1697 1698 1697 1699 1700 1702 1702 1705 1705 1706 1706 1706 1705 1706 1705 1707 1709 1706 1706 1708 1708 1709 1708 1706 1705 1705 1701 1700 1700 1701 1704 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1699 1701 1700 1699 1699 1700 1699 1699 1704 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 1709 1710 1710 1710 1710 1707 1708 1704 1704 1706 1704 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1699 1700 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1709 1709 1707 1707 1708 1707 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1710 1710 1709 1708 1709 1708 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1711 1710 1710 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
--9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+ncols 76
+nrows 55
+xllcorner 0
+yllcorner 0
+cellsize 10
+NODATA_value -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1708 -9999 1707 1708 -9999 1708 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1709 1708 1708 1708 1707 1708 1708 1707 1707 1707 1706 1705 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1708 1708 1707 1707 1707 1708 1707 1707 1706 1706 1705 1705 1707 1706 1705 1706 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1706 1707 1707 1707 1707 1707 1707 1707 1706 1706 1705 1705 1705 1705 1705 1706 1707 1706 1705 1705 1705 1705 1707 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1705 1705 1706 1706 1707 1706 1706 1707 1706 1706 1705 1704 1704 1703 1704 1704 1703 1704 1705 1704 1704 1705 1706 1705 1706 1704 1704 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1704 1704 1704 1704 1705 1704 1705 1705 1705 1706 1704 1704 1704 1703 1702 1702 1701 1702 1702 1704 1704 1705 1704 1704 1704 1705 1705 1703 1705 1704 1704 1704 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1704 1703 1702 1702 1703 1702 1703 1704 1703 1704 1704 1703 1702 1701 1700 1699 1699 1698 1700 1701 1702 1703 1703 1704 1704 1704 1704 1704 1705 1703 1702 1702 1702 1703 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1702 1702 1701 1700 1701 1701 1701 1702 1702 1702 1703 1702 1701 1699 1698 1696 1697 1695 1696 1699 1700 1699 1700 1700 1702 1702 1702 1702 1703 1702 1701 1701 1701 1701 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1700 1699 1698 1698 1698 1699 1698 1700 1699 1699 1699 1700 1699 1697 1696 1693 1693 1693 1694 1696 1698 1698 1698 1698 1699 1699 1700 1701 1700 1700 1699 1698 1699 1699 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1699 1698 1697 1696 1696 1695 1695 1696 1697 1697 1697 1697 1696 1696 1695 1693 1691 1689 1689 1691 1692 1695 1696 1695 1695 1695 1696 1697 1698 1698 1697 1695 1695 1696 1698 1698 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1702 1700 1698 1695 1694 1693 1692 1692 1693 1693 1693 1694 1693 1694 1693 1692 1692 1690 1688 1686 1686 1688 1691 1692 1693 1691 1692 1692 1694 1694 1695 1694 1693 1692 1692 1693 1695 1696 1697 1698 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1701 1699 1696 1694 1692 1690 1689 1689 1689 1690 1690 1690 1690 1690 1690 1690 1689 1688 1685 1684 1683 1686 1688 1689 1689 1689 1689 1689 1690 1691 1692 1692 1691 1690 1690 1691 1692 1694 1696 1696 1697 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1698 1696 1694 1691 1688 1687 1686 1686 1687 1687 1686 1687 1687 1687 1686 1686 1685 1683 1681 1681 1683 1685 1686 1686 1686 1686 1686 1687 1688 1689 1689 1688 1687 1686 1688 1689 1691 1694 1695 1695 1696 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1699 1696 1694 1691 1688 1685 1684 1684 1684 1684 1683 1683 1684 1683 1683 1683 1682 1681 1679 1678 1681 1683 1683 1683 1683 1682 1683 1684 1686 1687 1686 1685 1684 1684 1685 1687 1689 1691 1693 1693 1695 1694 1694 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1704 1703 1702 1700 1696 1695 1692 1689 1686 1684 1682 1682 1682 1681 1681 1681 1680 1680 1680 1680 1679 1677 1677 1679 1680 1680 1681 1680 1679 1680 1681 1683 1684 1684 1683 1681 1681 1682 1685 1687 1689 1691 1693 1694 1691 1693 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1702 1700 1698 1696 1692 1690 1688 1685 1685 1684 1681 1680 1680 1679 1678 1678 1678 1677 1677 1676 1675 1677 1677 1677 1678 1678 1677 1677 1679 1681 1682 1682 1681 1679 1678 1680 1683 1686 1688 1689 1690 1692 1691 1691 1692 1692 1692 1692 1691 1690 1692 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1706 1705 1705 1703 1701 1699 1696 1694 1692 1691 1690 1688 1687 1685 1683 1682 1681 1680 1678 1679 1676 1676 1676 1675 1675 1675 1675 1675 1675 1674 1676 1677 1678 1679 1679 1679 1677 1676 1678 1681 1684 1686 1688 1688 1689 1691 1691 1691 1690 1691 1689 1690 1690 1690 1689 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1705 1704 1702 1700 1698 1696 1695 1694 1692 1691 1691 1688 1687 1686 1685 1684 1682 1682 1680 1678 1677 1675 1675 1674 1674 1673 1673 1673 1674 1675 1675 1676 1676 1677 1676 1675 1677 1680 1683 1684 1687 1686 1687 1688 1687 1688 1687 1688 1687 1687 1687 1687 1686 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1706 1705 1705 1703 1701 1700 1699 1697 1696 1695 1694 1693 1691 1690 1688 1688 1687 1685 1685 1683 1682 1680 1678 1678 1677 1675 1673 1672 1671 1672 1673 1673 1673 1674 1675 1673 1673 1676 1679 1680 1682 1683 1684 1683 1684 1684 1683 1684 1684 1684 1683 1684 1683 1682 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1704 1703 1702 1700 1700 1699 1698 1697 1696 1694 1693 1692 1691 1689 1689 1688 1687 1684 1683 1681 1681 1679 1677 1677 1674 1673 1670 1670 1670 1670 1671 1672 1671 1672 1674 1678 1678 1680 1680 1680 1679 1680 1680 1680 1680 1680 1681 1680 1680 1679 1679 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1706 1706 1705 1703 1703 1703 1702 1701 1699 1698 1696 1696 1695 1695 1694 1692 1691 1689 1688 1685 1685 1683 1682 1680 1679 1678 1676 1675 1673 1671 1670 1669 1669 1670 1671 1674 1675 1676 1676 1677 1676 1676 1677 1676 1677 1677 1676 1677 1676 1678 1676 1675 1676
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1705 1705 1704 1704 1703 1702 1701 1700 1699 1698 1698 1697 1696 1695 1695 1693 1691 1690 1688 1687 1685 1683 1681 1680 1679 1677 1675 1673 1672 1669 1668 1669 1670 1671 1673 1674 1674 1674 1673 1673 1673 1673 1673 1672 1672 1673 1673 1673 1672 1672 1672
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1705 1705 1704 1704 1704 1703 1702 1701 1701 1701 1700 1697 1697 1697 1694 1693 1692 1690 1689 1686 1685 1682 1681 1679 1678 1676 1674 1674 1670 1668 1668 1669 1670 1670 1672 1672 1671 1671 1670 1670 1670 1669 1669 1669 1669 1669 1669 1669 1668 1669
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1706 1706 1705 1705 1705 1704 1703 1702 1701 1701 1700 1698 1697 1696 1695 1694 1692 1690 1689 1687 1684 1683 1682 1679 1679 1677 1675 1674 1672 1670 1668 1667 1668 1668 1669 1669 1669 1668 1668 1668 1667 1666 1666 1665 1665 1665 1665 1665 1665 1665
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1707 1707 1707 1706 1705 1705 1704 1703 1703 1702 1701 1700 1700 1697 1697 1695 1694 1692 1691 1689 1687 1686 1683 1681 1679 1678 1677 1675 1674 1673 1671 1669 1668 1666 1666 1667 1667 1667 1667 1666 1666 1665 1665 1664 1663 1663 1663 1663 1663 1662 1662 1662
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1708 1706 1706 1705 1704 1704 1702 1702 1701 1700 1699 1698 1696 1695 1694 1692 1690 1689 1688 1685 1684 1681 1679 1676 1675 1673 1673 1672 1670 1669 1669 1667 1667 1667 1666 1666 1666 1666 1665 1665 1665 1664 1663 1663 1663 1662 1662 1662 1661 1661 1661
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1706 1706 1706 1705 1705 1704 1702 1702 1700 1700 1699 1697 1696 1694 1693 1691 1690 1688 1686 1685 1683 1681 1678 1676 1673 1672 1671 1670 1670 1669 1668 1668 1668 1667 1667 1666 1666 1665 1665 1664 1664 1664 1664 1664 1663 1663 1663 1662 1662 1662 1661 1660
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1705 1706 1705 1704 1704 1702 1701 1701 1699 1698 1697 1695 1694 1692 1691 1689 1687 1686 1684 1682 1680 1678 1676 1674 1672 1671 1670 1671 1669 1670 1670 1670 1669 1668 1670 1667 1666 1665 1666 1664 1665 1665 1665 1665 1664 1664 1664 1663 1664 1663 1662 1661
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1705 1704 1705 1704 1704 1703 1702 1701 1700 1698 1697 1696 1695 1694 1692 1690 1688 1686 1684 1682 1681 1679 1678 1676 1674 1672 1672 1673 1672 1673 1672 1672 1672 1673 1671 1671 1673 1673 1669 1667 1665 1666 1666 1668 1668 1667 1666 1667 1665 1664 1666 1665 1663 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1704 1703 1703 1702 1701 1701 1700 1698 1696 1695 1693 1692 1691 1690 1687 1685 1683 1681 1680 1678 1677 1675 1674 1673 1673 1673 1675 1676 1677 1675 1676 1675 1675 1673 1673 1674 1675 1673 1672 1672 1672 1670 1671 1670 1669 1668 1668 1666 1665 1666 1665 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1703 1702 1701 1700 1700 1699 1699 1698 1696 1694 1692 1691 1690 1688 1687 1685 1682 1681 1679 1678 1676 1675 1675 1674 1674 1676 1674 1676 1678 1679 1679 1679 1679 1677 1675 1674 1676 1679 1679 1679 1678 1674 1674 1673 1671 1670 1669 1668 1666 1666 1668 1668 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1699 1698 1697 1697 1697 1696 1695 1692 1691 1689 1686 1685 1684 1682 1680 1679 1676 1676 1675 1675 1676 1677 1678 1677 1676 1678 1681 1682 1681 1683 1682 1679 1677 1678 1679 1681 1682 1682 1680 1678 1677 1675 1673 1671 1669 1668 1666 1668 1671 1671 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1701 1699 1697 1696 1694 1695 1694 1694 1693 1691 1688 1686 1683 1683 1681 1680 1679 1677 1676 1676 1678 1680 1681 1680 1678 1679 1677 1678 1681 1683 1684 1685 1684 1682 1678 1680 1682 1684 1684 1684 1683 1680 1678 1676 1673 1671 1669 1668 1668 1671 1673 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1698 1696 1694 1692 1691 1691 1692 1691 1690 1687 1685 1682 1680 1679 1678 1677 1677 1677 1681 1682 1682 1683 1683 1684 1682 1682 1680 1683 1686 1685 1687 1686 1683 1681 1681 1684 1686 1687 1686 1685 1681 1679 1676 1673 1671 1669 1671 1672 1675 1676 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1703 1701 1700 1698 1696 1693 1691 1689 1689 1690 1689 1687 1685 1684 1681 1679 1679 1680 1681 1682 1684 1684 1687 1685 1686 1687 1687 1684 1682 1681 1684 1687 1688 1689 1687 1685 1682 1685 1688 1688 1688 1687 1685 1681 1678 1676 1673 1671 1672 1673 1677 1678 1679 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1697 1694 1692 1688 1687 1687 1686 1685 1684 1682 1680 1680 1681 1683 1684 1685 1688 1688 1689 1688 1688 1689 1687 1685 1684 1683 1684 1688 1689 1690 1689 1686 1686 1688 1691 1690 1689 1687 1685 1681 1678 1675 1673 1673 1674 1676 1678 1680 1682 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1699 1699 1696 1694 1692 1689 1686 1685 1684 1683 1682 1681 1680 1682 1684 1686 1687 1687 1690 1692 1691 1690 1692 1691 1690 1689 1686 1685 1687 1689 1692 1692 1691 1689 1689 1691 1692 1693 1691 1688 1686 1682 1677 1675 1675 1676 1677 1680 1681 1683 1684 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1698 1696 1694 1691 1689 1687 1685 1684 1683 1682 1682 1682 1684 1686 1690 1690 1691 1694 1694 1694 1695 1694 1693 1691 1691 1689 1689 1690 1692 1693 1694 1693 1692 1693 1693 1695 1694 1692 1688 1685 1682 1678 1676 1679 1679 1680 1683 1684 1685 1686 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1698 1697 1695 1693 1690 1689 1687 1686 1685 1685 1685 1684 1685 1687 1691 1693 1694 1696 1696 1698 1698 1697 1696 1694 1693 1693 1692 1692 1694 1695 1696 1695 1696 1695 1696 1696 1693 1692 1690 1687 1683 1680 1679 1681 1684 1683 1686 1688 1688 1690 1688 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1695 1694 1692 1690 1689 1689 1689 1688 1687 1686 1686 1689 1692 1694 1696 1698 1699 1700 1700 1700 1699 1697 1696 1696 1695 1694 1697 1697 1699 1698 1698 1696 1698 1697 1696 1694 1691 1689 1685 1683 1681 1686 1687 1688 1687 1691 1689 1691 1691 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1700 1700 1697 1696 1694 1693 1692 1691 1690 1690 1690 1688 1687 1690 1692 1694 1697 1699 1701 1700 1701 1701 1702 1698 1700 1698 1698 1697 1699 1699 1700 1700 1699 1701 1700 1699 1699 1696 1693 1690 1687 1685 1687 1689 1691 1691 1691 1693 1693 1692 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1698 1698 1698 1693 1693 1694 1693 1692 1692 1691 1689 1690 1693 1695 1697 1700 1701 1702 1702 1704 1702 1702 1703 1703 1701 1700 1699 1701 1702 1702 1705 1704 1702 1702 1700 1697 1695 1693 1691 1690 1690 1694 1694 1696 1696 1695 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1697 1698 1696 1695 1695 1695 1694 1694 1693 1693 1696 1698 1699 1701 1702 1705 1704 1704 1703 1704 1704 1702 1702 1702 1703 1704 1703 1706 1706 1705 1702 1703 1701 1698 1695 1694 1695 1696 1697 1697 1699 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1697 1697 1696 1697 1697 1696 1696 1694 1695 1697 1699 1700 1703 1704 1705 1704 1706 1705 1706 1702 1703 1705 1705 1708 1707 1703 1708 1708 1706 1706 1705 1703 1701 1699 1699 1699 1698 1700 1700 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1697 1698 1698 1700 1697 1698 1697 1699 1700 1702 1702 1705 1705 1706 1706 1706 1705 1706 1705 1707 1709 1706 1706 1708 1708 1709 1708 1706 1705 1705 1701 1700 1700 1701 1704 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1699 1701 1700 1699 1699 1700 1699 1699 1704 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 1709 1710 1710 1710 1710 1707 1708 1704 1704 1706 1704 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1699 1700 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1709 1709 1707 1707 1708 1707 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1710 1710 1709 1708 1709 1708 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1711 1710 1710 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
+-9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999