├── .github └── workflows │ ├── build.yml │ └── deploy.yml ├── .gitignore ├── CODE_OF_CONDUCT.rst ├── LICENSE ├── MANIFEST.in ├── README.rst ├── assets ├── private │ ├── liang_2015_fig1fig2.png │ ├── liang_2015_fig5.png │ └── pyDeltaRCM_logo.svg └── symbol.svg ├── docs ├── Makefile ├── make.bat └── source │ ├── .nojekyll │ ├── _resources │ ├── checkpoint.yaml │ ├── checkpoint │ │ └── checkpoint.npz │ └── joss │ │ ├── figures │ │ ├── figures.py │ │ ├── pyDeltaRCM_20210810-151130.log │ │ └── timeseries.png │ │ ├── paper.bib │ │ └── paper.md │ ├── _static │ └── style.css │ ├── _templates │ └── page.html │ ├── conf.py │ ├── examples │ ├── basic_runs.rst │ ├── custom_class_preprocessor.rst │ ├── custom_saving.rst │ ├── custom_yaml.rst │ ├── index.rst │ ├── modelzoo.rst │ ├── overwrite_topo_diffusion.rst │ ├── resume_from_checkpoint.rst │ ├── simple_example.ipynb │ ├── slight_slope.rst │ ├── subsidence_region.rst │ ├── updating_boundary_conditions.rst │ ├── variable_bedload.rst │ └── variable_velocity.rst │ ├── guides │ ├── 10min.rst │ ├── advanced_configuration_guide.inc │ ├── developer_guide.rst │ ├── getting_started.rst │ ├── subsidence_guide.inc │ └── user_guide.rst │ ├── index.rst │ ├── info │ ├── hydrodynamics.rst │ ├── index.rst │ ├── initialization.rst │ ├── modeltime.rst │ ├── morphodynamics.rst │ ├── outputfile.rst │ └── yamlparameters.rst │ ├── meta │ ├── citing.rst │ ├── conduct.rst │ ├── contributing.rst │ ├── installing.rst │ ├── license.rst │ └── usedby.rst │ ├── pyplots │ ├── debug_tools │ │ └── debug_demo.py │ ├── guides │ │ ├── 10min_demo.py │ │ ├── cover.py │ │ └── output_file.py │ ├── init_tools │ │ ├── domain_basin_inlet_depth.py │ │ ├── domain_inlet_geometry.py │ │ ├── domain_parameters.py │ │ └── domain_size_compare.py │ ├── modeltime │ │ ├── _base.py │ │ ├── four_year_condensed_plot.py │ │ ├── four_year_plot.py │ │ └── one_year_plot.py │ ├── sed_tools │ │ ├── _initial_bed_state.py │ │ ├── route_all_mud_parcels.py │ │ ├── route_all_sand_parcels.py │ │ ├── sediment_weights_examples.py │ │ └── topo_diffusion.py │ └── water_tools │ │ ├── _accumulate_free_surface_walks.py │ │ ├── _check_for_loops.py │ │ ├── _smooth_free_surface.py │ │ ├── compute_free_surface_inputs.py │ │ ├── compute_free_surface_outputs.py │ │ ├── flooding_correction.py │ │ ├── run_water_iteration.py │ │ └── water_weights_examples.py │ └── reference │ ├── debug_tools │ └── index.rst │ ├── hook_tools │ └── index.rst │ ├── index.rst │ ├── init_tools │ └── index.rst │ ├── iteration_tools │ └── index.rst │ ├── model │ ├── index.rst │ ├── model_hooks.rst │ └── yaml_defaults.rst │ ├── preprocessor │ └── index.rst │ ├── sed_tools │ └── index.rst │ ├── shared_tools │ └── index.rst │ └── water_tools │ └── index.rst ├── pyDeltaRCM ├── __init__.py ├── __main__.py ├── _version.py ├── debug_tools.py ├── default.yml ├── hook_tools.py ├── init_tools.py ├── iteration_tools.py ├── model.py ├── preprocessor.py ├── sed_tools.py ├── shared_tools.py └── water_tools.py ├── pyproject.toml ├── requirements-docs.txt ├── requirements-test.txt ├── requirements.txt ├── strat_preprocess.py └── tests ├── __init__.py ├── imgs_baseline ├── test_plot_domain_cell_type.png ├── test_plot_domain_cell_type_list_index.png ├── test_plot_domain_cell_type_list_mix_tuple_index.png ├── test_plot_domain_cell_type_list_tuple.png ├── test_plot_domain_cell_type_multiple_diff_args.png ├── test_plot_domain_cell_type_multiple_diff_kwargs.png ├── test_plot_domain_cell_type_multiple_index_calls.png ├── test_plot_domain_cell_type_no_grid.png ├── test_plot_domain_cell_type_single_index.png ├── test_plot_domain_cell_type_single_tuple.png ├── test_plot_domain_velocity.png ├── test_plot_domain_withlabel.png ├── test_plot_iwalk.png ├── test_plot_multiple_subplots.png ├── test_show_line_pts_Nx2_array.png └── test_show_line_set_points.png ├── integration ├── __init__.py ├── test_checkpointing.py ├── test_cli.py ├── test_consistent_outputs.py └── test_timing_triggers.py ├── test_debug_tools.py ├── test_init_tools.py ├── test_iteration_tools.py ├── test_logging.py ├── test_model.py ├── test_preprocessor.py ├── test_sed_tools.py ├── test_shared_tools.py ├── test_water_tools.py └── utilities.py /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # This workflow installs and tests pyDeltaRCM on mulitple python versions and operating systems. 2 | 3 | name: build 4 | 5 | on: 6 | push: 7 | pull_request: 8 | schedule: 9 | - cron: '0 0 1 * *' # run workflow at 12AM on first day of every month 10 | 11 | jobs: 12 | 13 | test: 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [ubuntu-latest, macos-latest, windows-latest] 19 | python-version: ['3.11', '3.12', '3.13'] 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v5 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | pip install setuptools 31 | pip install -r requirements-test.txt 32 | pip install -r requirements.txt 33 | - name: Install pyDeltaRCM 34 | run: | 35 | pip install . 36 | - name: Test with pytest 37 | run: | 38 | python -m pytest --mpl --mpl-baseline-path=tests/imgs_baseline 39 | 40 | 41 | coverage: 42 | runs-on: ${{ matrix.os }} 43 | strategy: 44 | fail-fast: false 45 | matrix: 46 | os: [ubuntu-latest, macos-latest, windows-latest] 47 | env: 48 | OS: ${{ matrix.os }} 49 | PYTHON: '3.13' 50 | steps: 51 | - name: Checkout code 52 | uses: actions/checkout@v4 53 | - name: Set up Python ${{ env.PYTHON }} 54 | uses: actions/setup-python@v5 55 | with: 56 | python-version: ${{ env.PYTHON }} 57 | - name: Install dependencies 58 | run: | 59 | python -m pip install --upgrade pip 60 | pip install setuptools 61 | pip install pytest pytest-cov pytest-mpl coveralls 62 | pip install -r requirements.txt 63 | - name: Install pyDeltaRCM 64 | run: | 65 | pip install . 66 | - name: Disable jitted for coverage 67 | run: | 68 | echo "DISABLE_JIT: 1" > .numba_config.yaml 69 | - name: Test with pytest 70 | run: | 71 | python -m pytest --ignore=tests/integration/ --cov=pyDeltaRCM/ --cov-report=xml --mpl --mpl-baseline-path=tests/imgs_baseline 72 | - name: Upload coverage to Codecov 73 | uses: codecov/codecov-action@v5 74 | with: 75 | token: ${{ secrets.CODECOV_TOKEN }} 76 | file: ./coverage.xml 77 | env_vars: OS 78 | name: codecov-umbrella 79 | fail_ci_if_error: false 80 | 81 | 82 | docs: 83 | runs-on: ubuntu-latest 84 | steps: 85 | - name: Checkout code 86 | uses: actions/checkout@v4 87 | with: 88 | persist-credentials: false 89 | - name: Set up Python 90 | uses: actions/setup-python@v5 91 | with: 92 | python-version: '3.13' 93 | - name: Install dependencies 94 | run: | 95 | python -m pip install --upgrade pip 96 | pip install setuptools 97 | pip install -r requirements.txt 98 | pip install -r requirements-docs.txt 99 | sudo apt update -y && sudo apt install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended dvipng 100 | - name: Install pyDeltaRCM 101 | run: | 102 | pip install . 103 | - name: Build and test documentation 104 | run: | 105 | (cd docs && make docs) 106 | - name: Upload log file 107 | uses: actions/upload-artifact@v4 108 | if: ${{ failure() }} 109 | with: 110 | name: log-file 111 | path: docs/deltaRCM_Output/*.log 112 | - name: Debug 113 | run: | 114 | echo $REF 115 | echo $EVENT_NAME 116 | echo ${{ github.event_name == 'push' }} 117 | echo ${{ github.ref == 'refs/heads/develop' }} 118 | echo ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} 119 | - name: Deploy to GitHub Pages 120 | uses: JamesIves/github-pages-deploy-action@v4 121 | if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} 122 | with: 123 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 124 | EVENT_NAME: ${{ github.event_name }} 125 | REF: ${{ github.ref }} 126 | BRANCH: gh-pages 127 | FOLDER: docs/build/html 128 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # This workflows will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | name: deploy 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | deploy: 12 | 13 | # package runs on all os, so just upload from one for any 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Set up Python 19 | uses: actions/setup-python@v2 20 | with: 21 | python-version: '3.13' 22 | - name: Install dependencies 23 | run: | 24 | python -m pip install --upgrade pip 25 | pip install setuptools wheel twine build 26 | pip install -r requirements.txt 27 | - name: Build 28 | shell: bash 29 | run: | 30 | python -m build 31 | twine upload dist/* 32 | - name: Publish 33 | uses: pypa/gh-action-pypi-publish@release/v1 34 | with: 35 | repository-url: https://upload.pypi.org/legacy/ 36 | skip-existing: true 37 | print-hash: true 38 | verify-metadata: false 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | deltaRCM_Output/ 2 | 3 | ### a standard OSX .gitignore ### 4 | 5 | # General 6 | .DS_Store 7 | .AppleDouble 8 | .LSOverride 9 | 10 | # Icon must end with two \r 11 | Icon 12 | 13 | # Thumbnails 14 | ._* 15 | 16 | # Files that might appear in the root of a volume 17 | .DocumentRevisions-V100 18 | .fseventsd 19 | .Spotlight-V100 20 | .TemporaryItems 21 | .Trashes 22 | .VolumeIcon.icns 23 | .com.apple.timemachine.donotpresent 24 | 25 | # Directories potentially created on remote AFP share 26 | .AppleDB 27 | .AppleDesktop 28 | Network Trash Folder 29 | Temporary Items 30 | .apdisk 31 | 32 | ################# 33 | 34 | # Byte-compiled / optimized / DLL files 35 | __pycache__/ 36 | *.py[cod] 37 | *$py.class 38 | 39 | # C extensions 40 | *.so 41 | 42 | # Distribution / packaging 43 | .Python 44 | env/ 45 | build/ 46 | develop-eggs/ 47 | dist/ 48 | downloads/ 49 | eggs/ 50 | .eggs/ 51 | lib/ 52 | lib64/ 53 | parts/ 54 | sdist/ 55 | var/ 56 | *.egg-info/ 57 | .installed.cfg 58 | *.egg 59 | 60 | # PyInstaller 61 | # Usually these files are written by a python script from a template 62 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 63 | *.manifest 64 | *.spec 65 | 66 | # Installer logs 67 | pip-log.txt 68 | pip-delete-this-directory.txt 69 | 70 | # Unit test / coverage reports 71 | htmlcov/ 72 | .tox/ 73 | .coverage 74 | .coverage.* 75 | .cache 76 | nosetests.xml 77 | coverage.xml 78 | *,cover 79 | .hypothesis/ 80 | .pytest_cache 81 | 82 | # Translations 83 | *.mo 84 | *.pot 85 | 86 | # Django stuff: 87 | *.log 88 | 89 | # Sphinx documentation 90 | docs/_build/ 91 | docs/source/_autosummary/ 92 | 93 | # PyBuilder 94 | target/ 95 | 96 | #Ipython Notebook 97 | .ipynb_checkpoints 98 | 99 | # SublimeText docs 100 | *.sublime-* 101 | 102 | # VSCode settings directory 103 | .vscode/ 104 | 105 | # temp folder 106 | temp/ 107 | 108 | # joss paper resources 109 | docs/source/_resources/joss 110 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.rst: -------------------------------------------------------------------------------- 1 | *************** 2 | Code of Conduct 3 | *************** 4 | 5 | Our Pledge 6 | ---------- 7 | 8 | In the interest of fostering an open and welcoming environment, we as 9 | contributors and maintainers pledge to making participation in our project and 10 | our community a harassment-free experience for everyone, regardless of age, body 11 | size, disability, ethnicity, gender identity and expression, level of experience, 12 | nationality, personal appearance, race, religion, or sexual identity and 13 | orientation. 14 | 15 | 16 | Our Standards 17 | ------------- 18 | 19 | Examples of behavior that contributes to creating a positive environment 20 | include: 21 | 22 | * Using welcoming and inclusive language 23 | * Being respectful of differing viewpoints and experiences 24 | * Gracefully accepting constructive criticism 25 | * Focusing on what is best for the community 26 | * Showing empathy towards other community members 27 | 28 | 29 | Examples of unacceptable behavior by participants include: 30 | 31 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 32 | * Trolling, insulting/derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 35 | * Other conduct which could reasonably be considered inappropriate in a professional setting 36 | 37 | 38 | Our Responsibilities 39 | -------------------- 40 | 41 | Project maintainers are responsible for clarifying the standards of acceptable 42 | behavior and are expected to take appropriate and fair corrective action in 43 | response to any instances of unacceptable behavior. 44 | 45 | Project maintainers have the right and responsibility to remove, edit, or 46 | reject comments, commits, code, wiki edits, issues, and other contributions 47 | that are not aligned to this Code of Conduct, or to ban temporarily or 48 | permanently any contributor for other behaviors that they deem inappropriate, 49 | threatening, offensive, or harmful. 50 | 51 | Scope 52 | ----- 53 | 54 | This Code of Conduct applies both within project spaces and in public spaces 55 | when an individual is representing the project or its community. Examples of 56 | representing a project or community include using an official project e-mail 57 | address, posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. Representation of a project may be 59 | further defined and clarified by project maintainers. 60 | 61 | Enforcement 62 | ----------- 63 | 64 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 65 | reported by contacting the project team at the issue tracker. All 66 | complaints will be reviewed and investigated and will result in a response that 67 | is deemed necessary and appropriate to the circumstances. The project team is 68 | obligated to maintain confidentiality with regard to the reporter of an incident. 69 | Further details of specific enforcement policies may be posted separately. 70 | 71 | Project maintainers who do not follow or enforce the Code of Conduct in good 72 | faith may face temporary or permanent repercussions as determined by other 73 | members of the project's leadership. 74 | 75 | Attribution 76 | ----------- 77 | 78 | This Code of Conduct is adapted from the `Contributor Covenant `_, `version 1.4 `_, 79 | available at https://www.contributor-covenant.org/version/1/4/. 80 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Mariela Perignon 4 | Copyright (c) 2020 The DeltaRCM Team 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include pyDeltaRCM *.yml 2 | exclude *.yml 3 | recursive-include tests/ *.py *.png 4 | recursive-include docs/source/ * 5 | recursive-exclude docs/source/_autosummary * 6 | recursive-exclude docs/source/_resources/joss * 7 | global-exclude *.nc *.log -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ************** 2 | pyDeltaRCM 3 | ************** 4 | 5 | .. image:: https://badge.fury.io/py/pyDeltaRCM.svg 6 | :target: https://badge.fury.io/py/pyDeltaRCM 7 | 8 | .. image:: https://joss.theoj.org/papers/10.21105/joss.03398/status.svg 9 | :target: https://doi.org/10.21105/joss.03398 10 | 11 | .. image:: https://github.com/DeltaRCM/pyDeltaRCM/actions/workflows/build.yml/badge.svg 12 | :target: https://github.com/DeltaRCM/pyDeltaRCM/actions 13 | 14 | .. image:: https://codecov.io/gh/DeltaRCM/pyDeltaRCM/branch/develop/graph/badge.svg 15 | :target: https://codecov.io/gh/DeltaRCM/pyDeltaRCM 16 | 17 | .. image:: https://app.codacy.com/project/badge/Grade/1c137d0227914741a9ba09f0b00a49a7 18 | :target: https://app.codacy.com/gh/DeltaRCM/pyDeltaRCM/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade 19 | 20 | 21 | 22 | 23 | *pyDeltaRCM* is a computationally efficient, free and open source, and easy-to-customize numerical delta model based on the original DeltaRCM model design (`Matlab deltaRCM `_ model by Man Liang; `Liang et al., 2015 `_). 24 | *pyDeltaRCM* delivers improved model stability and capabilities, infrastructure to support exploration with minimal boilerplate code, and establishes an approach to extending model capabilities that ensures reproducible and comparable studies. 25 | 26 | 27 | .. figure:: https://deltarcm.org/pyDeltaRCM/_images/cover.png 28 | 29 | Weighted random walks for 20 water parcels, in a *pyDeltaRCM* model run with default parameters. 30 | 31 | 32 | Documentation 33 | ############# 34 | 35 | `Find the complete documentation here `_. 36 | 37 | Documentation includes an `installation guide `_, a thorough `guide for users `_, detailed `API documentation for developers `_, a `plethora of examples `_ to use and develop pyDeltaRCM in novel scientific experiments, and more! 38 | 39 | 40 | Installation 41 | ############ 42 | 43 | See our complete `installation guide `_, especially if you are a developer planning to modify or contribute code (`developer installation guide `_), or if you are new to managing Python `venv` or `conda` environments. 44 | 45 | For a quick installation into an existing Python 3.x environment: 46 | 47 | .. code:: console 48 | 49 | $ pip install pyDeltaRCM 50 | 51 | 52 | Executing the model 53 | ################### 54 | 55 | We recommend you check out our `pyDeltaRCM in 10 minutes tutorial `_, which is part of our documentation. 56 | 57 | Beyond that brief tutorial, we have a comprehensive `User Documentation `_ and `Developer Documentation `_ to check out. 58 | 59 | 60 | Citing pyDeltaRCM 61 | ################# 62 | 63 | When citing *pyDeltaRCM*, please cite the `JOSS paper `_: 64 | 65 | Moodie et al., (2021). pyDeltaRCM: a flexible numerical delta model. Journal of Open Source Software, 6(64), 3398, https://doi.org/10.21105/joss.03398 66 | 67 | If you use BibTeX, you can add *pyDeltaRCM* to your `.bib` file using the following code: 68 | 69 | .. code:: console 70 | 71 | @article{Moodie2021, 72 | doi = {10.21105/joss.03398}, 73 | url = {https://doi.org/10.21105/joss.03398}, 74 | year = {2021}, 75 | publisher = {The Open Journal}, 76 | volume = {6}, 77 | number = {64}, 78 | pages = {3398}, 79 | author = {Andrew J. Moodie and Jayaram Hariharan and Eric Barefoot and Paola Passalacqua}, 80 | title = {*pyDeltaRCM*: a flexible numerical delta model}, 81 | journal = {Journal of Open Source Software} 82 | } 83 | 84 | 85 | Additional notes 86 | ################ 87 | 88 | This repository no longer includes the `Basic Model Interface (BMI) `_ wrapper to the DeltaRCM model. 89 | *pyDeltaRCM* maintains BMI compatibility through another repository (`the BMI_pyDeltaRCM model `_). 90 | -------------------------------------------------------------------------------- /assets/private/liang_2015_fig1fig2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/assets/private/liang_2015_fig1fig2.png -------------------------------------------------------------------------------- /assets/private/liang_2015_fig5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/assets/private/liang_2015_fig5.png -------------------------------------------------------------------------------- /assets/private/pyDeltaRCM_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 46 | 48 | 49 | 51 | image/svg+xml 52 | 54 | 55 | 56 | 57 | 58 | 63 | 68 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /assets/symbol.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help docs Makefile 16 | 17 | 18 | docs: test clean html 19 | 20 | 21 | clean : 22 | rm -rf source/api/ 23 | rm -rf source/_autosummary/ 24 | rm -rf ./build/ 25 | 26 | 27 | test : clean 28 | @$(SPHINXBUILD) -b doctest "$(SOURCEDIR)" "$(BUILDDIR)" -E 29 | @$(SPHINXBUILD) -b linkcheck "$(SOURCEDIR)" "$(BUILDDIR)" -E 30 | 31 | 32 | # Catch-all target: route all unknown targets to Sphinx using the new 33 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 34 | %: Makefile 35 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 36 | 37 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/docs/source/.nojekyll -------------------------------------------------------------------------------- /docs/source/_resources/checkpoint.yaml: -------------------------------------------------------------------------------- 1 | out_dir: 'checkpoint' 2 | seed: 451220118313 3 | save_checkpoint: True 4 | timesteps: 2000 5 | -------------------------------------------------------------------------------- /docs/source/_resources/checkpoint/checkpoint.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/docs/source/_resources/checkpoint/checkpoint.npz -------------------------------------------------------------------------------- /docs/source/_resources/joss/figures/figures.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import matplotlib 4 | 5 | import os 6 | import sys 7 | 8 | import pyDeltaRCM 9 | from pyDeltaRCM.shared_tools import sec_in_day, day_in_yr 10 | 11 | import netCDF4 as nc 12 | from typing import List 13 | 14 | # everything relative to this file 15 | _dir: str = os.path.realpath(os.path.dirname(__file__)) 16 | 17 | 18 | if __name__ == '__main__': 19 | 20 | # get script input argument 21 | _arg: List[str] = sys.argv 22 | if len(_arg) == 3: 23 | _input_flag: str = sys.argv[1].strip('-') 24 | elif len(_arg) == 2: 25 | _input_flag: str = sys.argv[1].strip('-') 26 | else: 27 | raise ValueError('No arguments supplied.') 28 | 29 | # parameter choices for scaling 30 | If: float = 10 / day_in_yr # intermittency factor for year-scaling 31 | 32 | # if running the computation 33 | if _input_flag == 'compute': 34 | 35 | _mdl = pyDeltaRCM.DeltaModel( 36 | out_dir=_dir, 37 | seed=10151919, # JOSS, A1Z26 encoded 38 | save_eta_grids=True, 39 | save_dt=sec_in_day) 40 | 41 | for i in range(4000): 42 | _mdl.update() 43 | 44 | # finalize 45 | _mdl.finalize() 46 | 47 | # if running the plotting 48 | elif _input_flag == 'plot': 49 | 50 | # set up attributes needed for plotting 51 | H_SL, h, n = 0, 4, 0.3 # sea level, basin depth, surf relief 52 | blues = matplotlib.cm.get_cmap('Blues_r', 64) 53 | greens = matplotlib.cm.get_cmap('YlGn_r', 64) 54 | combined = np.vstack((blues(np.linspace(0.1, 0.7, 5)), 55 | greens(np.linspace(0.2, 0.8, 5)))) 56 | cmap = matplotlib.colors.ListedColormap(combined, name='delta') 57 | bounds = np.hstack( 58 | (np.linspace(H_SL-h, H_SL-(n/2), 5), 59 | np.linspace(H_SL, H_SL+n, 6))) 60 | norm = matplotlib.colors.BoundaryNorm(bounds, len(bounds)-1) 61 | 62 | data = nc.Dataset(os.path.join(_dir, 'pyDeltaRCM_output.nc')) 63 | 64 | nt = 4 65 | ts = np.linspace(0, data['eta'].shape[0]-1, 66 | num=nt, dtype=int) # linearly interpolate ts 67 | 68 | # make the timeseries plot 69 | fig, ax = plt.subplots(1, nt, figsize=(11, 2), dpi=300) 70 | for i, t in enumerate(ts): 71 | ax[i].imshow(data['eta'][t, :, :], cmap=cmap, norm=norm) 72 | _time = pyDeltaRCM.shared_tools.scale_model_time( 73 | data['time'][t], If=If, units='years') 74 | ax[i].set_title(' '.join(( 75 | str(np.round(_time, 1)), 76 | 'years'))) 77 | ax[i].axes.get_xaxis().set_ticks([]) 78 | ax[i].axes.get_yaxis().set_ticks([]) 79 | 80 | # plt.show() 81 | plt.tight_layout() 82 | plt.savefig(os.path.join(_dir, 'timeseries.png'), transparent=True) 83 | 84 | # otherwise 85 | else: 86 | raise ValueError('Invalid argument supplied.') 87 | -------------------------------------------------------------------------------- /docs/source/_resources/joss/figures/timeseries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/docs/source/_resources/joss/figures/timeseries.png -------------------------------------------------------------------------------- /docs/source/_resources/joss/paper.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '*pyDeltaRCM*: a flexible numerical delta model' 3 | tags: 4 | - Python 5 | - sedimentology 6 | - deltas 7 | - stratigraphy 8 | authors: 9 | - name: Andrew J. Moodie 10 | orcid: 0000-0002-6745-036X 11 | affiliation: "1" 12 | - name: Jayaram Hariharan 13 | orcid: 0000-0002-1343-193X 14 | affiliation: "1" 15 | - name: Eric Barefoot 16 | orcid: 0000-0001-5770-2116 17 | affiliation: "2" 18 | - name: Paola Passalacqua 19 | affiliation: "1" 20 | orcid: 0000-0002-4763-7231 21 | affiliations: 22 | - name: Department of Civil, Architectural, and Environmental Engineering, University of Texas at Austin, Austin, TX, USA 23 | index: 1 24 | - name: Department of Earth, Environmental and Planetary Sciences, Rice University, Houston, TX, USA 25 | index: 2 26 | date: 08 June 2021 27 | bibliography: paper.bib 28 | --- 29 | 30 | # Summary 31 | 32 | River deltas provide many societal benefits, and sustainability of these landforms may be impacted by human modification and global climate change. 33 | Reduced-complexity numerical delta models incorporate limited physical processes, allowing researchers to assess the spatiotemporal evolution of landscape response to individual processes and environmental forcings. 34 | Isolating individual processes is useful to understand, for example, shifting delta morphology due to sea-level rise, changing vegetal cover, or flooding intensity. 35 | As a result, many numerical delta models have been proposed in the literature, and results from these studies are difficult to compare because of various design and implementation choices. 36 | *pyDeltaRCM* (`v2.0`) delivers a computationally efficient and easy-to-customize implementation of the DeltaRCM numerical model [@liang_reduced_1_2015], enabling comparison and reproducibility in studies of delta change due to various environmental forcings. 37 | 38 | 39 | # Statement of need 40 | 41 | River deltas are societally important landforms because they provide arable land, deep inland ports, and are home to hundreds of millions of people globally [@edmonds_coastal_2020]. 42 | Existing at the interface between landmasses and water bodies, deltas are impacted by a multitude of processes arising in both of these domains. 43 | For example, changes in sediment input to the delta modulate the rate at which new land is built; similarly, rising water levels in the downstream basin create flooded land. 44 | In addition to natural processes, human landscape modification renders deltaic environments more sensitive to global climate change into the future [@paola_natural_2011]. 45 | Demand to understand natural delta processes, and how these processes will respond to various environmental forcings, has led to a proliferation of numerical delta models in the literature [@overeem_three_2005]. 46 | 47 | The DeltaRCM delta model [@liang_reduced_1_2015] has gained popularity among geomorphologists due to an attractive balance of computational cost, realism, and interpretability [@larsen_appropriate_2016]. 48 | For example, studies have employed the DeltaRCM design to examine delta morphology and dynamism response to sea-level rise and regional subsidence [@liang_quantifying_2016; @liang_how_2016], as well as extended model design to simulate delta evolution with vegetation [@lauzon_comparing_2018] and ice and permafrost [@lauzon_ice_2019; @piliouras_unraveling_2021]. 49 | However, comparison among these studies is difficult, owing to disparate code bases, various implementation choices, lack of version control, and proprietary software dependencies. 50 | 51 | 52 | # Background 53 | 54 | Here, version 2.0 of *pyDeltaRCM* is introduced; *pyDeltaRCM* is a computationally efficient, free and open source, and easy-to-customize numerical delta model based on the original DeltaRCM design. 55 | The original DeltaRCM framework is inspired by well-understood physical phenomena, and models mass movement as a probabilistic weighted random-walk process coupled with a set of hierarchical rules; the model is extensively described in @liang_reduced_1_2015 and @liang_reduced_2_2015. 56 | 57 | This same framework is the basis for *pyDeltaRCM* v2.0, with a few modifications selected only to resolve known numerical instabilities, improve computational efficiency, and support reproducible simulations. 58 | *PyDeltaRCM* depends only on common Python packages `numpy` [@harris2020], `matplotlib` [@hunter2007], `scipy` [@virtanen2020], `netCDF4`, `pyyaml`, and `numba` [@lam_numba_2015]. 59 | 60 | ![Simulation with *pyDeltaRCM* v2.0, default parameter set, and random `seed: 10151919`. Simulation was run for 4000 timesteps, and assumes 10 days of bankfull discharge per year; computational time was \~2 hours. \label{fig:timeseries}](figures/timeseries.png) 61 | 62 | 63 | # Flexible and easy to use 64 | 65 | *pyDeltaRCM* is an object-oriented package, providing the central model class `DeltaModel`. 66 | By creating custom model behavior as subclasses of `DeltaModel`, researchers can easily add, subtract, and modify model components without altering code that is not pertinent to the science objective. 67 | Importantly, separating custom code from core model code makes clear how different studies can be compared. 68 | The *pyDeltaRCM* documentation provides several examples for how to implement custom model behavior on top of the core `DeltaModel` object. 69 | 70 | *pyDeltaRCM* also provides infrastructure to accelerate scientific exploration, such as the ability to configure multiple simulations from a single file. 71 | Additionally, a preprocessor orchestrates `parallel` simulations for multi-core systems (optionally), and implements several tools to support simulations exploring a parameter space. 72 | For example, `matrix` expansion converts lists of parameters into an n-dimensional set of simulations. 73 | Similarly, replicate simulations can be created via an `ensemble` specification. 74 | 75 | Reproducibility and computational efficiency were important priorities in *pyDeltaRCM* development. 76 | For example, to-disk logging records all parameters, system-level and version data, and random-seed information to ensure that all runs can be recreated. 77 | Additionally, "checkpoint" infrastructure has been added to the model, which records simulation progress during computation and can later resume model runs for further simulation. 78 | Finally, *pyDeltaRCM* uses `numba` for computational optimization [@lam_numba_2015], and does not depend on any proprietary software. 79 | 80 | *pyDeltaRCM* component units and integrations are thoroughly documented and tested. 81 | Component-level documentation describes implementation notes, whereas narratives in "Guide" and "Example" documentation describes high-level model design and best practices for model use and development. 82 | *pyDeltaRCM* also couples with other numerical models via the CSDMS Basic Model Interface 2.0 [@hutton_basic_2020; @BMI_pyDeltaRCM]. 83 | 84 | 85 | # Acknowledgments 86 | 87 | We gratefully acknowledge Rebecca Lauzon and Mariela Perignon for developing an implementation of *DeltaRCM* in Python that was the basis for *pyDeltaRCM*. 88 | We also thank the National Science Foundation for supporting us in developing this software, by way of a Postdoctoral Fellowship to A.M. (EAR 1952772) and a grant to J.H. and P.P. (EAR 1719670). 89 | 90 | 91 | # References -------------------------------------------------------------------------------- /docs/source/_static/style.css: -------------------------------------------------------------------------------- 1 | @import url("default.css"); /* make sure to sync this with the base theme's css filename */ 2 | 3 | /*:root { 4 | --main-bg-color: DarkGreen; 5 | --url-color: Brown; 6 | --url-color-hover: Coral; 7 | --sidebar-box-bg-color: DarkOrange; 8 | --sidebar-border-color: Black; 9 | }*/ 10 | 11 | :root { 12 | --main-bg-color: #f2f2f2; 13 | --h1-color: #93776C; 14 | --hplus-color: black; 15 | --url-color: #D8925D; 16 | --url-color-hover: #9BAF9B; 17 | --sidebar-box-bg-color: #B3CF89; 18 | --sidebar-border-color: Black; 19 | --footer-bg-color: #B3CF89; 20 | } 21 | 22 | 23 | body { 24 | background-color: var(--main-bg-color); 25 | } 26 | 27 | h1 { 28 | margin: 0; 29 | padding: 0.7em 0 0.3em 0; 30 | font-size: 1.5em; 31 | color: var(--h1-color); 32 | } 33 | 34 | div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { 35 | color: var(--hplus-color)!important; 36 | } 37 | 38 | a { 39 | color: var(--url-color); 40 | text-decoration: none; 41 | } 42 | 43 | a:hover { 44 | color: var(--url-color-hover); 45 | } 46 | 47 | a code { 48 | border: 0; 49 | color: var(--url-color); 50 | } 51 | 52 | a code:hover { 53 | color: var(--url-color-hover); 54 | } 55 | 56 | a.headerlink { 57 | color: PeachPuff!important; 58 | font-size: 1em; 59 | margin-left: 6px; 60 | padding: 0 4px 0 4px; 61 | text-decoration: none!important; 62 | } 63 | 64 | div.related ul li a { 65 | margin: 0; 66 | padding: 0 5px 0 5px; 67 | line-height: 1.75em; 68 | color: var(--url-color); 69 | } 70 | 71 | div.related ul li a:hover { 72 | color: var(--url-color-hover); 73 | } 74 | 75 | div.sphinxsidebar h3, div.sphinxsidebar h4 { 76 | color: white; 77 | border: 1px solid var(--sidebar-border-color); 78 | background-color: var(--sidebar-box-bg-color); 79 | } 80 | 81 | div.sphinxsidebar input { 82 | border: 1px solid var(--sidebar-border-color); 83 | } 84 | 85 | pre { 86 | font-family: 'Consolas', 'Deja Vu Sans Mono', 87 | 'Bitstream Vera Sans Mono', monospace; 88 | font-size: 0.95em; 89 | letter-spacing: 0.015em; 90 | line-height: 120%; 91 | padding: 0.5em; 92 | border: 1px solid #ccc; 93 | background-color: #eaece5; 94 | } 95 | 96 | pre span gp { 97 | color: red; 98 | } 99 | 100 | div.footer { 101 | background-color: var(--footer-bg-color); 102 | color: #969696; 103 | padding: 3px 8px 3px 0; 104 | clear: both; 105 | font-size: 0.8em; 106 | text-align: right; 107 | } 108 | 109 | div.footer a { 110 | color: #969696; 111 | text-decoration: underline; 112 | } -------------------------------------------------------------------------------- /docs/source/_templates/page.html: -------------------------------------------------------------------------------- 1 | {% extends "!page.html" %} 2 | 3 | {% set css_files = css_files + ["_static/style.css"] %} 4 | 5 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | 16 | import pyDeltaRCM 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'pyDeltaRCM' 21 | copyright = '2020, The DeltaRCM Team' 22 | author = 'The DeltaRCM Team' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = pyDeltaRCM.__version__ 26 | version = pyDeltaRCM.__version__ 27 | 28 | 29 | # -- General configuration --------------------------------------------------- 30 | 31 | # Add any Sphinx extension module names here, as strings. They can be 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 33 | # ones. 34 | extensions = ['sphinx.ext.autodoc', 35 | 'sphinx.ext.doctest', 36 | 'sphinx.ext.autosummary', 37 | 'sphinx.ext.napoleon', 38 | 'sphinx.ext.graphviz', 39 | 'sphinx.ext.mathjax', 40 | 'sphinx.ext.githubpages', 41 | 'matplotlib.sphinxext.plot_directive', 42 | 'sphinx.ext.todo'] 43 | 44 | # Add any paths that contain templates here, relative to this directory. 45 | templates_path = ['_templates'] 46 | 47 | # toggle todo items 48 | todo_include_todos = True 49 | 50 | # List of patterns, relative to source directory, that match files and 51 | # directories to ignore when looking for source files. 52 | # This pattern also affects html_static_path and html_extra_path. 53 | exclude_patterns = [] 54 | 55 | # Napoleon settings 56 | napoleon_google_docstring = False 57 | napoleon_numpy_docstring = True 58 | napoleon_include_init_with_doc = False 59 | napoleon_include_private_with_doc = False 60 | napoleon_include_special_with_doc = True 61 | napoleon_use_admonition_for_examples = False 62 | napoleon_use_admonition_for_notes = False 63 | napoleon_use_admonition_for_references = False 64 | napoleon_use_ivar = False 65 | napoleon_use_param = True 66 | napoleon_use_rtype = True 67 | 68 | # Autosummary / Automodapi settings 69 | autosummary_generate = True 70 | automodapi_inheritance_diagram = False 71 | autodoc_default_options = {'members': True, 'inherited-members': False, 72 | 'private-members': True} 73 | 74 | # doctest 75 | doctest_global_setup = ''' 76 | import pyDeltaRCM 77 | import numpy as np 78 | from matplotlib import pyplot as plt 79 | ''' 80 | doctest_test_doctest_blocks = '' # empty string disables testing all code in any docstring 81 | 82 | ## mpl plots 83 | plot_basedir = 'pyplots' 84 | plot_html_show_source_link = False 85 | plot_formats = ['png', ('hires.png', 300)] 86 | plot_pre_code = ''' 87 | import numpy as np 88 | from matplotlib import pyplot as plt 89 | import pyDeltaRCM 90 | ''' 91 | 92 | 93 | # img math 94 | # imgmath_latex_preamble = '\\usepackage{fouriernc}' # newtxsf, mathptmx 95 | 96 | # -- Options for HTML output ------------------------------------------------- 97 | 98 | # The theme to use for HTML and HTML Help pages. See the documentation for 99 | # a list of builtin themes. 100 | # 101 | html_theme = 'sphinxdoc' 102 | 103 | # Add any paths that contain custom static files (such as style sheets) here, 104 | # relative to this directory. They are copied after the builtin static files, 105 | # so a file named "default.css" will overwrite the builtin "default.css". 106 | html_static_path = ['_static'] 107 | # html_static_path = [] 108 | 109 | # -- Options for linkcheck ------------------------------------------- 110 | 111 | # Some DOI links throw 403 errors but when checked they work fine 112 | linkcheck_ignore = [ 113 | r'https://doi.org/10.1029/2021GL095053', 114 | r'https://doi.org/10.1029/2018GL079405', 115 | r'https://doi.org/10.1029/2022JF006762', 116 | r'https://doi.org/10.1086/626637' 117 | ] -------------------------------------------------------------------------------- /docs/source/examples/basic_runs.rst: -------------------------------------------------------------------------------- 1 | Basic script to run the model 2 | ============================= 3 | 4 | .. plot:: 5 | :context: reset 6 | 7 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 8 | delta = pyDeltaRCM.DeltaModel( 9 | out_dir=output_dir, 10 | resume_checkpoint='../_resources/checkpoint') 11 | delta.finalize() 12 | 13 | 14 | .. code:: 15 | 16 | delta = pyDeltaRCM.DeltaModel() 17 | 18 | for _t in range(0, 1000): 19 | delta.update() 20 | 21 | delta.finalize() 22 | 23 | .. plot:: 24 | :context: 25 | :include-source: 26 | 27 | fig, ax = plt.subplots() 28 | ax.imshow(delta.eta) 29 | plt.show() 30 | -------------------------------------------------------------------------------- /docs/source/examples/custom_class_preprocessor.rst: -------------------------------------------------------------------------------- 1 | Using custom classes with the Preprocessor 2 | ========================================== 3 | 4 | Here, we set up three jobs to run as an ensemble of a single custom class. 5 | 6 | 7 | .. plot:: 8 | :context: reset 9 | :include-source: 10 | 11 | >>> import numpy as np 12 | >>> import matplotlib.pyplot as plt 13 | 14 | >>> import pyDeltaRCM 15 | 16 | >>> class CustomRandomModel(pyDeltaRCM.DeltaModel): 17 | ... """ 18 | ... A subclass of DeltaModel that runs fast for this example. 19 | ... 20 | ... Just for the sake of this example, we are implementing a 21 | ... custom class that runs very quickly. We override the 22 | ... `solve_water_and_sediment_timestep` method of the model to 23 | ... simply add random gaussian blobs to the surface on each step. 24 | ... """ 25 | ... def __init__(self, input_file=None, **kwargs): 26 | ... 27 | ... # inherit base DeltaModel methods 28 | ... super().__init__(input_file, **kwargs) 29 | ... 30 | ... self.noise_patch = int(25) 31 | ... self.noise_size = 5 # x y scale 32 | ... self.noise_scale = 200 # z scale 33 | ... self._half_ns = self.noise_patch // 2 34 | ... self.noise_x, self.noise_y = np.meshgrid( 35 | ... np.linspace(-self._half_ns, self._half_ns, num=self.noise_patch), 36 | ... np.linspace(-self._half_ns, self._half_ns, num=self.noise_patch)) 37 | ... 38 | ... def solve_water_and_sediment_timestep(self): 39 | ... """Overwrite method for documentation demonstration. 40 | ... 41 | ... This method now simply adds random gaussian noise on each step. 42 | ... """ 43 | ... # get a random x and y value 44 | ... # important: use get_random_uniform for reproducibility! 45 | ... x, y, z = [pyDeltaRCM.shared_tools.get_random_uniform(1) for _ in range(3)] 46 | ... 47 | ... # rescale to fit inside domain 48 | ... x = int(x * (self.L - self.noise_patch)) 49 | ... y = int(y * (self.W - self.noise_patch)) 50 | ... 51 | ... # generate the blob 52 | ... sx = sy = self.noise_size 53 | ... exp = np.exp(-((self.noise_x)**2. / (2. * sx**2.) + (self.noise_y)**2. / (2. * sy**2.))) 54 | ... blob = (1. / (2. * np.pi * sx * sy) * exp * self.noise_scale) 55 | ... 56 | ... # place into domain 57 | ... self.eta[x:x+self.noise_patch, y:y+self.noise_patch] += blob 58 | 59 | 60 | Then, we pass this custom subclass to the :obj:`~pyDeltaRCM.preprocessor.Preprocessor.run_jobs` method. 61 | 62 | .. plot:: 63 | :context: 64 | 65 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 66 | param_dict = dict( 67 | out_dir=output_dir, 68 | ensemble=3, 69 | timesteps=50 70 | ) 71 | 72 | # let the preprocessor set up the jobs for you from checkpoint 73 | pp = pyDeltaRCM.Preprocessor( 74 | param_dict) 75 | 76 | # run the jobs 77 | pp.run_jobs(DeltaModel=CustomRandomModel) 78 | 79 | .. code:: 80 | 81 | >>> # set up dictionary for parameters and create a `Preprocessor` 82 | >>> param_dict = dict( 83 | ... ensemble=3, 84 | ... timesteps=50 85 | ... ) 86 | 87 | >>> # preprocessor set up the jobs 88 | >>> pp = pyDeltaRCM.Preprocessor( 89 | ... param_dict) 90 | 91 | >>> # run the jobs with custom class! 92 | >>> pp.run_jobs(DeltaModel=CustomRandomModel) 93 | 94 | .. plot:: 95 | :context: 96 | :include-source: 97 | 98 | >>> fig, ax = plt.subplots( 99 | ... 1, len(pp.job_list), 100 | ... figsize=(12, 4.8)) 101 | >>> for i in range(len(pp.job_list)): 102 | ... ax[i].imshow(pp.job_list[i].deltamodel.eta) 103 | >>> plt.tight_layout() 104 | >>> plt.show() 105 | -------------------------------------------------------------------------------- /docs/source/examples/custom_saving.rst: -------------------------------------------------------------------------------- 1 | Saving custom fields to the output file 2 | ======================================= 3 | 4 | Given the flexibility of the pyDeltaRCM model to modifications via hooks and subclassing, it is necessary that the variables saved to the output netCDF file are similarly customizable. 5 | Fortunately, the use of subclasses and hooks itself enables flexible setting of gridded variables to be saved as figures, as well as customization of the fields saved to the netCDF file as both variables, and as metadata. 6 | 7 | To customize the figures and variables that are saved, the hook ``hook_init_output_file`` should be used to subclass the pyDeltaRCM model. 8 | 9 | When adding a model attribute to the key-value pairs of grids to save as figures, the key indicates the name of the figure file that will be saved, and the value-pair can be a string representing the model attribute to be plotted, or a combination of model attributes, such as ``self.eta * self.depth``. 10 | For example, ``self._save_fig_list['active_layer'] = ['active_layer']`` will properly indicate that figures of the active layer should be saved. 11 | 12 | .. important:: 13 | 14 | The built-in, on-the-fly, figure saving as the model runs is only supported for gridded variables with the shape ``L x W`` matching the model domain. 15 | Trying to set up figures to save that are not variables of that shape will result in an error. 16 | 17 | When adding variables or metadata to be initialized and subsequently saved in the output netCDF, the key-value pair relationship is as follows. 18 | The key added to ``self._save_var_list`` is the name of the variable as it will be recorded in the netCDF file, this *does not* have to correspond to the name of an attribute in the model. 19 | To add a variable to the metadata, a key must be added to ``self._save_var_list['meta']``. 20 | The expected value for a given key is a list containing strings indicating the model attribute to be saved, its units, the variable type, and lastly the variable dimensions (e.g., ``['active_layer', 'fraction', 'f4', ('time', 'x', 'y')]`` for the active layer). 21 | 22 | .. important:: 23 | 24 | The dimensions of the custom variable being specified must match *exactly* with one of the three standard dimensions: `x`, `y`, `time`. 25 | Use of an invalid dimension will result in an error. 26 | 27 | An example of using the hook and creating a model subclass to customize the figures, gridded variables, and metadata being saved is provided below. 28 | 29 | .. doctest:: 30 | 31 | >>> import pyDeltaRCM 32 | 33 | >>> class CustomSaveModel(pyDeltaRCM.DeltaModel): 34 | ... """A subclass of DeltaModel to save custom figures and variables. 35 | ... 36 | ... This subclass modifies the list of variables and figures used to 37 | ... initialize the netCDF file and save figures and grids before the 38 | ... output file is setup and initial conditions are plotted. 39 | ... """ 40 | ... def __init__(self, input_file=None, **kwargs): 41 | ... 42 | ... # inherit base DeltaModel methods 43 | ... super().__init__(input_file, **kwargs) 44 | ... 45 | ... def hook_init_output_file(self): 46 | ... """Add non-standard grids, figures and metadata to be saved.""" 47 | ... # save a figure of the active layer each save_dt 48 | ... self._save_fig_list['active_layer'] = ['active_layer'] 49 | ... 50 | ... # save the active layer grid each save_dt w/ a short name 51 | ... self._save_var_list['actlay'] = ['active_layer', 'fraction', 52 | ... 'f4', ('time', 53 | ... 'x', 'y')] 54 | ... 55 | ... # save number of water parcels w/ a long name 56 | ... self._save_var_list['meta']['water_parcels'] = ['Np_water', 57 | ... 'parcels', 58 | ... 'i8', ()] 59 | 60 | Next, we instantiate the model class. 61 | 62 | .. code:: 63 | 64 | >>> mdl = CustomSaveModel() 65 | 66 | 67 | .. doctest:: 68 | :hide: 69 | 70 | >>> with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 71 | ... mdl = CustomSaveModel(out_dir=output_dir) 72 | 73 | 74 | This subclass has added the active layer as a figure and a grid to be saved, as well as the number of water parcels as metadata to be saved. 75 | For simplicity we will just check that the appropriate parameters were added to the save figure and save variable lists, however please feel free to give this example a try on your local machine and examine the output figures and netCDF file. 76 | 77 | .. doctest:: 78 | 79 | >>> 'active_layer' in mdl._save_fig_list 80 | True 81 | 82 | >>> print(mdl._save_fig_list) 83 | {'active_layer': ['active_layer']} 84 | 85 | >>> print(mdl._save_var_list) 86 | {'meta': {'water_parcels': ['Np_water', 'parcels', 'i8', ()]}, 'actlay': ['active_layer', 'fraction', 'f4', ('time', 'x', 'y')]} 87 | -------------------------------------------------------------------------------- /docs/source/examples/custom_yaml.rst: -------------------------------------------------------------------------------- 1 | Defining custom YAML parameters 2 | =============================== 3 | 4 | .. currentmodule:: pyDeltaRCM.hook_tools 5 | 6 | Custom subclasses for the standard ``DeltaModel`` may require additional or custom parameters not listed in the :doc:`/reference/model/yaml_defaults`. 7 | By using the hook, :obj:`~hook_tools.hook_import_files`, it is straightforward to define custom YAML parameters along with expected types and default values for your subclassed model. 8 | 9 | The following subclass model demonstrates this by defining a custom boolean parameter (could be used to toggle some custom functionality on/off), and a custom numeric parameter (could be required for the custom function). 10 | 11 | .. doctest:: 12 | 13 | >>> import pyDeltaRCM 14 | 15 | >>> class CustomParamsModel(pyDeltaRCM.DeltaModel): 16 | ... """A subclass of DeltaModel with custom YAML parameters. 17 | ... 18 | ... This subclass defines custom YAML parameters, their expected types 19 | ... and default values. 20 | ... """ 21 | ... def __init__(self, input_file=None, **kwargs): 22 | ... 23 | ... # inherit base DeltaModel methods 24 | ... super().__init__(input_file, **kwargs) 25 | ... 26 | ... def hook_import_files(self): 27 | ... """Define the custom YAML parameters.""" 28 | ... # custom boolean parameter 29 | ... self.subclass_parameters['custom_bool'] = { 30 | ... 'type': 'bool', 'default': False 31 | ... } 32 | ... 33 | ... # custom numeric parameter 34 | ... self.subclass_parameters['custom_number'] = { 35 | ... 'type': ['int', 'float'], 'default': 0 36 | ... } 37 | 38 | If the subclass model is loaded with a YAML configuration file that does not explicitly define these custom parameters, then the default values will be assigned as model attributes. 39 | 40 | .. code:: 41 | 42 | >>> defaults = CustomParamsModel() 43 | 44 | .. doctest:: 45 | :hide: 46 | 47 | >>> with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 48 | ... defaults = CustomParamsModel(out_dir=output_dir) 49 | 50 | .. doctest:: 51 | 52 | >>> print(defaults.custom_bool) 53 | False 54 | 55 | >>> print(defaults.custom_number) 56 | 0 57 | 58 | .. note:: 59 | 60 | Since custom YAML parameters have expected types, ``TypeErrors`` are raised if the custom parameter type provided in the YAML does not agree with what is expected as defined in the subclass. 61 | 62 | 63 | Once the custom parameters have been defined in the subclassed model they can be treated just like the default model parameters, and can be specified in the YAML or as keyword arguments (``**kwargs``). 64 | 65 | .. code:: 66 | 67 | >>> customized = CustomParamsModel(custom_bool=True, custom_number=15.3) 68 | 69 | 70 | .. doctest:: 71 | :hide: 72 | 73 | >>> with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 74 | ... customized = CustomParamsModel(out_dir=output_dir, 75 | ... custom_bool=True, 76 | ... custom_number=15.3) 77 | 78 | .. doctest:: 79 | 80 | >>> print(customized.custom_bool) 81 | True 82 | 83 | >>> print(customized.custom_number) 84 | 15.3 85 | -------------------------------------------------------------------------------- /docs/source/examples/index.rst: -------------------------------------------------------------------------------- 1 | ============================================= 2 | Examples of using and working with pyDeltaRCM 3 | ============================================= 4 | 5 | Running the model 6 | ----------------- 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | basic_runs 12 | resume_from_checkpoint 13 | 14 | 15 | Modifying initial conditions 16 | ---------------------------- 17 | 18 | .. toctree:: 19 | :maxdepth: 1 20 | 21 | slight_slope 22 | 23 | 24 | Modifying boundary conditions 25 | ----------------------------- 26 | 27 | .. toctree:: 28 | :maxdepth: 1 29 | 30 | updating_boundary_conditions 31 | subsidence_region 32 | variable_bedload 33 | variable_velocity 34 | 35 | 36 | Modifying internal computations 37 | ------------------------------- 38 | 39 | .. toctree:: 40 | :maxdepth: 1 41 | 42 | overwrite_topo_diffusion 43 | 44 | 45 | Modifying Model Input/Output 46 | ---------------------------- 47 | 48 | .. toctree:: 49 | :maxdepth: 1 50 | 51 | custom_yaml 52 | custom_saving 53 | 54 | 55 | Working with the Preprocessor 56 | ----------------------------- 57 | 58 | .. toctree:: 59 | :maxdepth: 1 60 | 61 | custom_class_preprocessor 62 | -------------------------------------------------------------------------------- /docs/source/examples/modelzoo.rst: -------------------------------------------------------------------------------- 1 | Customized Applications of *pyDeltaRCM* 2 | ======================================= 3 | 4 | Below is a "model zoo" containing a list with links to customized subclasses 5 | of the *pyDeltaRCM* found "in the wild". If you have a implemented a custom 6 | subclass of the model and would like us to highlight it here please reach out 7 | or open a pull request! 8 | 9 | VegetationModel 10 | --------------- 11 | Link: `VegetationModel `_ 12 | 13 | This implementation of the *pyDeltaRCM* model is based off of the "DeltaRCM 14 | Vegetation" model presented in `Lauzon and Murray (2018) `_. 15 | 16 | MississippiFaultsModel 17 | ---------------------- 18 | Link: `MississippiFaultsModel `_ 19 | 20 | This implementation of the *pyDeltaRCM* model is used in the paper 21 | `Moodie and Passalacqua (2021) `_ to 22 | simulate a Mississippi River-like delta. 23 | 24 | SelengaModel 25 | ------------ 26 | Link: `SelengaModel `_ 27 | 28 | This implementation of the *pyDeltaRCM* model is used in the paper 29 | `Moodie and Passalacqua (2021) `_ to 30 | simulate a Selenga River-like delta. 31 | 32 | VariableSLRModel 33 | ---------------- 34 | Link: `VariableSLRModel `_ 35 | 36 | This implementation of the *pyDeltaRCM* model is used in the paper 37 | `Hariharan et al (2022) `_ to simulate 38 | variable sea level rise scenarios. -------------------------------------------------------------------------------- /docs/source/examples/overwrite_topo_diffusion.rst: -------------------------------------------------------------------------------- 1 | Changing topographic diffusion to represent tree throw 2 | ====================================================== 3 | 4 | Here, we demonstrate how to overwrite an existing method of the `DeltaModel` to achieve custom behavior during model runtime. 5 | 6 | .. note:: 7 | 8 | This example demonstrates several best-practices, including using yaml parameters specifications, custom figure and grid saving setup, and using :obj:`~pyDeltaRCM.shared_tools.get_random_uniform` for random number generation. 9 | 10 | In implementing custom model subclasses, it is common to want to change runtime behavior of the model. 11 | This can often be achieved by using hooks alone, but sometimes a combination of hooks and overwriting existing methods is necessary. 12 | 13 | In this example, we calculate a diffusion multiplier to represent tree throw. 14 | In this super simple and **likely way over-exaggerated** representation of this process, we assume: 15 | 16 | * there are trees everywhere the elevation of a cell has been above `self.dry_depth` for 10 consecutive timesteps 17 | * there is a probability threshold of tree throw occurring anywhere trees exist 18 | * tree throw makes the diffusion multiplier for that cell on that timestep really big! 19 | 20 | .. important:: 21 | 22 | There are all kinds of problems with the assumptions in this example. Don't read into it too much. It's an example to show how to modify code, not how to represent tree throw. 23 | 24 | .. plot:: 25 | :context: reset 26 | :include-source: 27 | 28 | class TreeThrowModel(pyDeltaRCM.DeltaModel): 29 | """Implementation of tree throw. 30 | """ 31 | 32 | def __init__(self, input_file=None, **kwargs): 33 | 34 | # inherit from base model 35 | super().__init__(input_file, **kwargs) 36 | self.hook_after_create_domain() 37 | 38 | def hook_import_files(self): 39 | """Define the custom YAML parameters.""" 40 | # whether to run vegetation 41 | self.subclass_parameters['tree_throw'] = { 42 | 'type': 'bool', 'default': False 43 | } 44 | 45 | # tree throw multiplier 46 | self.subclass_parameters['p_tt_mult'] = { 47 | 'type': ['int', 'float'], 'default': 100 48 | } 49 | 50 | # tree throw establish timesteps 51 | self.subclass_parameters['p_tt_iter'] = { 52 | 'type': ['int', 'float'], 'default': 10 53 | } 54 | 55 | # tree throw prob threshold 56 | self.subclass_parameters['p_tt_prob'] = { 57 | 'type': ['int', 'float'], 'default': 0.2 58 | } 59 | 60 | def hook_init_output_file(self): 61 | """Add non-standard grids, figures and metadata to be saved.""" 62 | # save a figure of the active layer each save_dt 63 | self._save_fig_list['tree'] = ['tree'] 64 | 65 | # save the active layer grid each save_dt w/ a short name 66 | self._save_var_list['tree'] = ['tree', 'boolean', 67 | 'i4', ('time', 68 | 'x', 'y')] 69 | 70 | def hook_after_create_domain(self): 71 | """Add fields to the model for all tree parameterizations. 72 | """ 73 | self.tree = np.zeros(self.depth.shape, dtype=np.int64) 74 | self.dry_count = np.zeros(self.depth.shape, dtype=np.int64) 75 | 76 | self.tree_multiplier = np.ones_like(self.depth) 77 | 78 | def hook_after_route_sediment(self): 79 | """Apply vegetation growth/death rules. 80 | """ 81 | # determine cells dry and increment counter 82 | _where_dry = (self.depth < self.dry_depth) 83 | self.dry_count[~_where_dry] = 0 # any wet gets reset 84 | self.dry_count[_where_dry] += 1 # any dry gets incremented 85 | 86 | # if tree_throw is on, run the tree placing routine 87 | if self.tree_throw: 88 | 89 | # trees die anywhere wet 90 | self.tree[~_where_dry] = int(0) 91 | 92 | # trees go anywhere dry for more than threshold 93 | _where_above_thresh = (self.dry_count >= self.p_tt_iter) 94 | 95 | self.tree[_where_above_thresh] = int(1) 96 | 97 | # determine the multiplier field 98 | _rand = np.array([get_random_uniform(1) for i in np.arange(self.depth.size)]).reshape(self.depth.shape) 99 | _thrown = np.logical_and((_rand < self.p_tt_prob), self.tree) 100 | 101 | # ignore the strip of land 102 | _thrown[self.cell_type == -2] = 0 103 | 104 | # set to ones everywhere, then overwrite with multiplier 105 | self.tree_multiplier[:] = 1 106 | self.tree_multiplier[_thrown] = self.p_tt_mult 107 | 108 | def topo_diffusion(self): 109 | """Overwrite with new behavior. 110 | 111 | This method is very similar to the base DeltaModel code, but we add an 112 | additional multiplier to represent tree throw. 113 | """ 114 | for _ in range(self.N_crossdiff): 115 | 116 | a = ndimage.convolve(self.eta, self.kernel1, mode='constant') 117 | b = ndimage.convolve(self.qs, self.kernel2, mode='constant') 118 | c = ndimage.convolve(self.qs * self.eta, self.kernel2, 119 | mode='constant') 120 | 121 | self.cf = (self.tree_multiplier * self.diffusion_multiplier * 122 | (self.qs * a - self.eta * b + c)) 123 | 124 | self.cf[self.cell_type == -2] = 0 125 | self.cf[0, :] = 0 126 | 127 | self.eta += self.cf 128 | 129 | And the model is then instantiated with: 130 | 131 | .. plot:: 132 | :context: 133 | 134 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 135 | mdl = TreeThrowModel( 136 | out_dir=output_dir, 137 | tree_throw=True) 138 | 139 | .. code:: python 140 | 141 | mdl = TreeThrowModel( 142 | tree_throw=True) 143 | 144 | We don't actually run this model at all in this example. 145 | Let's plot the ``.tree`` field just to see that the subclass was instantiated correctly. 146 | 147 | .. plot:: 148 | :context: 149 | :include-source: 150 | 151 | fig, ax = plt.subplots() 152 | im = ax.imshow(mdl.tree) 153 | plt.colorbar(im, ax=ax, shrink=0.5) 154 | plt.show() 155 | -------------------------------------------------------------------------------- /docs/source/examples/simple_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "70c593eb-e479-4b4c-ad52-2d578bfad177", 6 | "metadata": { 7 | "tags": [] 8 | }, 9 | "source": [ 10 | "# Simple model run example\n", 11 | "\n", 12 | "This Jupyter Notebook shows how to configure and run a model simulation, and how to examine the model outputs.\n", 13 | "\n", 14 | "This document supplements the [10-minute tutorial](https://deltarcm.org/pyDeltaRCM/guides/10min.html) and [User Guide](https://deltarcm.org/pyDeltaRCM/guides/user_guide.html), but is not a complete guide to the model." 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "id": "ac5919f8-0779-4ac1-b728-bb6c1361ef82", 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "import pyDeltaRCM" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "id": "d2d7db35-4f4b-4111-8269-e40478378ac8", 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "import os\n", 35 | "import numpy as np\n", 36 | "import netCDF4\n", 37 | "import matplotlib.pyplot as plt" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "id": "7121c3ca-4c8b-4d5e-9642-b76b35f68a72", 43 | "metadata": {}, 44 | "source": [ 45 | "First, we will configure a YAML file to input to the model." 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "id": "169fd14b-3d16-4569-a91f-0523dbbad30d", 52 | "metadata": {}, 53 | "outputs": [], 54 | "source": [ 55 | "%%writefile eg_config.yaml\n", 56 | "\n", 57 | "f_bedload: 0.25\n", 58 | "h0: 2\n", 59 | "u0: 1.1\n", 60 | "save_eta_figs: True\n", 61 | "save_eta_grids: True\n", 62 | "save_velocity_grids: True\n", 63 | "save_dt: 250000" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "id": "46e6dd75-bd65-4dc3-81a1-29369eb87c6f", 69 | "metadata": {}, 70 | "source": [ 71 | "In the following cell, we instantiate the model with the yaml file we just created, run the model for 1000 steps, and finalize.\n", 72 | "\n", 73 | "**WARNING** executing the run will likely take 30-40 minutes." 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "id": "a87a3c1d-60bf-4916-b531-1ded37d89050", 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "mdl = pyDeltaRCM.DeltaModel('eg_config.yaml')\n", 84 | "\n", 85 | "for _ in range(0, 1000):\n", 86 | " mdl.update()\n", 87 | "\n", 88 | "mdl.finalize()" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "id": "57bb6af2-d7a4-4f0a-88b1-d6f29594aa02", 94 | "metadata": {}, 95 | "source": [ 96 | "With the model completed, we can see the final state:" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": null, 102 | "id": "a86fd13d-ffb7-4c31-85c7-be3bd4533001", 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [ 106 | "fig, ax = plt.subplots()\n", 107 | "ax.imshow(mdl.eta, cmap='cividis')\n", 108 | "plt.show()" 109 | ] 110 | }, 111 | { 112 | "cell_type": "markdown", 113 | "id": "a2488676-78da-4387-b933-4a237da2ca9f", 114 | "metadata": {}, 115 | "source": [ 116 | "We can also access the history of the run in the output NetCDF4 file." 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": null, 122 | "id": "7e02e59a-f615-4f58-b100-208d466f2df8", 123 | "metadata": {}, 124 | "outputs": [], 125 | "source": [ 126 | "data = netCDF4.Dataset(os.path.join('deltaRCM_Output', 'pyDeltaRCM_output.nc')) # this is the default location for the output file" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "id": "32b652fa-6158-412d-a4e8-d0fcdc41c31f", 133 | "metadata": {}, 134 | "outputs": [], 135 | "source": [ 136 | "nt = 3\n", 137 | "ts = np.linspace(0, data['eta'].shape[0]-1,\n", 138 | " num=nt, dtype=int) # linearly interpolate ts\n", 139 | "\n", 140 | "# make the timeseries plot\n", 141 | "fig, ax = plt.subplots(1, nt, figsize=(11, 2), dpi=300)\n", 142 | "for i, t in enumerate(ts):\n", 143 | " ax[i].imshow(data['eta'][t, :, :], cmap='cividis')\n", 144 | " ax[i].axes.get_xaxis().set_ticks([])\n", 145 | " ax[i].axes.get_yaxis().set_ticks([])\n", 146 | "\n", 147 | "plt.tight_layout()\n", 148 | "plt.show()" 149 | ] 150 | } 151 | ], 152 | "metadata": { 153 | "kernelspec": { 154 | "display_name": "Python 3 (ipykernel)", 155 | "language": "python", 156 | "name": "python3" 157 | }, 158 | "language_info": { 159 | "codemirror_mode": { 160 | "name": "ipython", 161 | "version": 3 162 | }, 163 | "file_extension": ".py", 164 | "mimetype": "text/x-python", 165 | "name": "python", 166 | "nbconvert_exporter": "python", 167 | "pygments_lexer": "ipython3", 168 | "version": "3.9.5" 169 | } 170 | }, 171 | "nbformat": 4, 172 | "nbformat_minor": 5 173 | } 174 | -------------------------------------------------------------------------------- /docs/source/examples/slight_slope.rst: -------------------------------------------------------------------------------- 1 | Slightly sloping basin 2 | ====================== 3 | 4 | Consider the case where we are a researcher seeking to explore the effects of a receiving basin that is sloped perpendicular to the channel outlet. 5 | This researcher asks: does this sloped basin cause channels to steer towards the deeper water, where compensation is higher? 6 | 7 | The researcher can easily use subclassing and model hooks to achieve the desired effect. 8 | Recall that anything added to the end of the the subclass' `__init__` method will be called during instantiation of the subclass. 9 | 10 | .. plot:: 11 | :context: reset 12 | :include-source: 13 | 14 | class SlightSlopeModel(pyDeltaRCM.DeltaModel): 15 | """A subclass of DeltaModel with sloping basin. 16 | 17 | This subclass simply modifies the basin geometry 18 | before any computation has occurred. 19 | """ 20 | def __init__(self, input_file=None, **kwargs): 21 | 22 | # inherit base DeltaModel methods 23 | super().__init__(input_file, **kwargs) 24 | 25 | # modify the basin 26 | slope = 0.0005 # cross basin slope 27 | eta_line = slope * np.arange(0, self.Width, 28 | step=self.dx) 29 | eta_grid = np.tile(eta_line, (self.L - self.L0, 1)) 30 | eta_grid = eta_grid - ((slope * self.Width)/2) # center at inlet 31 | self.eta[self.L0:, :] += eta_grid 32 | 33 | Next, we instantiate the model class. 34 | 35 | .. code:: 36 | 37 | mdl = SlightSlopeModel() 38 | 39 | 40 | .. plot:: 41 | :context: 42 | 43 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 44 | mdl = SlightSlopeModel(out_dir=output_dir) 45 | 46 | 47 | And finally, make a plot of the initial condition using the :obj:`~pyDeltaRCM.debug_tools.debug_tools.show_attribute` method. 48 | 49 | .. plot:: 50 | :context: 51 | :include-source: 52 | 53 | fig, ax = plt.subplots() 54 | mdl.show_attribute('eta', grid=False) 55 | plt.show() 56 | 57 | You can try this out for yourself, and even complete the model run. 58 | Are the channels steered by the basin slope? 59 | 60 | .. important:: 61 | 62 | In this example, we did not take care to update the model `stage` or `depth` fields. In this simple case it works out fine, because after a single timestep, the fields are correctly computed relative to the modified bed. However, take caution when modifying `DeltaModel` fields directly, and be sure to change *all* relevant fields too. 63 | -------------------------------------------------------------------------------- /docs/source/examples/subsidence_region.rst: -------------------------------------------------------------------------------- 1 | Constraining subsidence to part of the domain 2 | ============================================= 3 | 4 | One case that has been explored in the literature with the DeltaRCM model is the case of subsidence limited to one region of the model domain [1]_. 5 | This model configuration can be readily achieved with model subclassing. 6 | 7 | Setting up the custom subclass 8 | ------------------------------ 9 | 10 | .. plot:: 11 | :context: reset 12 | :include-source: 13 | 14 | class ConstrainedSubsidenceModel(pyDeltaRCM.DeltaModel): 15 | """A simple subclass of DeltaModel with subsidence region constrained. 16 | 17 | This subclass *overwrites* the `init_subsidence` method to 18 | constrain subsidence to only one region of the model domain. 19 | """ 20 | def __init__(self, input_file=None, **kwargs): 21 | 22 | # inherit base DeltaModel methods 23 | super().__init__(input_file, **kwargs) 24 | 25 | def init_subsidence(self): 26 | """Initialize subsidence pattern constrained to a tighter region. 27 | 28 | Uses theta1 and theta2 to set the angular bounds for the 29 | subsiding region. theta1 and theta2 are set in relation to the 30 | inlet orientation. The inlet channel is at an angle of 0, if 31 | theta1 is -pi/3 radians, this means that the angle to the left of 32 | the inlet that will be included in the subsiding region is 30 33 | degrees. theta2 defines the right angular bounds for the subsiding 34 | region in a similar fashion. 35 | """ 36 | _msg = 'Initializing custom subsidence field' 37 | self.log_info(_msg, verbosity=1) 38 | 39 | if self._toggle_subsidence: 40 | 41 | theta1 = -(np.pi / 3) 42 | theta2 = 0 43 | 44 | R1 = 0.3 * self.L # radial limits (fractions of L) 45 | R2 = 0.8 * self.L 46 | 47 | Rloc = np.sqrt((self.y - self.L0)**2 + (self.x - self.W / 2.)**2) 48 | 49 | thetaloc = np.zeros((self.L, self.W)) 50 | thetaloc[self.y > self.L0 - 1] = np.arctan( 51 | (self.x[self.y > self.L0 - 1] - self.W / 2.) 52 | / (self.y[self.y > self.L0 - 1] - self.L0 + 1)) 53 | self.subsidence_mask = ((R1 <= Rloc) & (Rloc <= R2) & 54 | (theta1 <= thetaloc) & 55 | (thetaloc <= theta2)) 56 | self.subsidence_mask[:self.L0, :] = False 57 | 58 | self.sigma = self.subsidence_mask * self.subsidence_rate * self.dt 59 | 60 | 61 | Now, initialize the model and look at the field. 62 | Note that the colorscale depicts the magnitude of subsidence in the model *per timestep* (`sigma`, which has units meters). 63 | 64 | .. code:: python 65 | 66 | mdl = ConstrainedSubsidenceModel(toggle_subsidence=True) 67 | 68 | .. plot:: 69 | :context: 70 | 71 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 72 | mdl = ConstrainedSubsidenceModel(toggle_subsidence=True, 73 | out_dir=output_dir) 74 | 75 | .. plot:: 76 | :context: 77 | :include-source: 78 | 79 | fig, ax = plt.subplots() 80 | mdl.show_attribute('sigma', grid=False) 81 | plt.show() 82 | 83 | 84 | Using the custom subclass with the preprocessor 85 | ----------------------------------------------- 86 | 87 | We can configure a :obj:`Preprocessor` to handle a set of custom runs in conjunction with out custom `pyDeltaRCM` model subclass. 88 | For example, in [1]_, the authors explore the impact of subsidence at various rates: 3 mm/yr, 6 mm/yr, 10 mm/yr, 25 mm/yr, 50 mm/yr, and 100 mm/yr. 89 | We can scale these rates, assuming a model :doc:`intermittency factor ` of 0.019, representing 7 of 365 days of flooding per year, by using the convenience function :obj:`~pyDeltaRCM.preprocessor.scale_relative_sea_level_rise_rate`: 90 | 91 | .. plot:: 92 | :context: close-figs 93 | :include-source: 94 | 95 | from pyDeltaRCM.preprocessor import scale_relative_sea_level_rise_rate 96 | 97 | subsidence_mmyr = np.array([3, 6, 10, 25, 50, 100]) 98 | subsidence_scaled = scale_relative_sea_level_rise_rate(subsidence_mmyr, If=0.019) 99 | 100 | Now, we use :ref:`matrix expansion ` to set up the runs with a preprocessor. 101 | For example, in a Python script, following the definition of the subclass above, define a dictionary with a `matrix` key and supply to the `Preprocessor`: 102 | 103 | .. plot:: 104 | :context: 105 | :include-source: 106 | 107 | # add a matrix with subsidence to the dict 108 | param_dict = {} 109 | param_dict['matrix'] = {'subsidence_rate': subsidence_scaled} 110 | 111 | # add other configurations 112 | param_dict.update( 113 | {'out_dir': 'liang_2016_reproduce', 114 | 'toggle_subsidence': True, 115 | 'parallel': 3}) # we can take advantage of parallel jobs 116 | 117 | .. code:: 118 | 119 | # create the preprocessor 120 | pp = pyDeltaRCM.Preprocessor( 121 | param_dict, 122 | timesteps=10000) 123 | 124 | And finally run the jobs by specifying the model subclass as the class to use when instantiating the jobs with the preprocessor. 125 | 126 | .. below, we overwrite the above, to make sure we only run for one timestep 127 | .. plot:: 128 | :context: 129 | 130 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 131 | param_dict['out_dir'] = output_dir 132 | pp = pyDeltaRCM.Preprocessor( 133 | param_dict, 134 | parallel=False, 135 | timesteps=1) 136 | pp.run_jobs(DeltaModel=ConstrainedSubsidenceModel) 137 | 138 | .. code:: python 139 | 140 | # run the jobs 141 | pp.run_jobs(DeltaModel=ConstrainedSubsidenceModel) 142 | 143 | We can check whether the runs were set up, as expected: 144 | 145 | .. plot:: 146 | :context: 147 | :include-source: 148 | 149 | from matplotlib.colors import Normalize 150 | 151 | fig, ax = plt.subplots(2, 3, sharex=True, sharey=True, figsize=(10, 4)) 152 | norm = Normalize(vmin=3, vmax=100) 153 | 154 | for i, job in enumerate(pp.job_list): 155 | # first convert the field to a rate 156 | subsidence_rate_field = (job.deltamodel.sigma / job.deltamodel.dt) 157 | 158 | # now convert to mm/yr 159 | subsidence_rate_field = (subsidence_rate_field * 1000 * 160 | pyDeltaRCM.shared_tools._scale_factor(If=0.019, units='years')) 161 | 162 | # and display 163 | im = ax.flat[i].imshow(subsidence_rate_field, norm=norm) 164 | 165 | fig.colorbar(im, ax=ax.ravel().tolist()) 166 | plt.show() 167 | 168 | 169 | .. [1] Liang, M., Kim, W., and Passalacqua, P. (2016), How much subsidence is 170 | enough to change the morphology of river deltas?, Geophysical Research Letters, 43, 10,266--10,276, doi:10.1002/2016GL070519. 171 | -------------------------------------------------------------------------------- /docs/source/examples/updating_boundary_conditions.rst: -------------------------------------------------------------------------------- 1 | Updating model boundary conditions 2 | ================================== 3 | 4 | In implementing custom model subclasses, it is common to want to change boundary conditions throughout the model run (see :doc:`variable_bedload`, :doc:`variable_velocity`). 5 | In some situations, we want to change a single variable, and see the effect of changing *only this variable*, in essence, pushing the model out of a dynamic equilibrium. 6 | Another possibility is that we would want to change the boundary conditions of the inlet, *but maintain the dynamic equilibrium*. 7 | 8 | Let's create a `DeltaModel` class to demonstrate. 9 | 10 | .. code:: 11 | 12 | mdl = DeltaModel() 13 | 14 | 15 | .. doctest:: 16 | :hide: 17 | 18 | >>> with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 19 | ... mdl = pyDeltaRCM.DeltaModel(out_dir=output_dir) 20 | 21 | Now, we can see that by the default settings, after initialization, the model flow velocity is 1.0 m/s, flow depth is 5 m, and so the unit water discharge is 5 m2/s. 22 | 23 | .. doctest:: 24 | 25 | >>> mdl.u0 26 | 1.0 27 | >>> mdl.h0 28 | 5.0 29 | >>> mdl.qw0 30 | 5.0 31 | 32 | If after some number of model iterations, we wanted to change the inlet flow velocity to be 2.0 m/s, we could simply set this value directly. 33 | 34 | .. doctest:: 35 | 36 | >>> mdl.u0 = 2.0 37 | 38 | But, now the model has been thrown out of equilibrium, where the unit water discharge no longer matches the product of the flow depth and flow velocity. 39 | 40 | .. doctest:: 41 | 42 | >>> mdl.u0 43 | 2.0 44 | >>> mdl.h0 45 | 5.0 46 | >>> mdl.qw0 47 | 5.0 48 | 49 | To remedy this, we need to use the :obj:`~pyDeltaRCM.init_tools.init_tools.create_boundary_conditions` method, which will reinitialize a number of fields, based on the current value of the inlet flow velocity. 50 | 51 | .. doctest:: 52 | 53 | >>> mdl.create_boundary_conditions() 54 | >>> mdl.qw0 55 | 10.0 56 | 57 | .. important:: 58 | 59 | You are responsible for ensuring that boundary conditions are updated in the appropriate manner after changing certain model parameters. **You need to call the method to reinitialize boundary conditions yourself!** 60 | -------------------------------------------------------------------------------- /docs/source/examples/variable_bedload.rst: -------------------------------------------------------------------------------- 1 | Time-varying bedload 2 | ==================== 3 | 4 | The following example demonstrates how to configure a subclassing model with a time-varying parameter. 5 | In this example, the time-varying behavior arises by managing two "switches", ``self._changed`` and ``self._changed_back``, which change the state of the :obj:`f_bedload` parameters at a predetermined time in the mode sequence. 6 | 7 | The following codes produce two runs (using `matrix` expansion from the Preprocessor), which has a baseline `f_bedload` value of either ``0.3`` or ``0.7``, and for a period in the middle of the run, the `f_bedload` values are mirrored by ``self.f_bedload = (1 - self.f_bedload)``, i.e., briefly switching the bedload values. 8 | 9 | 10 | .. plot:: 11 | :context: reset 12 | :include-source: 13 | 14 | class VariableBedloadModel(pyDeltaRCM.DeltaModel): 15 | 16 | def __init__(self, input_file=None, **kwargs): 17 | 18 | super().__init__(input_file, **kwargs) 19 | 20 | self._changed = False 21 | self._changed_back = False 22 | 23 | def hook_solve_water_and_sediment_timestep(self): 24 | """Change the state depending on the _time. 25 | """ 26 | # check if the state has been changed, and time to change it 27 | if (not self._changed) and (self._time > 459909090): 28 | self.f_bedload = (1 - self.f_bedload) 29 | self._changed = True 30 | 31 | _msg = 'Bedload changed to {f_bedload}'.format( 32 | f_bedload=self.f_bedload) 33 | self.log_info(_msg, verbosity=0) 34 | 35 | # check if the state has been changed back, and time to change it back 36 | if (not self._changed_back) and (self._time > 714545454): 37 | self.f_bedload = (1 - self.f_bedload) 38 | self._changed_back = True 39 | 40 | _msg = 'Bedload changed back to {f_bedload}'.format( 41 | f_bedload=self.f_bedload) 42 | self.log_info(_msg, verbosity=0) 43 | 44 | 45 | .. rubric:: Checking on the state-change effect 46 | 47 | To demonstrate how this works, let's loop through time and check the model state. 48 | Here, we will change the model time value directly, so that we can verify that the model is working as intended, but you should never do this in practice. 49 | 50 | .. plot:: 51 | :context: 52 | 53 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 54 | mdl_muddy = VariableBedloadModel(f_bedload=0.3, 55 | out_dir=output_dir) 56 | mdl_sandy = VariableBedloadModel(f_bedload=0.7, 57 | out_dir=output_dir) 58 | 59 | .. code:: python 60 | 61 | mdl_muddy = VariableBedloadModel(f_bedload=0.3) 62 | mdl_sandy = VariableBedloadModel(f_bedload=0.7) 63 | 64 | .. important:: 65 | 66 | You should never modify the model time via ``self._time`` directly when working with the model. 67 | 68 | 69 | .. plot:: 70 | :context: 71 | :include-source: 72 | 73 | # create a figure 74 | fig, ax = plt.subplots() 75 | 76 | # set the "simulation" range 77 | _times = np.linspace(0, 1e9, num=100) 78 | fb_mdl_muddy = np.zeros_like(_times) 79 | fb_mdl_sandy = np.zeros_like(_times) 80 | 81 | # loop through time, change the model time and grab f_bedload values 82 | for i, _time in enumerate(_times): 83 | # change the model time directly 84 | mdl_muddy._time = _time # you should never do this 85 | mdl_sandy._time = _time # you should never do this 86 | 87 | # run the hooked method 88 | mdl_muddy.hook_solve_water_and_sediment_timestep() 89 | mdl_sandy.hook_solve_water_and_sediment_timestep() 90 | 91 | # grab the state of the `f_bedload` parameter 92 | fb_mdl_muddy[i] = mdl_muddy.f_bedload # get the value 93 | fb_mdl_sandy[i] = mdl_sandy.f_bedload # get the value 94 | 95 | # add it to the plot 96 | ax.plot(_times, fb_mdl_muddy, '-', c='saddlebrown', lw=2, label='muddy') 97 | ax.plot(_times, fb_mdl_sandy, '--', c='goldenrod', lw=2, label='sandy') 98 | ax.legend() 99 | 100 | # clean up 101 | ax.set_ylim(0, 1) 102 | ax.set_ylabel('f_bedload') 103 | ax.set_xlabel('model time (s)') 104 | 105 | plt.show() 106 | 107 | 108 | .. rubric:: Running the model for real 109 | 110 | Given a yaml file (``variable_bedload.yaml``): 111 | 112 | .. code:: yaml 113 | 114 | Length: 5000. 115 | Width: 10000. 116 | dx: 50 117 | N0_meters: 500 118 | C0_percent: 0.05 119 | SLR: 1.5e-8 120 | h0: 2 121 | u0: 1.1 122 | coeff_U_dep_mud: 0.5 123 | parallel: True 124 | 125 | matrix: 126 | f_bedload: 127 | - 0.3 128 | - 0.7 129 | 130 | 131 | and a script to run the code: 132 | 133 | .. code:: python 134 | 135 | if __name__ == '__main__': 136 | 137 | # base yaml configuration 138 | base_yaml = 'variable_bedload.yaml' 139 | 140 | pp = pyDeltaRCM.Preprocessor( 141 | base_yaml, 142 | timesteps=12000) 143 | 144 | # run the jobs 145 | pp.run_jobs(DeltaModel=VariableBedloadModel) 146 | 147 | -------------------------------------------------------------------------------- /docs/source/examples/variable_velocity.rst: -------------------------------------------------------------------------------- 1 | Time-varying inlet velocity 2 | =========================== 3 | 4 | It is straightforward to create models with time-varying boundary conditions. 5 | In this example, we set up an array of values to use for the inlet flow velocity, depending on the time of the model (i.e., a timeseries). 6 | 7 | In implementation, because we don't know the timestep of the model before creating it, we interpolate the actual inlet flow velocity from the boundary condition timeseries. 8 | 9 | 10 | Define the boundary condition 11 | ----------------------------- 12 | 13 | First, let's set up the boundary condition array we want to use. 14 | We'll set this up in a function, so that it can be called from the model subclass, as well as here for plotting. 15 | 16 | .. plot:: 17 | :context: reset 18 | :include-source: 19 | 20 | def create_velocity_array(end_time, a=1, b=5e4, h=3.2, k=2): 21 | """Create velocity timeseries. 22 | """ 23 | _time = np.linspace(0, end_time, num=1000) 24 | 25 | _velocity = a * np.sin((_time - h)/b) + k 26 | return _time, _velocity 27 | 28 | The function we define takes the `end_time` of the model run, as well as some shape parameters, and computes according to: 29 | 30 | .. math:: 31 | 32 | y = a \sin \left( \frac{ \left( t - h \right) }{ b } \right) + k 33 | 34 | where :math:`t` is the time array in seconds. 35 | We can inspect the result of this function, as it will be called in the model subclass below. 36 | 37 | .. plot:: 38 | :context: 39 | :include-source: 40 | 41 | end_time = 86400 * 100 42 | _time_array, _velocity_array = create_velocity_array( 43 | end_time) 44 | 45 | # make a plot of the boundary condition 46 | fig, ax = plt.subplots() 47 | ax.plot(_time_array, _velocity_array) 48 | ax.set_xlabel('time (seconds)') 49 | ax.set_ylabel('inlet velocity (meters/second)') 50 | plt.show() 51 | 52 | 53 | Define the model subclass 54 | ------------------------- 55 | 56 | We define a model subclass to handle the changing boundary condition: 57 | 58 | .. plot:: 59 | :context: close-figs 60 | :include-source: 61 | 62 | class ChangingVelocityModel(pyDeltaRCM.DeltaModel): 63 | """Model with changing flow velocity. 64 | 65 | Create a model that changes the inlet flow velocity throughout the run. 66 | In this example, the velocity is changed on each timestep, and the value 67 | it is set to is interpolated from a **predetermined timeseries** of 68 | velocities. 69 | """ 70 | def __init__(self, input_file=None, end_time=86400, **kwargs): 71 | 72 | # inherit from the base model 73 | super().__init__(input_file, **kwargs) 74 | 75 | # set up the attributes for interpolation 76 | self._time_array, self._velocity_array = create_velocity_array( 77 | end_time) # use default shape parameters for the array 78 | 79 | def hook_solve_water_and_sediment_timestep(self): 80 | """Change the velocity.""" 81 | 82 | # find the new velocity and set it to the model 83 | self.u0 = np.interp(self._time, self._time_array, self._velocity_array) 84 | 85 | # update other boundary conditions using u0 86 | self.create_boundary_conditions() 87 | 88 | # log the new value 89 | _msg = 'Changed velocity value to {u0}'.format( 90 | u0=self.u0) 91 | self.log_info(_msg, verbosity=0) 92 | 93 | 94 | and then simply run with: 95 | 96 | .. plot:: 97 | :context: 98 | 99 | # we create the model here, just to be sure it works (for good docs) 100 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 101 | mdl = ChangingVelocityModel( 102 | end_time=86400*100, 103 | out_dir=output_dir) 104 | 105 | .. code:: 106 | 107 | mdl = ChangingVelocityModel(end_time=end_time) 108 | 109 | while mdl.time < end_time: 110 | mdl.update() 111 | 112 | 113 | .. note:: 114 | 115 | For information on updating boundary conditions after changing certain model parameters see :doc:`updating_boundary_conditions`. 116 | -------------------------------------------------------------------------------- /docs/source/guides/10min.rst: -------------------------------------------------------------------------------- 1 | ****************** 2 | 10-minute tutorial 3 | ****************** 4 | 5 | Use pyDeltaRCM in ten minutes! 6 | This simple guide will show you the absolute basics of getting a `pyDeltaRCM` model running, and give you some direction on where to go from there. 7 | 8 | .. important:: 9 | 10 | If you haven't already, be sure to follow the :doc:`installation guide ` to get *pyDeltaRCM* set up properly on your computer. 11 | 12 | 13 | A default model 14 | --------------- 15 | 16 | You can get a model running with five simple lines of Python code. Note that you can run *pyDeltaRCM* in either a standalone script or part of an interactive session. 17 | First, we instantiate the main :obj:`~pyDeltaRCM.DeltaModel` model object. 18 | 19 | .. code:: python 20 | 21 | >>> import pyDeltaRCM 22 | 23 | >>> default_delta = pyDeltaRCM.DeltaModel() 24 | 25 | Instantiating the :obj:`~pyDeltaRCM.model.DeltaModel()` without any arguments will use a set of :doc:`default parameters <../reference/model/yaml_defaults>` to configure the model run. 26 | The default options are a reasonable set for exploring some controls of the model, and would work perfectly well for a simple demonstration here. 27 | 28 | The delta model is run forward with a call to the :meth:`~pyDeltaRCM.DeltaModel.update()` method. 29 | So, we simply create a `for` loop, and call the `update` function, and then wrap everything up with a call to :meth:`~pyDeltaRCM.DeltaModel.finalize` the model: 30 | 31 | .. code:: python 32 | 33 | >>> for _ in range(0, 5): 34 | ... default_delta.update() 35 | 36 | >>> default_delta.finalize() 37 | 38 | .. note:: 39 | 40 | Additional calls to update the model can be called up until the model is finalized. 41 | 42 | That's it! You ran the pyDeltaRCM model for five timesteps, with just five lines of code. 43 | 44 | We can visualize the delta bed elevation, though it's not very exciting after only five timesteps... 45 | 46 | .. code:: python 47 | 48 | >>> import matplotlib.pyplot as plt 49 | 50 | >>> fig, ax = plt.subplots() 51 | >>> ax.imshow(default_delta.bed_elevation, vmax=-3) 52 | >>> plt.show() 53 | 54 | .. plot:: guides/10min_demo.py 55 | 56 | 57 | The model with set parameters 58 | ----------------------------- 59 | 60 | To run a simulation with a non-default set of parameters, we use a configuration file written in the YAML markup language named `10min_tutorial.yaml`. 61 | The markup file allows us to specify model boundary conditions and input and output settings, where anything set in the file will override the :doc:`default parameters <../reference/model/yaml_defaults>` for the model, and anything *not* specified will take the default value. 62 | 63 | .. important:: 64 | 65 | The best practice for model configurations is to create a YAML file with only the settings you want to change specified. 66 | 67 | The YAML configuration file is central to managing *pyDeltaRCM* simulations, so we did not create this file for you; you will need to create the YAML file yourself. 68 | To create the YAML file, open up your favorite plain-text editing application (e.g., gedit, notepad). 69 | YAML syntax is pretty simple for basic configurations, essentially amounting to each line representing a parameter-value pair, separated by a colon. 70 | For this example, let's specify three simulation controls: where we want the output file to be placed via the `out_dir` parameter, we will ensure that our simulation is easily reproducible by setting the random `seed` parameter, and we can examine what is the effect of a high fraction of bedload with the `f_bedload` parameter. 71 | Enter the following in your text editor, and save the file as ``10min_tutorial.yaml``, making sure to place the file in a location accessible to your interpreter. 72 | 73 | .. code:: yaml 74 | 75 | out_dir: '10min_tutorial' 76 | seed: 451220118313 77 | f_bedload: 0.9 78 | 79 | 80 | Now, we can create a second instance of the :obj:`~pyDeltaRCM.model.DeltaModel()`, this time using the input yaml file. 81 | 82 | .. code:: 83 | 84 | >>> second_delta = pyDeltaRCM.DeltaModel(input_file='10min_tutorial.yaml') 85 | 86 | and repeat the same `for` loop operation as above: 87 | 88 | .. code:: python 89 | 90 | >>> for _ in range(0, 5): 91 | ... second_delta.update() 92 | 93 | >>> second_delta.finalize() 94 | 95 | 96 | Resources 97 | --------- 98 | 99 | Consider reading through the :doc:`User Guide ` as a first action, and determine how to set up the model to complete your experiment, including tutorials and examples for customizing the model to achieve any arbitrary behavior you need! 100 | 101 | * :doc:`user_guide` 102 | * :doc:`/reference/model/index` 103 | -------------------------------------------------------------------------------- /docs/source/guides/getting_started.rst: -------------------------------------------------------------------------------- 1 | .. _getting_started: 2 | 3 | =============== 4 | Getting Started 5 | =============== 6 | 7 | 8 | It's easy to get started using *pyDeltaRCM*. 9 | We recommend starting out with the 10-minute learn-by-example lesson: 10 | 11 | .. toctree:: 12 | :maxdepth: 3 13 | 14 | 10min 15 | 16 | 17 | Return to the main index :ref:`user_documentation` to see all the other documentation available to help you get started. 18 | 19 | Some other helpful resources: 20 | 21 | * An example `Jupyter Notebook `_ that shows a complete model runs and quick analysis of output file. 22 | * A comprehensive :doc:`user_guide` on how to use and experiment with the model 23 | 24 | 25 | And when you're ready to start developing, check out the :doc:`developer_guide` and the complete model :doc:`API documentation `. 26 | -------------------------------------------------------------------------------- /docs/source/guides/subsidence_guide.inc: -------------------------------------------------------------------------------- 1 | ======================= 2 | Working with subsidence 3 | ======================= 4 | 5 | What is subsidence anyway? Subsidence is basically the downward vertical 6 | movement of the ground. There are many direct and indirect causes of subsidence, 7 | check out the `Wikipedia page `_ 8 | to get an overview. 9 | 10 | Turning on Subsidence in pyDeltaRCM 11 | =================================== 12 | 13 | To configure a pyDeltaRCM model with subsidence, the yaml parameter, 14 | ``toggle_subsidence`` must be set to ``True``. 15 | 16 | Controlling Subsidence Behavior 17 | =============================== 18 | 19 | Two yaml parameters are provided to give users some basic control over 20 | subsidence behavior. The first is ``start_subsidence``, which defines *when* 21 | subsidence begins in the model run. This parameter is set in terms of seconds, 22 | and is set to begin on the step *following* the time step that brings the 23 | model to ``time >= start_subsidence``. The second subsidence parameter is the 24 | ``subsidence_rate`` yaml parameter. This parameter defines the rate at which 25 | the basin will subside in meters per second. The default subsiding region is 26 | the entire delta basin with the exception of the inlet cells and the land cells 27 | along boundary. 28 | 29 | If, for example we wanted the basin to begin to subside after 2000 seconds 30 | with a rate of 2e-10 m/s, we would write our yaml file with the following 31 | parameters: 32 | 33 | .. code:: yaml 34 | 35 | toggle_subsidence: True 36 | start_subsidence: 2000 37 | subsidence_rate: 2e-10 38 | 39 | Advanced Subsidence Configurations 40 | ================================== 41 | 42 | Subsidence behavior can be easily modified by :ref:`creating a subclass ` and overwriting the :obj:`~pyDeltaRCM.init_tools.init_tools.init_subsidence` or :obj:`~pyDeltaRCM.iteration_tools.iteration_tools.apply_subsidence` methods, or even more simply the relevant model hooks. 43 | 44 | An example of using subclassing to create a model setup with subsidence confined to only part of the model domain is included in the documentation: 45 | 46 | * :doc:`/examples/subsidence_region` 47 | 48 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. pyDeltaRCM documentation master file 2 | 3 | Welcome to the PyDeltaRCM documentation 4 | ######################################### 5 | 6 | *pyDeltaRCM* is a computationally efficient, free and open source, and easy-to-customize numerical delta model based on the original DeltaRCM model design (`Matlab DeltaRCM `_ model by Man Liang). 7 | *pyDeltaRCM* delivers improved model stability and capabilities, infrastructure to support exploration with minimal boilerplate code, and establishes an approach to extending model capabilities that ensures reproducible and comparable studies. 8 | 9 | .. plot:: guides/cover.py 10 | 11 | The weighted random walk of 20 water parcels in a *pyDeltaRCM* model run with default parameters. 12 | 13 | 14 | Project information 15 | ################### 16 | 17 | .. image:: https://badge.fury.io/gh/DeltaRCM%2FpyDeltaRCM.svg 18 | :target: https://github.com/DeltaRCM/pyDeltaRCM/releases 19 | 20 | .. image:: https://badge.fury.io/py/pyDeltaRCM.svg 21 | :target: https://badge.fury.io/py/pyDeltaRCM 22 | 23 | .. image:: https://img.shields.io/static/v1?label=GitHub&logo=github&message=source&color=brightgreen 24 | :target: https://github.com/DeltaRCM/pyDeltaRCM 25 | 26 | .. image:: https://joss.theoj.org/papers/10.21105/joss.03398/status.svg 27 | :target: https://joss.theoj.org/papers/10.21105/joss.03398 28 | 29 | .. toctree:: 30 | :maxdepth: 1 31 | 32 | meta/installing 33 | meta/contributing 34 | meta/license 35 | meta/conduct 36 | meta/citing 37 | meta/usedby 38 | 39 | 40 | .. _user_documentation: 41 | 42 | User documentation 43 | ################## 44 | 45 | .. toctree:: 46 | :maxdepth: 2 47 | 48 | guides/getting_started 49 | guides/user_guide 50 | info/index 51 | examples/index 52 | examples/modelzoo 53 | 54 | 55 | 56 | Developer documentation 57 | ####################### 58 | 59 | .. image:: https://badge.fury.io/py/pyDeltaRCM.svg 60 | :target: https://badge.fury.io/py/pyDeltaRCM 61 | 62 | .. image:: https://github.com/DeltaRCM/pyDeltaRCM/actions/workflows/build.yml/badge.svg 63 | :target: https://github.com/DeltaRCM/pyDeltaRCM/actions 64 | 65 | .. image:: https://codecov.io/gh/DeltaRCM/pyDeltaRCM/branch/develop/graph/badge.svg 66 | :target: https://codecov.io/gh/DeltaRCM/pyDeltaRCM 67 | 68 | .. image:: https://app.codacy.com/project/badge/Grade/1c137d0227914741a9ba09f0b00a49a7 69 | :target: https://app.codacy.com/gh/DeltaRCM/pyDeltaRCM/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade 70 | 71 | .. toctree:: 72 | :maxdepth: 3 73 | 74 | guides/developer_guide 75 | reference/index 76 | -------------------------------------------------------------------------------- /docs/source/info/index.rst: -------------------------------------------------------------------------------- 1 | .. model_info: 2 | 3 | ================= 4 | Model Information 5 | ================= 6 | 7 | This section provides background information about the pyDeltaRCM model itself. 8 | What are the model variables and parameters? 9 | What do they mean? 10 | How does the model simulate hydrodynamics? 11 | How is morphodynamics handled? 12 | All of these questions and more are answered here! 13 | 14 | .. toctree:: 15 | :maxdepth: 1 16 | 17 | initialization 18 | yamlparameters 19 | modeltime 20 | hydrodynamics 21 | morphodynamics 22 | outputfile 23 | ../reference/model/model_hooks 24 | -------------------------------------------------------------------------------- /docs/source/info/initialization.rst: -------------------------------------------------------------------------------- 1 | ************** 2 | Initialization 3 | ************** 4 | 5 | .. currentmodule:: pyDeltaRCM.init_tools 6 | 7 | There are many built-in parameters for setting up pyDeltaRCM runs. 8 | 9 | 10 | Domain configuration 11 | ==================== 12 | 13 | The domain configuration is controlled by a series of input configuration parameters. 14 | Conceptually, we can consider the domain of pyDeltaRCM to be made up of an *inlet* along the top edge of the model domain and bounded by a strip of land, and the *basin*. 15 | 16 | .. plot:: init_tools/domain_parameters.py 17 | 18 | By default, the basin and inlet are both flat and have the same depth. However these characteristics can be controlled by a variety of input parameters explained below. 19 | Moreover, any complex initial geometry can be configured by the use of hooks; see an example here :doc:`../examples/slight_slope`. 20 | 21 | Domain size 22 | ----------- 23 | 24 | The domain size is controlled by the `Length` and `Width` YAML parameters. 25 | 26 | .. plot:: init_tools/domain_size_compare.py 27 | 28 | .. hint:: 29 | 30 | The size of the computational domain is determined by the size of the smallest size of the domain. The value for `Width` should almost always be 2 times `Length` to minimize unecessary calcualtions outside the valid computational domain. 31 | 32 | Importantly, the number of cells in the domain is then a function of the domain size in meters and the grid spacing :obj:`dx`. 33 | Because the number of grid cells is inverse nonlinearly related to the grid spacing (:math:`numcells = 1/dx^2`), the model runtime is sensitive to the choice of `dx` relative to `Length` and `Width`. 34 | 35 | 36 | Basin depth and inlet depth 37 | --------------------------- 38 | 39 | Inlet depth is controlled by :obj:`h0`. 40 | If no argument is given in the configuration for the parameter :obj:`hb`, then the basin depth is determined to be the same as the inlet depth. 41 | However, these depths can be controlled independently. 42 | 43 | .. plot:: init_tools/domain_basin_inlet_depth.py 44 | 45 | 46 | Inlet width and length 47 | ---------------------- 48 | 49 | The inlet length and width are controlled by an inlet length parameter :obj:`L0_meters` and an inlet width parameter :obj:`N0_meters`. 50 | In implementation, the input length and width are rounded to the nearest grid location (a function of :obj:`dx`). 51 | 52 | .. plot:: init_tools/domain_inlet_geometry.py 53 | 54 | 55 | 56 | Input water and sediment 57 | ======================== 58 | 59 | The input flow velocity is determined by :obj:`u0`. 60 | 61 | The input water discharge is thus fully constrained by the inlet geometry and the inlet flow velocity as: 62 | 63 | .. math:: 64 | Q_{w0} = h_0 \times N_0 \times u_0 65 | 66 | .. hint:: 67 | Keep in mind that :math:`N_0` is specified in meters as :obj:`N0_meters` in the input configuration. Ditto for the inlet length (:obj:`L0_meters`). 68 | 69 | 70 | Input sediment discharge is then determined by a **percentage concentration** of sediment in the flow :obj:`C0_percent`. 71 | 72 | .. math:: 73 | Q_{s0} = Q_{w0} \times (C_{0percent}/100) 74 | 75 | The volume of each parcel of water to be routed is then determined by the total water discharge divided by the number of parcels :obj:`Np_water`. 76 | The volume of each parcel of sediment to be routed is then determined by the total sediment discharge divided by the number of parcels :obj:`Np_sed`. 77 | 78 | The number of sand and mud parcels are then determined as `Np_sed` times :obj:`f_bedload` and `Np_sed` times (1-:obj:`f_bedload`), respectively. 79 | -------------------------------------------------------------------------------- /docs/source/info/modeltime.rst: -------------------------------------------------------------------------------- 1 | ****************** 2 | Time in pyDeltaRCM 3 | ****************** 4 | 5 | Time in the pyDeltaRCM model is simulated in units of seconds. 6 | The duration of a timestep is determined during model initialization to maintain numerical stability; the calculation is based on model domain and configuration parameters. 7 | The model is then iterated timestep by timestep, until an end-run condition is reached 8 | 9 | .. note:: 10 | 11 | If you are using the :ref:`high-level API `, the model run end condition is that the elapsed model time is *equal to or greater than* the specified input time. As a result, the model run duration is unlikely to exactly match the input time specification, because the model timestep is unlikely to be a factor of the specified time. 12 | 13 | Please keep this in mind when evaluating model results, and especially when comparing between different model runs. 14 | 15 | Over the duration of the model, the water discharge (and thus sediment discharge) are assumed to be at bankfull. 16 | This assumption is based on the concept of geomorphic work [WM60]_ and the strongly nonlinear relationship between water discharge and sediment transport. 17 | To summarize the basis of this assumption, a very small proportion of sediment is in motion when discharge is at or near a low-flow "base flow" condition, relative to the amount of sediment in motion during flood conditions. 18 | So while flooding only occurs for a small fraction of total time, most of the time-integrated sediment transport occurs during this fraction of time, and the remainder of time is deemed negligible in comparison. 19 | 20 | For example, in the contrived river-delta hydrograph shown below, the discharge fluctuates around a base-flow condition for most of the year, with the exception of a 50 day period when a flood event occurs (from "start event" to "end event"). 21 | For 25 days of the flood event, the discharge is high enough to exceed the bankfull discharge ("flooding duration"). 22 | 23 | .. plot:: modeltime/one_year_plot.py 24 | 25 | A numerical model could simulate every day of this hydrograph, but this would require substantial computing power. 26 | To accelerate the computation time of models, we assume that the only important period of time is when the river is at-or-above bankfull discharge, and we collapse the hydrograph to a single value: the bankfull discharge. 27 | The choice of bankfull discharge for the single-value discharge assumption is a matter of convenience, in that this is readily estimated from field data or measurements. 28 | 29 | The duration of time represented by the single-value discharge assumption is also determined by the hydrograph. 30 | We arrive at the so-called *intermittency factor* (:math:`I_f`) by finding the fraction of unit-time per unit-time when the river is in flood. 31 | For this example, the intermittency factor scales between days and years as 32 | 33 | .. math:: 34 | 35 | \frac{25~\textrm{days}}{365.25~\textrm{days}} \approx 0.07 \equiv I_f 36 | 37 | The intermittency factor thus gives a relationship to scale pyDeltaRCM model time (which is always computed in units of seconds elapsed) from seconds to years. 38 | For example, for a model run that has elapsed :math:`4.32 \times 10^8` seconds and an assumed intermittency factor of 0.07: 39 | 40 | .. math:: 41 | 42 | \frac{\textrm{seconds~elapsed}}{I_f} = \frac{4.32 \times 10^8~\textrm{seconds}}{0.07} = 6.17 \times 10^9~\textrm{seconds} \approx 196~\textrm{years} 43 | 44 | .. note:: A convenience function is supplied with the low-level API for these time conversions: :obj:`~pyDeltaRCM.shared_tools.scale_model_time`. 45 | 46 | Applying the intermittency assumption to a four year model simulation reveals the computational advantage of this approach. 47 | A simulation of every day in the simulation duration would require 1460 days of simulated time (:math:`1.26 \times 10^8` seconds). 48 | 49 | .. plot:: modeltime/four_year_plot.py 50 | 51 | In contrast, by condensing the simulated time down to a bankfull discharge only, the intermittency assumption allows us to simulate the same "four year" period in just under 59 days of simulated time (:math:`5.08 \times 10^6` seconds). 52 | 53 | 54 | See also 55 | -------- 56 | 57 | * :obj:`~pyDeltaRCM.preprocessor.scale_relative_sea_level_rise_rate` 58 | * :obj:`~pyDeltaRCM.shared_tools.scale_model_time` 59 | 60 | 61 | References 62 | ---------- 63 | 64 | .. [WM60] Wolman, M. G., & Miller, J. P. (1960). Magnitude and frequency of forces in geomorphic processes. The Journal of Geology, 68(1), 54–74. https://doi.org/10.1086/626637 -------------------------------------------------------------------------------- /docs/source/info/outputfile.rst: -------------------------------------------------------------------------------- 1 | ================= 2 | Model Output File 3 | ================= 4 | 5 | If configured to save any output data, model outputs are saved using the `netCDF4 `_ file format. 6 | 7 | 8 | Gridded Variables 9 | ================= 10 | 11 | In any given run, the saving parameters "save__grids" control whether or 12 | not that 2-D grid variable (e.g. velocity) is saved to the netCDF4 file. In 13 | the netCDF4 file, a 3-D array with the dimensions `time` :math:`\times` 14 | `x` :math:`\times` `y` is created for each 2-D grid variable that is set to 15 | be saved. Note that `x` is the *downstream* coordinate, rather than the 16 | Cartesian `x` when displaying the grid. The appropriate units for all 17 | variables are stored: for example "meters per second" for the *velocity* 18 | grid. 19 | 20 | .. note:: 21 | 22 | The format of the output netCDF file coordinate changed in `v2.1.0`. The 23 | old format is documented 24 | in :attr:`~pyDeltaRCM.model.DeltaModel.legacy_netcdf`, and that input 25 | parameter `legacy_netcdf` can be used to create on output netcdf file with 26 | the old coordinate configuration. 27 | 28 | 29 | Grid Coordinates 30 | ================ 31 | 32 | Grid coordinates are specified in the variables `time`, `x`, and `y` in the output netCDF4 file. 33 | These arrays are 1D arrays, which specify the location of each cell in the domain in *dimensional* coordinates (e.g., meters). 34 | In the downstream direction, the distance of each cell from the inlet boundary is specified in `x` in meters. 35 | Similarly, the cross-domain distance is specified in `y` in meters. 36 | Lastly, the `time` variable is stored as a 1D array with model `time` in seconds. 37 | 38 | 39 | Model Metadata 40 | ============== 41 | 42 | In addition to the grid coordinates, model metadata is saved as a group of 43 | 1-D arrays (vectors) and 0-D arrays (floats and integers). The values that are 44 | saved as metadata are the following: 45 | 46 | - Length of the land surface: `L0` 47 | - Width of the inlet channel: `N0` 48 | - Center of the domain: `CTR` 49 | - Length of cell faces: `dx` 50 | - Depth of inlet channel: `h0` 51 | - Sea level: `H_SL` 52 | - Bedload fraction: `f_bedload` 53 | - Sediment concentration: `C0_percent` 54 | - Characteristic Velocity: `u0` 55 | - If subsidence is enabled: 56 | - Subsidence start time: `start_subsidence` 57 | - Subsidence rate: `sigma` 58 | 59 | 60 | Working with Model Outputs 61 | ========================== 62 | 63 | The resulting netCDF4 output file can be read using any netCDF4-compatible 64 | library. These libraries range from the 65 | `netCDF4 Python package `_ itself, 66 | to higher-level libraries such as 67 | `xarray `_. For deltas, and specifically 68 | *pyDeltaRCM*, there is also a package under development called 69 | `DeltaMetrics `_, 70 | that is being designed to help post-process and analyze *pyDeltaRCM* outputs. 71 | 72 | 73 | Here, we show how to read the output NetCDF file with Python package ``netCDF4``. 74 | 75 | .. code:: 76 | 77 | import netCDF4 as nc 78 | 79 | data = nc.Dataset('pyDeltaRCM_output.nc') # the output file path! 80 | 81 | This `data` object is a `Dataset` object that can be sliced the same was as a `numpy` array. 82 | For example, we can slice the final bed elevation and velocity of a model run: 83 | 84 | .. code:: 85 | 86 | final_bed_elevation = data['eta'][-1, :, :] 87 | final_velocity = data['velocity'][-1, :, :] 88 | 89 | These slices look like this, if we were to plot them. 90 | 91 | .. plot:: guides/output_file.py 92 | -------------------------------------------------------------------------------- /docs/source/info/yamlparameters.rst: -------------------------------------------------------------------------------- 1 | *************** 2 | YAML Parameters 3 | *************** 4 | 5 | Configurable model parameters are listed in the 6 | :doc:`../reference/model/yaml_defaults`. 7 | Links to the API documentation for different types of YAML Parameters are 8 | provided below. The YAML parameters are sorted by "type", for example, 9 | :ref:`model-domain-parameters` are those parameters which control the 10 | definition of the pyDeltaRCM model domain. 11 | 12 | .. hint:: 13 | 14 | View the complete list of default values and expected types 15 | here: :doc:`../reference/model/yaml_defaults`. 16 | 17 | 18 | Model Settings 19 | ============== 20 | 21 | :attr:`pyDeltaRCM.model.DeltaModel.out_dir` 22 | 23 | :attr:`pyDeltaRCM.model.DeltaModel.verbose` 24 | 25 | 26 | .. _model-domain-parameters: 27 | 28 | Model Domain Parameters 29 | ======================= 30 | 31 | :attr:`pyDeltaRCM.model.DeltaModel.Length` 32 | 33 | :attr:`pyDeltaRCM.model.DeltaModel.Width` 34 | 35 | :attr:`pyDeltaRCM.model.DeltaModel.dx` 36 | 37 | :attr:`pyDeltaRCM.model.DeltaModel.L0_meters` 38 | 39 | :attr:`pyDeltaRCM.model.DeltaModel.N0_meters` 40 | 41 | :attr:`pyDeltaRCM.model.DeltaModel.S0` 42 | 43 | :attr:`pyDeltaRCM.model.DeltaModel.u0` 44 | 45 | :attr:`pyDeltaRCM.model.DeltaModel.h0` 46 | 47 | :attr:`pyDeltaRCM.model.DeltaModel.hb` 48 | 49 | :attr:`pyDeltaRCM.model.DeltaModel.H_SL` 50 | 51 | :attr:`pyDeltaRCM.model.DeltaModel.seed` 52 | 53 | :attr:`pyDeltaRCM.model.DeltaModel.SLR` 54 | 55 | :attr:`pyDeltaRCM.model.DeltaModel.f_bedload` 56 | 57 | :attr:`pyDeltaRCM.model.DeltaModel.C0_percent` 58 | 59 | :attr:`pyDeltaRCM.model.DeltaModel.active_layer_thickness` 60 | 61 | :attr:`pyDeltaRCM.model.DeltaModel.toggle_subsidence` 62 | 63 | :attr:`pyDeltaRCM.model.DeltaModel.subsidence_rate` 64 | 65 | :attr:`pyDeltaRCM.model.DeltaModel.start_subsidence` 66 | 67 | 68 | Reduced-Complexity Routing Parameters 69 | ===================================== 70 | 71 | :attr:`pyDeltaRCM.model.DeltaModel.Np_water` 72 | 73 | :attr:`pyDeltaRCM.model.DeltaModel.Np_sed` 74 | 75 | :attr:`pyDeltaRCM.model.DeltaModel.omega_sfc` 76 | 77 | :attr:`pyDeltaRCM.model.DeltaModel.omega_flow` 78 | 79 | :attr:`pyDeltaRCM.model.DeltaModel.Nsmooth` 80 | 81 | :attr:`pyDeltaRCM.model.DeltaModel.Csmooth` 82 | 83 | :attr:`pyDeltaRCM.model.DeltaModel.theta_water` 84 | 85 | :attr:`pyDeltaRCM.model.DeltaModel.coeff_theta_sand` 86 | 87 | :attr:`pyDeltaRCM.model.DeltaModel.coeff_theta_mud` 88 | 89 | :attr:`pyDeltaRCM.model.DeltaModel.beta` 90 | 91 | :attr:`pyDeltaRCM.model.DeltaModel.sed_lag` 92 | 93 | :attr:`pyDeltaRCM.model.DeltaModel.coeff_U_dep_mud` 94 | 95 | :attr:`pyDeltaRCM.model.DeltaModel.coeff_U_ero_mud` 96 | 97 | :attr:`pyDeltaRCM.model.DeltaModel.coeff_U_ero_sand` 98 | 99 | :attr:`pyDeltaRCM.model.DeltaModel.alpha` 100 | 101 | :attr:`pyDeltaRCM.model.DeltaModel.itermax` 102 | 103 | :attr:`pyDeltaRCM.model.DeltaModel.stepmax` 104 | 105 | 106 | Output Settings 107 | =============== 108 | 109 | :attr:`pyDeltaRCM.model.DeltaModel.save_eta_figs` 110 | 111 | :attr:`pyDeltaRCM.model.DeltaModel.save_stage_figs` 112 | 113 | :attr:`pyDeltaRCM.model.DeltaModel.save_depth_figs` 114 | 115 | :attr:`pyDeltaRCM.model.DeltaModel.save_discharge_figs` 116 | 117 | :attr:`pyDeltaRCM.model.DeltaModel.save_velocity_figs` 118 | 119 | :attr:`pyDeltaRCM.model.DeltaModel.save_sedflux_figs` 120 | 121 | :attr:`pyDeltaRCM.model.DeltaModel.save_sandfrac_figs` 122 | 123 | :attr:`pyDeltaRCM.model.DeltaModel.save_figs_sequential` 124 | 125 | :attr:`pyDeltaRCM.model.DeltaModel.save_eta_grids` 126 | 127 | :attr:`pyDeltaRCM.model.DeltaModel.save_stage_grids` 128 | 129 | :attr:`pyDeltaRCM.model.DeltaModel.save_depth_grids` 130 | 131 | :attr:`pyDeltaRCM.model.DeltaModel.save_discharge_grids` 132 | 133 | :attr:`pyDeltaRCM.model.DeltaModel.save_velocity_grids` 134 | 135 | :attr:`pyDeltaRCM.model.DeltaModel.save_sedflux_grids` 136 | 137 | :attr:`pyDeltaRCM.model.DeltaModel.save_sandfrac_grids` 138 | 139 | :attr:`pyDeltaRCM.model.DeltaModel.save_discharge_components` 140 | 141 | :attr:`pyDeltaRCM.model.DeltaModel.save_velocity_components` 142 | 143 | :attr:`pyDeltaRCM.model.DeltaModel.save_dt` 144 | 145 | :attr:`pyDeltaRCM.model.DeltaModel.checkpoint_dt` 146 | 147 | :attr:`pyDeltaRCM.model.DeltaModel.save_checkpoint` 148 | 149 | :attr:`pyDeltaRCM.model.DeltaModel.resume_checkpoint` 150 | 151 | :attr:`pyDeltaRCM.model.DeltaModel.clobber_netcdf` 152 | 153 | :attr:`pyDeltaRCM.model.DeltaModel.legacy_netcdf` 154 | -------------------------------------------------------------------------------- /docs/source/meta/citing.rst: -------------------------------------------------------------------------------- 1 | ******************* 2 | Citing *pyDeltaRCM* 3 | ******************* 4 | 5 | When citing *pyDeltaRCM*, please cite the `JOSS paper `_: 6 | 7 | Moodie et al., (2021). pyDeltaRCM: a flexible numerical delta model. Journal of Open Source Software, 6(64), 3398, https://doi.org/10.21105/joss.03398 8 | 9 | If you use BibTeX, you can add *pyDeltaRCM* to your `.bib` file using the following code: 10 | 11 | .. code:: console 12 | 13 | @article{Moodie2021, 14 | doi = {10.21105/joss.03398}, 15 | url = {https://doi.org/10.21105/joss.03398}, 16 | year = {2021}, 17 | publisher = {The Open Journal}, 18 | volume = {6}, 19 | number = {64}, 20 | pages = {3398}, 21 | author = {Andrew J. Moodie and Jayaram Hariharan and Eric Barefoot and Paola Passalacqua}, 22 | title = {*pyDeltaRCM*: a flexible numerical delta model}, 23 | journal = {Journal of Open Source Software} 24 | } 25 | -------------------------------------------------------------------------------- /docs/source/meta/conduct.rst: -------------------------------------------------------------------------------- 1 | 2 | .. include:: ../../../CODE_OF_CONDUCT.rst 3 | -------------------------------------------------------------------------------- /docs/source/meta/contributing.rst: -------------------------------------------------------------------------------- 1 | ************ 2 | Contributing 3 | ************ 4 | 5 | To contribute to this project, you must follow our :doc:`Code of Conduct ` at all times. 6 | If you are not familiar with our code of conduct policy, take a minute to read the policy before starting with your first contribution. 7 | 8 | 9 | How to contribute 10 | ----------------- 11 | 12 | We welcome contributions of many types, including but not limited to: 13 | 14 | * bug fixes 15 | * improvements to documentation 16 | * new features 17 | * additional examples for using and developing *pyDeltaRCM* 18 | 19 | If you are interested in contributing, please submit a pull request or get in touch with the development team via the `Github issue tracker `_. 20 | 21 | 22 | Issues and questions 23 | -------------------- 24 | 25 | If you have identified a bug within the code, but aren't sure how to (or don't want to) fix it, we invite you to open an issue on our `Github issue tracker `_. 26 | Please explain the problem as fully as possible, including any system information that may be relevant. 27 | 28 | You can also ask any questions about the software or ask for help on the `Github issue tracker `_. 29 | We will try our best to help you how we can! 30 | -------------------------------------------------------------------------------- /docs/source/meta/installing.rst: -------------------------------------------------------------------------------- 1 | ************ 2 | Installing 3 | ************ 4 | 5 | We recommend installing *pyDeltaRCM* in a virtual environment. 6 | That said, *pyDeltaRCM* depends on a small number of packages (:ref:`list of dependencies `), many of which are likely already in a Python user/developer's regular use, so it's probably safe to install *pyDeltaRCM* in your base environment, too. 7 | 8 | 9 | Installing 10 | ========== 11 | 12 | We describe installation flavors for both users and developers below. 13 | 14 | .. hint:: 15 | 16 | If you are looking to make any modifications to the model source code, you should follow the developer instructions. 17 | 18 | We suggest using the Anaconda Python distribution, which you can obtain via `the project website `_. 19 | 20 | Before proceeding, you may wish to create a virtual environment for the *pyDeltaRCM* project. 21 | With Anaconda on Linux: 22 | 23 | .. code:: console 24 | 25 | $ conda create -n deltarcm python=3 26 | $ conda activate deltarcm 27 | 28 | For more informtaion, see `this guide `_ for help on creating and activating a virtual environment with Anaconda on other platforms. 29 | See `this helpful guide `_ for creating virtual environments with `venv` if you do not use Anaconda. 30 | 31 | 32 | User installation 33 | ----------------- 34 | 35 | For a user installation, simply install from the pypi package repository: 36 | 37 | .. code:: console 38 | 39 | $ pip install pyDeltaRCM 40 | 41 | .. note:: 42 | 43 | You may need to `first install `_ `pip`. 44 | 45 | 46 | .. _dev-install: 47 | 48 | Developer installation 49 | ---------------------- 50 | 51 | For a developer installation, you should first fork the repository on Github. 52 | This will allow you to submit suggestions and contribute to *pyDeltaRCM*. 53 | 54 | .. note:: 55 | 56 | You do not *need* to create a fork if your are just testing, but it may save you time and headache down the road. If you choose not to, just use the main repository url below (https://github.com/DeltaRCM/pyDeltaRCM). 57 | 58 | First, you will need to `install git `_ if you do not already have it. 59 | Then, download or clone your fork of the project: 60 | 61 | .. code:: console 62 | 63 | $ git clone https://github.com//pyDeltaRCM.git 64 | 65 | Then, with current working directory as the root of the repository (e.g., ``cd pyDeltaRCM``), run the following commands: 66 | 67 | .. code:: console 68 | 69 | $ pip install -r requirements.txt 70 | $ pip install -r requirements-docs.txt 71 | $ pip install -r requirements-test.txt 72 | $ pip install -e . 73 | 74 | To check installation, run the complete test suite with: 75 | 76 | .. code:: console 77 | 78 | $ pytest --mpl --mpl-baseline-path=tests/imgs_baseline 79 | 80 | Finally, add the `upstream` repository to your `remote` repository list: 81 | 82 | .. code:: console 83 | 84 | $ git remote add upstream https://github.com/DeltaRCM/pyDeltaRCM.git 85 | 86 | You can build a local copy of the documentation with: 87 | 88 | .. code:: console 89 | 90 | $ (cd docs && make html) 91 | 92 | 93 | Next steps 94 | ========== 95 | 96 | Consider reading through the :doc:`10-minute tutorial ` or the :doc:`User Guide ` to help get you started using *pyDeltaRCM*. 97 | 98 | 99 | .. _dependencies-list: 100 | 101 | Dependencies 102 | ============ 103 | 104 | .. literalinclude:: ../../../requirements.txt 105 | :linenos: 106 | -------------------------------------------------------------------------------- /docs/source/meta/license.rst: -------------------------------------------------------------------------------- 1 | ************ 2 | License 3 | ************ 4 | 5 | This project is licensed under the MIT License - see the `full license `_ file for details. 6 | It is provided without warranty or guaranteed support. 7 | -------------------------------------------------------------------------------- /docs/source/meta/usedby.rst: -------------------------------------------------------------------------------- 1 | ******* 2 | Used By 3 | ******* 4 | 5 | Below are papers, presentations, and other material that use *pyDeltaRCM*. 6 | 7 | Papers 8 | ------ 9 | .. copied from "Chicago" style within Google Scholar 10 | 11 | [1] Moodie, Andrew J., and Paola Passalacqua. "When Does Faulting‐Induced Subsidence Drive Distributary Network Reorganization?." Geophysical Research Letters 48, no. 22 (2021): e2021GL095053. 12 | 13 | [2] Hariharan, Jayaram, Paola Passalacqua, Zhongyuan Xu, Holly A. Michael, Elisabeth Steel, Austin Chadwick, Chris Paola, and Andrew J. Moodie. "Modeling the Dynamic Response of River Deltas to Sea‐Level Rise Acceleration." Journal of Geophysical Research: Earth Surface 127, no. 9 (2022): e2022JF006762. 14 | 15 | 16 | Presentations 17 | ------------- 18 | 19 | 20 | 21 | Other 22 | ----- 23 | 24 | [1] Hariharan, Jayaram. "Exploring *pyDeltaRCM*: A Collection of Numerical Experiments." Zenodo v0.1 (2022), https://zenodo.org/records/7315646. -------------------------------------------------------------------------------- /docs/source/pyplots/debug_tools/debug_demo.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | import pyDeltaRCM 4 | 5 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 6 | delta = pyDeltaRCM.DeltaModel(out_dir=output_dir) 7 | 8 | delta.show_attribute('cell_type', grid=False) 9 | delta.show_attribute('cell_type', grid=False) 10 | delta.show_ind([3378, 9145, 11568, 514, 13558]) 11 | delta.show_ind((42, 94), 'bs') 12 | delta.show_ind([(41, 8), (42, 10)], 'g^') 13 | plt.show() 14 | -------------------------------------------------------------------------------- /docs/source/pyplots/guides/10min_demo.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | import pyDeltaRCM 4 | 5 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 6 | delta = pyDeltaRCM.DeltaModel(out_dir=output_dir) 7 | 8 | for _t in range(0, 5): 9 | delta.update() 10 | 11 | delta.finalize() 12 | 13 | 14 | fig, ax = plt.subplots() 15 | ax.imshow(delta.bed_elevation, vmax=-3) 16 | plt.show() 17 | -------------------------------------------------------------------------------- /docs/source/pyplots/guides/cover.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | import pyDeltaRCM 8 | 9 | 10 | # filter out the warning raised about no netcdf being found 11 | warnings.filterwarnings("ignore", category=UserWarning) 12 | 13 | 14 | n = 20 15 | cm = matplotlib.colormaps['tab10'] 16 | 17 | 18 | # init delta model 19 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 20 | 21 | delta = pyDeltaRCM.DeltaModel( 22 | out_dir=output_dir, 23 | resume_checkpoint='../../_resources/checkpoint') 24 | 25 | 26 | _shp = delta.eta.shape 27 | 28 | 29 | # manually call only the necessary paths 30 | delta.init_water_iteration() 31 | delta.run_water_iteration() 32 | 33 | 34 | # define a function to fill in the walks of given idx 35 | def _plot_idxs_walks_to_step(delta_inds, _step, _idxs, _ax) -> None: 36 | for i in range(len(_idxs)): 37 | iidx = _idxs[i] 38 | walk = delta_inds[iidx, :] 39 | walk = walk[:_step] 40 | pyDeltaRCM.debug_tools.plot_line( 41 | walk, shape=_shp, color='r', alpha=0.5, 42 | nozeros=True) 43 | yend, xend = pyDeltaRCM.shared_tools.custom_unravel( 44 | walk[-1], _shp) 45 | _ax.plot(xend, yend, 46 | marker='o', ms=3, color='r', alpha=0.5) 47 | 48 | 49 | # declare the idxs to use: 50 | np.random.seed(0) # make it reproducible 51 | idxs = np.random.randint(low=0, high=delta._Np_water, size=n) 52 | ps = 100 53 | 54 | # set up axis 55 | fig, ax = plt.subplots(figsize=(6, 3)) 56 | vmin, vmax = delta.eta.min(), delta.eta.max() 57 | 58 | # fill in axis2 59 | ax.imshow( 60 | delta.eta, vmin=vmin, vmax=vmax, cmap='cividis') 61 | ax.set_xticks([]) 62 | ax.set_yticks([]) 63 | _plot_idxs_walks_to_step( 64 | delta.free_surf_walk_inds, _step=ps, _idxs=idxs, _ax=ax) 65 | 66 | plt.tight_layout() 67 | plt.show() 68 | -------------------------------------------------------------------------------- /docs/source/pyplots/guides/output_file.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | import pyDeltaRCM 8 | 9 | 10 | # filter out the warning raised about no netcdf being found 11 | warnings.filterwarnings("ignore", category=UserWarning) 12 | 13 | 14 | n = 20 15 | cm = matplotlib.colormaps['tab10'] 16 | 17 | 18 | # init delta model 19 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 20 | 21 | delta = pyDeltaRCM.DeltaModel( 22 | out_dir=output_dir, 23 | resume_checkpoint='../../_resources/checkpoint') 24 | 25 | 26 | _shp = delta.eta.shape 27 | 28 | # set up axis 29 | fig, ax = plt.subplots(1, 2, figsize=(6, 3)) 30 | vmin, vmax = delta.eta.min(), delta.eta.max() 31 | 32 | # fill in axis 33 | ax[0].imshow( 34 | delta.eta, vmin=vmin, vmax=vmax, cmap='cividis') 35 | ax[0].set_xticks([]) 36 | ax[0].set_yticks([]) 37 | ax[0].set_title('bed elevation') 38 | 39 | ax[1].imshow( 40 | delta.uw, cmap='plasma') 41 | ax[1].set_xticks([]) 42 | ax[1].set_yticks([]) 43 | ax[1].set_title('velocity') 44 | 45 | plt.tight_layout() 46 | plt.show() 47 | -------------------------------------------------------------------------------- /docs/source/pyplots/init_tools/domain_basin_inlet_depth.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | 6 | import pyDeltaRCM 7 | 8 | 9 | # filter out the warning raised about no netcdf being found 10 | warnings.filterwarnings("ignore", category=UserWarning) 11 | 12 | 13 | n = 1 14 | cm = matplotlib.colormaps.get_cmap("tab10") 15 | 16 | param_dict = {"timesteps": 0} 17 | _matrix = {"h0": [2, 5], "hb": [2, 5]} 18 | param_dict["matrix"] = _matrix 19 | param_dict["L0_meters"] = 500 20 | param_dict["N0_meters"] = 500 21 | 22 | # init delta models with preprocessor 23 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 24 | param_dict.update({"out_dir": output_dir}) 25 | 26 | pp = pyDeltaRCM.preprocessor.Preprocessor(param_dict) 27 | 28 | pp.run_jobs() 29 | 30 | 31 | fig, ax = plt.subplots( 32 | 2, 2, figsize=(6, 4), subplot_kw=dict(aspect="equal"), sharex=True, sharey=True 33 | ) 34 | 35 | ax = ax.ravel() 36 | for i in range(4): 37 | ax[i].imshow( 38 | pp.job_list[i].deltamodel.eta, 39 | interpolation="none", 40 | extent=[ 41 | 0, 42 | pp.job_list[i].deltamodel.Width, 43 | pp.job_list[i].deltamodel.Length, 44 | 0, 45 | ], 46 | ) 47 | ax[i].text( 48 | 0.05, 49 | 0.05, 50 | f"h0: {pp.job_list[i].deltamodel.h0}\nhb: {pp.job_list[i].deltamodel.hb}", 51 | ha="left", 52 | va="bottom", 53 | color="white", 54 | fontsize=8, 55 | transform=ax[i].transAxes, 56 | ) 57 | 58 | for i, axi in enumerate(ax.ravel()): 59 | axi.tick_params(labelsize=7) 60 | if i % 2 == 0: 61 | axi.set_ylabel("Length", fontsize=8) 62 | if i > 2: 63 | axi.set_xlabel("Width", fontsize=8) 64 | 65 | plt.tight_layout() 66 | plt.show() 67 | -------------------------------------------------------------------------------- /docs/source/pyplots/init_tools/domain_inlet_geometry.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | 6 | import pyDeltaRCM 7 | 8 | 9 | # filter out the warning raised about no netcdf being found 10 | warnings.filterwarnings("ignore", category=UserWarning) 11 | 12 | 13 | n = 1 14 | cm = matplotlib.colormaps.get_cmap("tab10") 15 | 16 | param_dict = {"timesteps": 0} 17 | _matrix = {"L0_meters": [200, 500, 1000], "N0_meters": [200, 500, 1000]} 18 | param_dict["matrix"] = _matrix 19 | 20 | # init delta models with preprocessor 21 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 22 | param_dict.update({"out_dir": output_dir}) 23 | 24 | pp = pyDeltaRCM.preprocessor.Preprocessor(param_dict) 25 | 26 | pp.run_jobs() 27 | 28 | 29 | fig, ax = plt.subplots( 30 | 3, 3, figsize=(9, 5), subplot_kw=dict(aspect="equal"), sharex=True, sharey=True 31 | ) 32 | 33 | ax = ax.ravel() 34 | for i in range(9): 35 | ax[i].imshow( 36 | pp.job_list[i].deltamodel.eta, 37 | interpolation="none", 38 | extent=[ 39 | 0, 40 | pp.job_list[i].deltamodel.Width, 41 | pp.job_list[i].deltamodel.Length, 42 | 0, 43 | ], 44 | ) 45 | ax[i].text( 46 | 0.05, 47 | 0.05, 48 | f"L0_meters: {pp.job_list[i].deltamodel.L0_meters}\nN0_meters: {pp.job_list[i].deltamodel.N0_meters}", 49 | ha="left", 50 | va="bottom", 51 | color="white", 52 | fontsize=8, 53 | transform=ax[i].transAxes, 54 | ) 55 | 56 | for i, axi in enumerate(ax.ravel()): 57 | axi.tick_params(labelsize=7) 58 | if i % 3 == 0: 59 | axi.set_ylabel("Length", fontsize=8) 60 | if i > 6: 61 | axi.set_xlabel("Width", fontsize=8) 62 | 63 | plt.tight_layout() 64 | plt.show() 65 | -------------------------------------------------------------------------------- /docs/source/pyplots/init_tools/domain_parameters.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | 6 | import pyDeltaRCM 7 | 8 | # this creates a large plot showing a bunch of the basin parameters 9 | 10 | # filter out the warning raised about no netcdf being found 11 | warnings.filterwarnings("ignore", category=UserWarning) 12 | 13 | 14 | n = 1 15 | cm = matplotlib.colormaps.get_cmap("tab10") 16 | 17 | param_dict = {"timesteps": 0} 18 | # _matrix = {"Length": [2500, 5000, 10000]} 19 | # param_dict["matrix"] = _matrix 20 | LENGTH = 2000 21 | WIDTH = 4000 22 | param_dict["Length"] = LENGTH 23 | param_dict["Width"] = WIDTH 24 | 25 | # init delta model 26 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 27 | param_dict["out_dir"] = output_dir 28 | delta = pyDeltaRCM.DeltaModel(**param_dict) 29 | 30 | fig, ax = plt.subplots( 31 | figsize=(6, 3.5), 32 | subplot_kw=dict(aspect="equal"), 33 | ) 34 | 35 | 36 | ax.imshow(delta.eta, interpolation="none", extent=[0, delta.Width, delta.Length, 0]) 37 | 38 | # computational edge 39 | ax.contour( 40 | delta.X[1:, 1:], 41 | delta.Y[1:, 1:], 42 | delta.cell_type, 43 | levels=[-1], 44 | colors="white", 45 | linewidths=[1], 46 | linestyles=["-"], 47 | ) 48 | ax.annotate( 49 | "computational\ndomain edge:\n Length, Width", 50 | (0.2 * WIDTH, 0.8 * LENGTH), 51 | (0.25 * WIDTH + delta.dx, 0.75 * LENGTH - delta.dx), 52 | fontsize=8, 53 | color="white", 54 | arrowprops=dict(arrowstyle="-", color="white"), 55 | ) 56 | 57 | # inlet 58 | inlet_x = (delta.CTR + 1) * delta.dx 59 | inlet_y = (delta.L0 - 2) * delta.dx 60 | ax.annotate( 61 | "inlet geometry:\n h0, N0_meters, L0_meters", 62 | (inlet_x, inlet_y), # point 63 | (inlet_x - (10 * delta.dx), inlet_y + (10 * delta.dx)), # label 64 | fontsize=8, 65 | color="white", 66 | textcoords="data", 67 | arrowprops=dict(arrowstyle="-", color="white"), 68 | ) 69 | 70 | # basin depth 71 | ax.annotate( 72 | "basin depth:\n hb", 73 | (0.75 * WIDTH, 0.45 * LENGTH), 74 | (0.65 * WIDTH, 0.6 * LENGTH), 75 | fontsize=8, 76 | color="white", 77 | arrowprops=dict(arrowstyle="-", color="white"), 78 | ) 79 | 80 | ax.set_ylabel("Length", fontsize=8) 81 | 82 | ax.tick_params(labelsize=7) 83 | ax.set_xlabel("Width", fontsize=8) 84 | 85 | plt.tight_layout() 86 | plt.show() 87 | -------------------------------------------------------------------------------- /docs/source/pyplots/init_tools/domain_size_compare.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | 6 | import pyDeltaRCM 7 | 8 | 9 | # filter out the warning raised about no netcdf being found 10 | warnings.filterwarnings("ignore", category=UserWarning) 11 | 12 | 13 | n = 1 14 | cm = matplotlib.colormaps.get_cmap("tab10") 15 | 16 | param_dict = {"timesteps": 0} 17 | _matrix = {"Length": [2500, 5000, 10000]} 18 | param_dict["matrix"] = _matrix 19 | 20 | # init delta models with preprocessor 21 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 22 | param_dict.update({"out_dir": output_dir}) 23 | 24 | pp = pyDeltaRCM.preprocessor.Preprocessor(param_dict) 25 | 26 | pp.run_jobs() 27 | 28 | 29 | fig, ax = plt.subplots( 30 | 1, 31 | 3, 32 | figsize=(9, 3.5), 33 | subplot_kw=dict(aspect="equal"), 34 | gridspec_kw=dict(width_ratios=[1, 1, 1]), 35 | ) 36 | 37 | for i in range(3): 38 | ax[i].imshow( 39 | pp.job_list[i].deltamodel.eta, 40 | interpolation="none", 41 | extent=[ 42 | 0, 43 | pp.job_list[i].deltamodel.Width, 44 | pp.job_list[i].deltamodel.Length, 45 | 0, 46 | ], 47 | ) 48 | ax[i].contour( 49 | pp.job_list[i].deltamodel.X[1:, 1:], 50 | pp.job_list[i].deltamodel.Y[1:, 1:], 51 | pp.job_list[i].deltamodel.cell_type, 52 | levels=[-1], 53 | colors="white", 54 | linewidths=[1], 55 | linestyles=["-"], 56 | ) 57 | 58 | ax[2].annotate( 59 | "computational\ndomain edge", 60 | (2000, 4000), 61 | (200, 6400), 62 | fontsize=8, 63 | color="white", 64 | arrowprops=dict(arrowstyle="-", color="white"), 65 | ) 66 | 67 | ax[0].set_ylabel("Length", fontsize=8) 68 | 69 | for axi in ax.ravel(): 70 | axi.tick_params(labelsize=7) 71 | axi.set_xlabel("Width", fontsize=8) 72 | 73 | plt.tight_layout() 74 | plt.show() 75 | -------------------------------------------------------------------------------- /docs/source/pyplots/modeltime/_base.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | time = np.arange(365) 4 | hydrograph = np.ones((len(time),)) + \ 5 | (np.random.uniform(size=(len(time),)) / 10) 6 | hydrograph[100:150] = 2 + np.sin(np.arange(15, 65) / 15) 7 | flood = hydrograph >= 2.5 8 | -------------------------------------------------------------------------------- /docs/source/pyplots/modeltime/four_year_condensed_plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | 5 | import _base 6 | 7 | 8 | fig, ax = plt.subplots(figsize=(8, 2)) 9 | plt.subplots_adjust(top=0.7) 10 | 11 | nflood = np.sum(_base.flood) 12 | day = 0 13 | for i in range(4): 14 | ax.axvline(x=day, color='k', ls='-') 15 | ax.fill_between(day + np.arange(nflood + 1), np.zeros((nflood + 1,)), 16 | 4 * np.ones((nflood + 1,)), 17 | alpha=0.4, edgecolor='none') 18 | ax.plot(day + np.arange(nflood + 1), 2.5 * np.ones((nflood + 1),)) 19 | day += nflood 20 | 21 | ax.axvline(x=day, color='k', ls='-') 22 | ax.set_ylim(0.9, 3.1) 23 | ax.set_xlim(0 - 10, 365 * 4 + 10) 24 | ax.set_yticks([]) 25 | ax.set_xlabel(r'time $\rightarrow$') 26 | ax.set_yticks([1.05, 2.5]) 27 | ax.set_yticklabels(['base flow', 'bankfull flow']) 28 | 29 | plt.show() 30 | -------------------------------------------------------------------------------- /docs/source/pyplots/modeltime/four_year_plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | 5 | import _base 6 | 7 | 8 | fig, ax = plt.subplots(2, 1, figsize=(8, 4), sharex=True) 9 | # plt.subplots_adjust(top=0.7) 10 | 11 | 12 | day = 0 13 | for i in range(4): 14 | ax[0].axvline(x=day, color='k', ls='-') 15 | ax[0].fill_between(day + np.arange(365), np.zeros((len(_base.time),)), 16 | 4 * np.ones((len(_base.time),)), 17 | where=_base.flood, alpha=0.4, edgecolor='none') 18 | ax[0].plot(day + np.arange(365), _base.hydrograph) 19 | ax[0].text(day + 220, 2.6, 'year ' + str(i)) 20 | day += 365 21 | 22 | ax[0].axvline(x=day, color='k', ls='-') 23 | ax[0].set_ylim(0.9, 3.1) 24 | ax[0].set_xlim(0 - 10, day + 10) 25 | ax[0].set_xlabel(r'time $\rightarrow$') 26 | ax[0].set_yticks([1.05, 2.5]) 27 | ax[0].set_yticklabels(['base flow', 'bankfull flow']) 28 | 29 | 30 | nflood = np.sum(_base.flood) 31 | day = 0 32 | for i in range(4): 33 | ax[1].axvline(x=day, color='k', ls='-') 34 | ax[1].fill_between(day + np.arange(nflood + 1), np.zeros((nflood + 1,)), 35 | 4 * np.ones((nflood + 1,)), 36 | alpha=0.4, edgecolor='none') 37 | ax[1].plot(day + np.arange(nflood + 1), 2.5 * np.ones((nflood + 1),)) 38 | day += nflood 39 | 40 | ax[1].axvline(x=day, color='k', ls='-') 41 | ax[1].set_ylim(0.9, 3.1) 42 | ax[1].set_xlim(0 - 10, 365 * 4 + 10) 43 | ax[1].set_yticks([]) 44 | ax[1].set_xlabel(r'time $\rightarrow$') 45 | ax[1].set_yticks([1.05, 2.5]) 46 | ax[1].set_yticklabels(['base flow', 'bankfull flow']) 47 | 48 | 49 | plt.show() 50 | -------------------------------------------------------------------------------- /docs/source/pyplots/modeltime/one_year_plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | import _base 5 | from typing import Dict 6 | 7 | fig, ax = plt.subplots() 8 | plt.subplots_adjust(left=0.2) 9 | ax.plot(_base.time, _base.hydrograph) 10 | ax.axhline(y=2.5, color='k', ls='--') 11 | ax.fill_between(np.arange(365), 2.5 * np.ones((len(_base.time),)), 12 | _base.hydrograph, where=_base.flood, alpha=0.4) 13 | ax.set_yticks([1.05, 2.5]) 14 | ax.set_yticklabels(['base flow', 'bankfull flow']) 15 | ax.set_xlabel('calendar day') 16 | ax.set_ylim(0.9, 3.1) 17 | 18 | bbox: Dict[str, str] = dict(boxstyle="round", fc="0.8") 19 | _cs0 = "angle,angleA=-10,angleB=-60,rad=10" 20 | ax.annotate('start event', xy=(95, 1.1), xytext=(0, 1.4), 21 | bbox=bbox, arrowprops=dict(arrowstyle="->", connectionstyle=_cs0)) 22 | _cs1 = "angle,angleA=10,angleB=60,rad=10" 23 | ax.annotate('end event', xy=(150, 1.1), xytext=(170, 1.4), 24 | bbox=bbox, arrowprops=dict(arrowstyle="->", connectionstyle=_cs1)) 25 | _cs2 = "angle,angleA=-10,angleB=60,rad=10" 26 | ax.annotate('flooding duration', xy=(110, 2.7), xytext=(150, 2.7), 27 | bbox=bbox, arrowprops=dict(arrowstyle="->", connectionstyle=_cs2)) 28 | 29 | plt.show() 30 | -------------------------------------------------------------------------------- /docs/source/pyplots/sed_tools/_initial_bed_state.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | import pyDeltaRCM 7 | 8 | # filter out the warning raised about no netcdf being found 9 | warnings.filterwarnings("ignore", category=UserWarning) 10 | 11 | 12 | # init delta model 13 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 14 | delta = pyDeltaRCM.DeltaModel( 15 | out_dir=output_dir, 16 | resume_checkpoint='../../_resources/checkpoint') 17 | 18 | _shp = delta.eta.shape 19 | 20 | # set up axis 21 | fig, ax = plt.subplots() 22 | 23 | # fill in axis2 24 | pyDeltaRCM.debug_tools.plot_domain( 25 | delta.eta, ax=ax, grid=False, cmap='cividis') 26 | ax.set_title('intial bed elevation (m)') 27 | 28 | 29 | plt.tight_layout() 30 | plt.show() 31 | -------------------------------------------------------------------------------- /docs/source/pyplots/sed_tools/route_all_mud_parcels.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | import pyDeltaRCM 7 | 8 | # filter out the warning raised about no netcdf being found 9 | warnings.filterwarnings("ignore", category=UserWarning) 10 | 11 | 12 | # init delta model 13 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 14 | delta = pyDeltaRCM.DeltaModel( 15 | out_dir=output_dir, 16 | resume_checkpoint='../../_resources/checkpoint') 17 | 18 | _shp = delta.eta.shape 19 | 20 | _eta_before = np.copy(delta.eta) 21 | 22 | delta.route_all_mud_parcels() 23 | 24 | _eta_after = np.copy(delta.eta) 25 | 26 | 27 | # set up axis 28 | fig, ax = plt.subplots() 29 | 30 | # fill in axis2 31 | _diff = _eta_after - _eta_before 32 | pyDeltaRCM.debug_tools.plot_domain( 33 | _diff, ax=ax, grid=False, cmap='RdBu', 34 | vmin=-0.1, vmax=0.1) 35 | ax.set_title('bed elevation change (m) \n due to mud parcels') 36 | 37 | 38 | plt.tight_layout() 39 | plt.show() 40 | -------------------------------------------------------------------------------- /docs/source/pyplots/sed_tools/route_all_sand_parcels.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | import pyDeltaRCM 7 | 8 | # filter out the warning raised about no netcdf being found 9 | warnings.filterwarnings("ignore", category=UserWarning) 10 | 11 | 12 | # init delta model 13 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 14 | delta = pyDeltaRCM.DeltaModel( 15 | out_dir=output_dir, 16 | resume_checkpoint='../../_resources/checkpoint') 17 | 18 | _shp = delta.eta.shape 19 | 20 | _eta_before = np.copy(delta.eta) 21 | 22 | delta.route_all_sand_parcels() 23 | 24 | _eta_after = np.copy(delta.eta) 25 | 26 | 27 | # set up axis 28 | fig, ax = plt.subplots() 29 | 30 | # fill in axis2 31 | _diff = _eta_after - _eta_before 32 | pyDeltaRCM.debug_tools.plot_domain( 33 | _diff, ax=ax, grid=False, cmap='RdBu', 34 | vmin=-0.1, vmax=0.1) 35 | ax.set_title('bed elevation change (m) \n due to sand parcels') 36 | 37 | 38 | plt.tight_layout() 39 | plt.show() 40 | -------------------------------------------------------------------------------- /docs/source/pyplots/sed_tools/sediment_weights_examples.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | import pyDeltaRCM 8 | 9 | 10 | # filter out the warning raised about no netcdf being found 11 | warnings.filterwarnings("ignore", category=UserWarning) 12 | 13 | 14 | n = 10 15 | cm = matplotlib.colormaps['tab10'] 16 | 17 | 18 | class SedimentWeightingCalculator(pyDeltaRCM.DeltaModel): 19 | 20 | def __init__(self, input_file=None, **kwargs) -> None: 21 | 22 | # inherit from base model 23 | super().__init__(input_file, **kwargs) 24 | 25 | def get_sediment_weight_array(self) -> None: 26 | sand_weights = np.zeros((self.L, self.W, 9)) 27 | mud_weights = np.zeros((self.L, self.W, 9)) 28 | 29 | for i in range(self.L): 30 | for j in range(self.W): 31 | stage_nbrs = self.pad_stage[i:i + 3, j:j + 3] 32 | depth_nbrs = self.pad_depth[i:i + 3, j:j + 3] 33 | ct_nbrs = self.pad_cell_type[i:i + 3, j:j + 3] 34 | 35 | _, weight_int = pyDeltaRCM.shared_tools.get_weight_sfc_int( 36 | self.stage[i, j], stage_nbrs.ravel(), 37 | self.qx[i, j], self.qy[i, j], self.ivec_flat, 38 | self.jvec_flat, self.distances_flat) 39 | 40 | try: 41 | sand_weights[i, j] = pyDeltaRCM.sed_tools._get_weight_at_cell_sediment( 42 | (i, j), weight_int, depth_nbrs.ravel(), ct_nbrs.ravel(), 43 | self.dry_depth, self.theta_sand, self.distances_flat) 44 | 45 | mud_weights[i, j] = pyDeltaRCM.sed_tools._get_weight_at_cell_sediment( 46 | (i, j), weight_int, depth_nbrs.ravel(), ct_nbrs.ravel(), 47 | self.dry_depth, self.theta_mud, self.distances_flat) 48 | except Exception: 49 | sand_weights[i, j] = np.nan 50 | mud_weights[i, j] = np.nan 51 | 52 | self.sand_weights = sand_weights 53 | self.mud_weights = mud_weights 54 | 55 | 56 | # init delta model 57 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 58 | delta = SedimentWeightingCalculator( 59 | out_dir=output_dir, 60 | resume_checkpoint='../../_resources/checkpoint') 61 | 62 | delta.init_water_iteration() 63 | delta.run_water_iteration() 64 | delta.compute_free_surface() 65 | delta.finalize_free_surface() 66 | 67 | delta.get_sediment_weight_array() 68 | 69 | _shp = delta.eta.shape 70 | 71 | 72 | # manually call only the necessary paths 73 | delta.init_water_iteration() 74 | delta.run_water_iteration() 75 | 76 | 77 | NPLOT = 5 78 | hdr: int = NPLOT // 2 79 | 80 | # fig, ax = plt.subplots() 81 | fig = plt.figure(figsize=(6, 9)) 82 | gs = fig.add_gridspec( 83 | nrows=NPLOT+hdr, ncols=5, 84 | left=0.05, right=0.95, top=0.95, bottom=0.05, 85 | wspace=0.01, hspace=0.2) 86 | 87 | hdr_ax = fig.add_subplot(gs[:hdr, :]) 88 | pyDeltaRCM.debug_tools.plot_domain( 89 | delta.eta, ax=hdr_ax, grid=False, cmap='cividis', vmin=-3, vmax=0.5) 90 | hdr_ax.set_xticks([]) 91 | hdr_ax.set_yticks([]) 92 | hdr_ax.set_xlim(0, delta.W // 2) 93 | hdr_ax.set_ylim(delta.L // 2, 0) 94 | 95 | 96 | def plot_pxpy_weights(pxpy, i): 97 | 98 | px, py = pxpy 99 | 100 | hdr_ax.text(py, px, str(i-hdr), 101 | fontsize=9, color='white', 102 | ha='center', va='center') 103 | 104 | __ax_list = [] 105 | 106 | def _make_single_axis(i, j, values, **kwargs): 107 | __ax = fig.add_subplot(gs[i, j]) 108 | __ax.set_xticks([]) 109 | __ax.set_yticks([]) 110 | __ax.imshow(values, **kwargs) 111 | for _i in range(3): 112 | for _j in range(3): 113 | __ax.text( 114 | _j, _i, str(np.round(values[_i, _j], 2)), 115 | ha='center', va='center', fontsize=8) 116 | return __ax 117 | 118 | # grab the data from the fields and put it into axis 119 | _eta_data = delta.eta[px-1:px+2, py-1:py+2] 120 | _eta_ax = _make_single_axis( 121 | i, 0, _eta_data, cmap='cividis', vmin=-3, vmax=0.5) 122 | __ax_list.append(_eta_ax) 123 | 124 | _dpth_data = delta.depth[px-1:px+2, py-1:py+2] 125 | _dpth_ax = _make_single_axis( 126 | i, 1, _dpth_data, cmap='Blues', vmin=0, vmax=5) 127 | __ax_list.append(_dpth_ax) 128 | 129 | _vel_data = delta.uw[px-1:px+2, py-1:py+2] 130 | _vel_ax = _make_single_axis( 131 | i, 2, _vel_data, cmap='plasma', vmin=0, vmax=1.5) 132 | __ax_list.append(_vel_ax) 133 | 134 | _sandwght_data = delta.sand_weights[px, py, :].reshape((3, 3)) 135 | _sandwght_ax = _make_single_axis( 136 | i, 3, _sandwght_data, cmap='YlGn', vmin=0, vmax=1) 137 | __ax_list.append(_sandwght_ax) 138 | 139 | _mudwght_data = delta.mud_weights[px, py, :].reshape((3, 3)) 140 | _mudwght_ax = _make_single_axis( 141 | i, 4, _mudwght_data, cmap='YlGn', vmin=0, vmax=1) 142 | __ax_list.append(_mudwght_ax) 143 | 144 | return __ax_list 145 | 146 | 147 | # define the example location set 148 | _ex_set = [(10, 94), (20, 78), (38, 72), (22, 87), (47, 43)] 149 | 150 | 151 | # plot the points 152 | ax0 = plot_pxpy_weights(_ex_set[0], hdr+0) 153 | ax1 = plot_pxpy_weights(_ex_set[1], hdr+1) 154 | ax2 = plot_pxpy_weights(_ex_set[2], hdr+2) 155 | ax3 = plot_pxpy_weights(_ex_set[3], hdr+3) 156 | ax4 = plot_pxpy_weights(_ex_set[4], hdr+4) 157 | 158 | 159 | # labels 160 | for a, axx in enumerate([ax0, ax1, ax2, ax3, ax4]): 161 | axx[0].set_ylabel(str(a), rotation=0, labelpad=10, 162 | ha='center', va='center') 163 | 164 | albls = ['bed elevation\n(eta)', 'depth', 165 | 'velocity\n(uw)', 'sand weights', 'mud weights'] 166 | for a, (axx, albl) in enumerate(zip(ax4, albls)): 167 | axx.set_xlabel(albl) 168 | 169 | # show 170 | plt.show() 171 | -------------------------------------------------------------------------------- /docs/source/pyplots/sed_tools/topo_diffusion.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | import pyDeltaRCM 7 | 8 | # filter out the warning raised about no netcdf being found 9 | warnings.filterwarnings("ignore", category=UserWarning) 10 | 11 | 12 | # init delta model 13 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 14 | delta = pyDeltaRCM.DeltaModel( 15 | out_dir=output_dir, 16 | resume_checkpoint='../../_resources/checkpoint') 17 | 18 | _shp = delta.eta.shape 19 | 20 | delta.route_all_sand_parcels() 21 | 22 | _eta_before = np.copy(delta.eta) 23 | delta.topo_diffusion() 24 | _eta_after = np.copy(delta.eta) 25 | 26 | # set up axis 27 | fig, ax = plt.subplots(1, 3, sharex=True, sharey=True, figsize=(12, 4)) 28 | 29 | # fill in axis0 30 | pyDeltaRCM.debug_tools.plot_domain( 31 | _eta_before, ax=ax[0], grid=False, cmap='cividis', vmin=-6) 32 | ax[0].set_title('bed elevation before \n topographic diffusion') 33 | 34 | # fill in axis1 35 | pyDeltaRCM.debug_tools.plot_domain( 36 | _eta_after, ax=ax[1], grid=False, cmap='cividis', vmin=-6) 37 | ax[1].set_title('bed elevation before \n topographic diffusion') 38 | 39 | 40 | # fill in axis2 41 | _diff = _eta_after - _eta_before 42 | pyDeltaRCM.debug_tools.plot_domain( 43 | _diff, ax=ax[2], grid=False, cmap='RdBu', 44 | vmin=-0.1, vmax=0.1) 45 | ax[2].set_title('difference (after - before)') 46 | 47 | 48 | plt.tight_layout() 49 | plt.show() 50 | -------------------------------------------------------------------------------- /docs/source/pyplots/water_tools/_accumulate_free_surface_walks.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | import pyDeltaRCM 8 | 9 | 10 | # filter out the warning raised about no netcdf being found 11 | warnings.filterwarnings("ignore", category=UserWarning) 12 | 13 | 14 | n = 1 15 | cm = matplotlib.colormaps['tab10'] 16 | 17 | 18 | # init delta model 19 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 20 | delta = pyDeltaRCM.DeltaModel( 21 | out_dir=output_dir, 22 | resume_checkpoint='../../_resources/checkpoint') 23 | _shp = delta.eta.shape 24 | 25 | 26 | delta.init_water_iteration() 27 | delta.run_water_iteration() 28 | 29 | 30 | # define a function to fill in the walks of given idx 31 | def _plot_idxs_walks_to_step(delta_inds, _step, _idxs, _ax) -> None: 32 | for i in range(len(_idxs)): 33 | walk = delta_inds[_idxs[i], :] 34 | walk = walk[:_step] 35 | # print(walk) 36 | pyDeltaRCM.debug_tools.plot_line( 37 | walk, shape=_shp, color='c', 38 | multiline=True, nozeros=True) 39 | yend, xend = pyDeltaRCM.shared_tools.custom_unravel(walk[-1], _shp) 40 | _ax.plot(xend, yend, 41 | marker='o', ms=3, color='c') 42 | 43 | 44 | # declare the idxs to use: 45 | idxs = np.random.randint(low=0, high=delta._Np_water, size=n) 46 | pidx = 85 47 | 48 | 49 | # set up axis 50 | # fig, ax = plt.subplots(1, 4, figsize=(10, 5)) 51 | fig = plt.figure() 52 | gs = fig.add_gridspec( 53 | 2, 2, 54 | wspace=0.3, 55 | left=0.1, right=0.9) 56 | 57 | 58 | # fill in axis0 59 | ax0 = fig.add_subplot(gs[0, 0]) 60 | pyDeltaRCM.debug_tools.plot_domain( 61 | delta.eta, ax=ax0, grid=False, cmap='cividis') 62 | _plot_idxs_walks_to_step( 63 | delta.free_surf_walk_inds, _step=pidx, _idxs=idxs, _ax=ax0) 64 | ax0.set_title('bed elevation') 65 | 66 | 67 | # fill in axis0 68 | ax1 = fig.add_subplot(gs[0, 1]) 69 | pyDeltaRCM.debug_tools.plot_domain( 70 | delta.stage, ax=ax1, grid=False) 71 | _plot_idxs_walks_to_step(delta.free_surf_walk_inds, _step=pidx, _idxs=idxs, _ax=ax1) 72 | ax1.set_title('water surface (stage)') 73 | 74 | 75 | ax2 = fig.add_subplot(gs[1, :]) 76 | ax2.axhline(y=0, xmin=0, xmax=pidx+1, ls='--', color='0.6') 77 | for i in range(n): 78 | walk = delta.free_surf_walk_inds[idxs[i], :] 79 | walk = walk[:pidx] 80 | 81 | ax2.plot(delta.eta.flat[walk], 'k-') 82 | ax2.plot(delta.stage.flat[walk], '-', color=cm(i)) 83 | 84 | ax2.set_ylabel('elevation') 85 | ax2.set_xlabel('steps along parcel path') 86 | 87 | plt.show() 88 | -------------------------------------------------------------------------------- /docs/source/pyplots/water_tools/_check_for_loops.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import numpy as np 4 | import matplotlib 5 | import matplotlib.pyplot as plt 6 | from matplotlib.patches import Rectangle 7 | 8 | import pyDeltaRCM 9 | from pyDeltaRCM import water_tools 10 | 11 | 12 | # filter out the warning raised about no netcdf being found 13 | warnings.filterwarnings("ignore", category=UserWarning) 14 | 15 | 16 | n = 10 17 | cm = matplotlib.colormaps['tab10'] 18 | 19 | 20 | # init delta model 21 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 22 | delta = pyDeltaRCM.DeltaModel( 23 | out_dir=output_dir, 24 | resume_checkpoint='../../_resources/checkpoint') 25 | _shp = delta.eta.shape 26 | 27 | 28 | # determine the index to plot at 29 | pidx = 40 30 | Npts = 5 31 | jidx = np.random.randint(0, delta._Np_water, Npts) 32 | 33 | # run an interation from the checkpoint 34 | delta.init_water_iteration() 35 | delta.run_water_iteration() 36 | 37 | # here, we recreate some steps of each iteration, in order to set up the 38 | # arrays needed to display the action of _check_for_loops 39 | # 40 | # 1. extract the water walks 41 | current_inds = delta.free_surf_walk_inds[:, pidx-1] 42 | # 43 | # 2. use water weights and random pick to determine d8 direction 44 | water_weights_flat = delta.water_weights.reshape(-1, 9) 45 | new_direction = water_tools._choose_next_directions( 46 | current_inds, water_weights_flat) 47 | new_direction = new_direction.astype(int) 48 | # 49 | # 3. use the new directions for each parcel to determine the new ind for 50 | # each parcel 51 | new_inds = water_tools._calculate_new_inds( 52 | current_inds, 53 | new_direction, 54 | delta.ravel_walk_flat) 55 | new_inds0 = np.copy(new_inds) 56 | 57 | # choose N indices randomly to jump 58 | new_inds[jidx] = delta.free_surf_walk_inds[jidx, pidx-2] 59 | 60 | # copy inputs and then run the function to get new outputs 61 | new_inds, looped = water_tools._check_for_loops( 62 | delta.free_surf_walk_inds[:, :pidx-1], new_inds, pidx + 1, delta.L0, 63 | delta.CTR, delta.stage - delta.H_SL) 64 | 65 | 66 | # make the figure 67 | fig, ax = plt.subplots(1, 2, figsize=(10, 4)) 68 | 69 | delta.show_attribute('eta', ax=ax[0], grid=False, cmap='cividis') 70 | delta.show_attribute('eta', ax=ax[1], grid=False, cmap='cividis') 71 | 72 | 73 | def _fill_out_an_axis(_ax, _sc=1): 74 | for j in range(len(jidx)): 75 | walk = delta.free_surf_walk_inds[jidx[j], :] 76 | walk = walk[:pidx-2] 77 | yend, xend = pyDeltaRCM.shared_tools.custom_unravel( 78 | walk[-1], _shp) 79 | ynew, xnew = pyDeltaRCM.shared_tools.custom_unravel( 80 | new_inds[jidx[j]], _shp) 81 | pyDeltaRCM.debug_tools.plot_line( 82 | walk, shape=_shp, color=cm(j), 83 | multiline=True, nozeros=True, lw=1.5*_sc, ax=_ax) 84 | _ax.plot(xend, yend, 85 | marker='o', ms=3*_sc, color=cm(j)) 86 | _ax.plot(xnew, ynew, 87 | marker='o', ms=3*_sc, color=cm(j)) 88 | 89 | # return the last set 90 | return yend, xend, ynew, xnew 91 | 92 | 93 | # fill out both axes with the same info 94 | _fill_out_an_axis(_ax=ax[0]) 95 | yend, xend, ynew, xnew = _fill_out_an_axis(_ax=ax[1], _sc=2) 96 | 97 | # sub region of the original image 98 | _f = int(delta.W / delta.L) # ensure x-y scale same 99 | _s = 10 100 | x1, x2, y1, y2 = xend-(_s*_f), xnew+(_s*_f), yend-(_s), ynew+(_s) 101 | ax[1].set_xlim(x1, x2) 102 | ax[1].set_ylim(y2, y1) 103 | ax[1].set_xticks([]) 104 | ax[1].set_yticks([]) 105 | 106 | _r = Rectangle((x1, y2), _s*_f*2, -_s*2, ec='k', fc='none') 107 | ax[0].add_patch(_r) 108 | 109 | plt.show() 110 | -------------------------------------------------------------------------------- /docs/source/pyplots/water_tools/_smooth_free_surface.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib.pyplot as plt 4 | import matplotlib 5 | 6 | import pyDeltaRCM 7 | 8 | # filter out the warning raised about no netcdf being found 9 | warnings.filterwarnings("ignore", category=UserWarning) 10 | 11 | 12 | n = 10 13 | cm = matplotlib.colormaps['tab10'] 14 | 15 | 16 | # init delta model 17 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 18 | delta = pyDeltaRCM.DeltaModel( 19 | out_dir=output_dir, 20 | resume_checkpoint='../../_resources/checkpoint') 21 | 22 | 23 | _shp = delta.eta.shape 24 | 25 | 26 | # manually call only the necessary paths 27 | delta.init_water_iteration() 28 | delta.run_water_iteration() 29 | 30 | # lines cobbled together from compute_free_surface and finalize_free_surface 31 | delta.sfc_visit, delta.sfc_sum = pyDeltaRCM.water_tools._accumulate_free_surface_walks( 32 | delta.free_surf_walk_inds, delta.free_surf_flag, delta.cell_type, 33 | delta.uw, delta.ux, delta.uy, delta.depth, 34 | delta._dx, delta._u0, delta.h0, delta._H_SL, delta._S0) 35 | Hnew = delta.eta + delta.depth 36 | Hnew[delta.sfc_visit > 0] = (delta.sfc_sum[delta.sfc_visit > 0] / 37 | delta.sfc_visit[delta.sfc_visit > 0]) 38 | Hnew[Hnew < delta._H_SL] = delta._H_SL 39 | Hnew[Hnew < delta.eta] = delta.eta[Hnew < delta.eta] 40 | 41 | # now run the smoothing function to get grids 42 | Hsmth = pyDeltaRCM.water_tools._smooth_free_surface( 43 | Hnew, delta.cell_type, delta._Nsmooth, delta._Csmooth) 44 | 45 | # set up axis 46 | fig, ax = plt.subplots(1, 3, sharex=True, sharey=True, figsize=(12, 4)) 47 | 48 | # fill in axis0 49 | pyDeltaRCM.debug_tools.plot_domain( 50 | Hnew, ax=ax[0], grid=False, cmap='viridis') 51 | ax[0].set_title('stage before smoothing') 52 | 53 | # fill in axis1 54 | pyDeltaRCM.debug_tools.plot_domain( 55 | Hsmth, ax=ax[1], grid=False, cmap='viridis') 56 | ax[1].set_title('stage after smoothing') 57 | 58 | 59 | # fill in axis2 60 | _diff = Hsmth - Hnew 61 | pyDeltaRCM.debug_tools.plot_domain( 62 | _diff, ax=ax[2], grid=False, cmap='RdBu', 63 | vmin=-0.1, vmax=0.1) 64 | ax[2].set_title('difference (after - before)') 65 | 66 | 67 | plt.tight_layout() 68 | plt.show() 69 | -------------------------------------------------------------------------------- /docs/source/pyplots/water_tools/compute_free_surface_inputs.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | 6 | import pyDeltaRCM 7 | 8 | 9 | # filter out the warning raised about no netcdf being found 10 | warnings.filterwarnings("ignore", category=UserWarning) 11 | 12 | 13 | n = 1 14 | cm = matplotlib.colormaps['tab10'] 15 | 16 | 17 | # init delta model 18 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 19 | delta = pyDeltaRCM.DeltaModel( 20 | out_dir=output_dir, 21 | resume_checkpoint='../../_resources/checkpoint') 22 | _shp = delta.eta.shape 23 | 24 | 25 | delta.init_water_iteration() 26 | delta.run_water_iteration() 27 | 28 | 29 | fig, ax = plt.subplots(1, 2, sharex=True, sharey=True, figsize=(9, 3)) 30 | 31 | # fill in axis 32 | pyDeltaRCM.debug_tools.plot_domain( 33 | delta.eta, ax=ax[0], grid=False, cmap='cividis', 34 | label='bed elevation (m)') 35 | pyDeltaRCM.debug_tools.plot_domain( 36 | delta.eta, ax=ax[1], grid=False, cmap='cividis', 37 | label='bed elevation (m)') 38 | delta.show_line(delta.free_surf_walk_inds[::10, :].T, 'k-', 39 | ax=ax[1], alpha=0.1, 40 | multiline=True, nozeros=True) 41 | 42 | fig.show() 43 | -------------------------------------------------------------------------------- /docs/source/pyplots/water_tools/compute_free_surface_outputs.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | import pyDeltaRCM 8 | 9 | 10 | # filter out the warning raised about no netcdf being found 11 | warnings.filterwarnings("ignore", category=UserWarning) 12 | 13 | 14 | n = 1 15 | cm = matplotlib.colormaps['tab10'] 16 | 17 | 18 | # init delta model 19 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 20 | delta = pyDeltaRCM.DeltaModel( 21 | out_dir=output_dir, 22 | resume_checkpoint='../../_resources/checkpoint') 23 | _shp = delta.eta.shape 24 | 25 | 26 | delta.init_water_iteration() 27 | delta.run_water_iteration() 28 | delta.compute_free_surface() 29 | 30 | 31 | # pidx = 60 32 | 33 | # sfc_visit, sfc_sum = pyDeltaRCM.water_tools._accumulate_free_surface_walks( 34 | # delta.free_surf_walk_inds, delta.free_surf_flag, delta.cell_type, 35 | # delta.uw, delta.ux, delta.uy, delta.depth, 36 | # delta._dx, delta._u0, delta.h0, delta._H_SL, delta._S0) 37 | 38 | 39 | Hnew = np.full_like(delta.sfc_visit, np.nan) 40 | Hnew[delta.sfc_visit > 0] = (delta.sfc_sum[delta.sfc_visit > 0] / 41 | delta.sfc_visit[delta.sfc_visit > 0]) 42 | 43 | 44 | # stage_new = delta.eta + delta.depth 45 | # stage_new[delta.sfc_visit > 0] = (delta.sfc_sum[delta.sfc_visit > 0] / 46 | # delta.sfc_visit[delta.sfc_visit > 0]) 47 | 48 | 49 | fig, ax = plt.subplots(2, 2, sharex=True, sharey=True, figsize=(9, 4)) 50 | 51 | pyDeltaRCM.debug_tools.plot_domain( 52 | delta.sfc_visit, ax=ax[0, 0], grid=False, cmap='Greys', 53 | label='sfc_visit (-)') 54 | pyDeltaRCM.debug_tools.plot_domain( 55 | delta.sfc_sum, ax=ax[0, 1], grid=False, cmap='Blues', 56 | label='sfc_sum (m)') 57 | 58 | pyDeltaRCM.debug_tools.plot_domain( 59 | Hnew, ax=ax[1, 0], grid=False, 60 | label='computed Hnew (m)') 61 | pyDeltaRCM.debug_tools.plot_domain( 62 | delta.Hnew, ax=ax[1, 1], grid=False, 63 | label='stage (m)') 64 | 65 | fig.show() 66 | -------------------------------------------------------------------------------- /docs/source/pyplots/water_tools/flooding_correction.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | import matplotlib 6 | 7 | import pyDeltaRCM 8 | 9 | # filter out the warning raised about no netcdf being found 10 | warnings.filterwarnings("ignore", category=UserWarning) 11 | 12 | 13 | n = 10 14 | cm = matplotlib.colormaps['tab10'] 15 | 16 | 17 | # init delta model 18 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 19 | delta = pyDeltaRCM.DeltaModel( 20 | out_dir=output_dir, 21 | resume_checkpoint='../../_resources/checkpoint') 22 | 23 | 24 | _shp = delta.eta.shape 25 | 26 | 27 | # manually call only the necessary paths 28 | delta.init_water_iteration() 29 | delta.run_water_iteration() 30 | 31 | # lines cobbled together from compute_free_surface and finalize_free_surface 32 | delta.sfc_visit, delta.sfc_sum = pyDeltaRCM.water_tools._accumulate_free_surface_walks( 33 | delta.free_surf_walk_inds, delta.free_surf_flag, delta.cell_type, 34 | delta.uw, delta.ux, delta.uy, delta.depth, 35 | delta._dx, delta._u0, delta.h0, delta._H_SL, delta._S0) 36 | Hnew = delta.eta + delta.depth 37 | Hnew[delta.sfc_visit > 0] = (delta.sfc_sum[delta.sfc_visit > 0] / 38 | delta.sfc_visit[delta.sfc_visit > 0]) 39 | Hnew[Hnew < delta._H_SL] = delta._H_SL 40 | Hnew[Hnew < delta.eta] = delta.eta[Hnew < delta.eta] 41 | 42 | # now run the smoothing function to get grids 43 | Hsmth = pyDeltaRCM.water_tools._smooth_free_surface( 44 | Hnew, delta.cell_type, delta._Nsmooth, delta._Csmooth) 45 | 46 | delta.stage = (((1 - delta._omega_sfc) * delta.stage) + 47 | (delta._omega_sfc * Hsmth)) 48 | 49 | before_flood = np.copy(delta.stage) 50 | delta.flooding_correction() 51 | after_flood = np.copy(delta.stage) 52 | 53 | # set up axis 54 | fig, ax = plt.subplots(1, 3, sharex=True, sharey=True, figsize=(12, 4)) 55 | 56 | # fill in axis0 57 | pyDeltaRCM.debug_tools.plot_domain( 58 | before_flood, ax=ax[0], grid=False, cmap='viridis') 59 | ax[0].set_title('stage before flooding correction') 60 | 61 | # fill in axis1 62 | pyDeltaRCM.debug_tools.plot_domain( 63 | after_flood, ax=ax[1], grid=False, cmap='viridis') 64 | ax[1].set_title('stage after flooding correction') 65 | 66 | 67 | # fill in axis2 68 | _diff = after_flood - before_flood 69 | pyDeltaRCM.debug_tools.plot_domain( 70 | _diff, ax=ax[2], grid=False, cmap='RdBu', 71 | vmin=-0.1, vmax=0.1) 72 | ax[2].set_title('difference (after - before)') 73 | 74 | 75 | plt.tight_layout() 76 | plt.show() 77 | -------------------------------------------------------------------------------- /docs/source/pyplots/water_tools/run_water_iteration.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | import pyDeltaRCM 8 | 9 | 10 | # filter out the warning raised about no netcdf being found 11 | warnings.filterwarnings("ignore", category=UserWarning) 12 | 13 | 14 | n = 10 15 | cm = matplotlib.colormaps['tab10'] 16 | 17 | 18 | # init delta model 19 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 20 | delta = pyDeltaRCM.DeltaModel( 21 | out_dir=output_dir) 22 | 23 | delta_later = pyDeltaRCM.DeltaModel( 24 | out_dir=output_dir, 25 | resume_checkpoint='../../_resources/checkpoint') 26 | 27 | 28 | _shp = delta_later.eta.shape 29 | 30 | 31 | # manually call only the necessary paths 32 | delta.init_water_iteration() 33 | delta.run_water_iteration() 34 | 35 | delta_later.init_water_iteration() 36 | delta_later.run_water_iteration() 37 | 38 | 39 | # define a function to fill in the walks of given idx 40 | def _plot_idxs_walks_to_step(delta_inds, _step, _idxs, _ax) -> None: 41 | for i in range(len(_idxs)): 42 | iidx = _idxs[i] 43 | walk = delta_inds[iidx, :] 44 | walk = walk[:_step] 45 | pyDeltaRCM.debug_tools.plot_line( 46 | walk, shape=_shp, color=cm(i), 47 | nozeros=True) 48 | yend, xend = pyDeltaRCM.shared_tools.custom_unravel( 49 | walk[-1], _shp) 50 | _ax.plot(xend, yend, 51 | marker='o', ms=3, color=cm(i)) 52 | 53 | 54 | # declare the idxs to use: 55 | idxs = np.random.randint(low=0, high=delta._Np_water, size=n) 56 | ps = [5, 25, 75] 57 | 58 | # set up axis 59 | fig, ax = plt.subplots(2, 3, sharex=True, sharey=True, figsize=(12, 4)) 60 | vmin, vmax = delta.eta.min(), delta.eta.max() 61 | 62 | # fill in axis0 63 | pyDeltaRCM.debug_tools.plot_domain( 64 | delta.eta, ax=ax[0, 0], grid=False, cmap='cividis') 65 | _plot_idxs_walks_to_step( 66 | delta.free_surf_walk_inds, _step=ps[0], _idxs=idxs, _ax=ax[0, 0]) 67 | ax[0, 0].set_title('after {} steps'.format(ps[0])) 68 | pyDeltaRCM.debug_tools.plot_domain( 69 | delta_later.eta, ax=ax[1, 0], grid=False, vmin=vmin, vmax=vmax, cmap='cividis') 70 | _plot_idxs_walks_to_step( 71 | delta_later.free_surf_walk_inds, _step=ps[0], _idxs=idxs, _ax=ax[1, 0]) 72 | # ax[1, 0].set_title('after {} steps'.format(ps[0])) 73 | 74 | 75 | # fill in axis1 76 | pyDeltaRCM.debug_tools.plot_domain( 77 | delta.eta, ax=ax[0, 1], grid=False, cmap='cividis') 78 | _plot_idxs_walks_to_step( 79 | delta.free_surf_walk_inds, _step=ps[1], _idxs=idxs, _ax=ax[0, 1]) 80 | ax[0, 1].set_title('after {} steps'.format(ps[1])) 81 | pyDeltaRCM.debug_tools.plot_domain( 82 | delta_later.eta, ax=ax[1, 1], grid=False, vmin=vmin, vmax=vmax, cmap='cividis') 83 | _plot_idxs_walks_to_step( 84 | delta_later.free_surf_walk_inds, _step=ps[1], _idxs=idxs, _ax=ax[1, 1]) 85 | # ax[1, 1].set_title('after {} steps'.format(ps[1])) 86 | 87 | 88 | # fill in axis2 89 | pyDeltaRCM.debug_tools.plot_domain( 90 | delta.eta, ax=ax[0, 2], grid=False, cmap='cividis') 91 | _plot_idxs_walks_to_step( 92 | delta.free_surf_walk_inds, _step=ps[2], _idxs=idxs, _ax=ax[0, 2]) 93 | ax[0, 2].set_title('after {} steps'.format(ps[2])) 94 | pyDeltaRCM.debug_tools.plot_domain( 95 | delta_later.eta, ax=ax[1, 2], grid=False, vmin=vmin, vmax=vmax, cmap='cividis') 96 | _plot_idxs_walks_to_step( 97 | delta_later.free_surf_walk_inds, _step=ps[2], _idxs=idxs, _ax=ax[1, 2]) 98 | # ax[1, 3].set_title('after {} steps'.format(ps[3])) 99 | 100 | 101 | plt.tight_layout() 102 | plt.show() 103 | -------------------------------------------------------------------------------- /docs/source/pyplots/water_tools/water_weights_examples.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | 7 | import pyDeltaRCM 8 | 9 | 10 | # filter out the warning raised about no netcdf being found 11 | warnings.filterwarnings("ignore", category=UserWarning) 12 | 13 | 14 | n = 10 15 | cm = matplotlib.colormaps['tab10'] 16 | 17 | # init delta model 18 | with pyDeltaRCM.shared_tools._docs_temp_directory() as output_dir: 19 | delta = pyDeltaRCM.DeltaModel( 20 | out_dir=output_dir, 21 | resume_checkpoint='../../_resources/checkpoint') 22 | 23 | _shp = delta.eta.shape 24 | 25 | 26 | # manually call only the necessary paths 27 | delta.init_water_iteration() 28 | delta.run_water_iteration() 29 | 30 | 31 | NPLOT = 5 32 | hdr: int = NPLOT // 2 33 | 34 | # fig, ax = plt.subplots() 35 | fig = plt.figure(figsize=(6, 9)) 36 | gs = fig.add_gridspec( 37 | nrows=NPLOT+hdr, ncols=5, 38 | left=0.05, right=0.95, top=0.95, bottom=0.05, 39 | wspace=0.01, hspace=0.2) 40 | 41 | hdr_ax = fig.add_subplot(gs[:hdr, :]) 42 | pyDeltaRCM.debug_tools.plot_domain( 43 | delta.eta, ax=hdr_ax, grid=False, cmap='cividis', vmin=-3, vmax=0.5) 44 | hdr_ax.set_xticks([]) 45 | hdr_ax.set_yticks([]) 46 | hdr_ax.set_xlim(0, delta.W // 2) 47 | hdr_ax.set_ylim(delta.L // 2, 0) 48 | 49 | 50 | def plot_pxpy_weights(pxpy, i): 51 | 52 | px, py = pxpy 53 | 54 | hdr_ax.text(py, px, str(i-hdr), 55 | fontsize=9, color='white', 56 | ha='center', va='center') 57 | 58 | __ax_list = [] 59 | 60 | def _make_single_axis(i, j, values, **kwargs): 61 | __ax = fig.add_subplot(gs[i, j]) 62 | __ax.set_xticks([]) 63 | __ax.set_yticks([]) 64 | __ax.imshow(values, **kwargs) 65 | for _i in range(3): 66 | for _j in range(3): 67 | __ax.text( 68 | _j, _i, str(np.round(values[_i, _j], 2)), 69 | ha='center', va='center', fontsize=8) 70 | return __ax 71 | 72 | # grab the data from the fields and put it into axis 73 | _eta_data = delta.eta[px-1:px+2, py-1:py+2] 74 | _eta_ax = _make_single_axis( 75 | i, 0, _eta_data, cmap='cividis', vmin=-3, vmax=0.5) 76 | __ax_list.append(_eta_ax) 77 | 78 | _dpth_data = delta.depth[px-1:px+2, py-1:py+2] 79 | _dpth_ax = _make_single_axis( 80 | i, 1, _dpth_data, cmap='Blues', vmin=0, vmax=5) 81 | __ax_list.append(_dpth_ax) 82 | 83 | _stge_data = delta.stage[px-1:px+2, py-1:py+2] 84 | _stge_ax = _make_single_axis( 85 | i, 2, _stge_data, cmap='viridis', vmin=0, vmax=5) 86 | __ax_list.append(_stge_ax) 87 | 88 | _vel_data = delta.uw[px-1:px+2, py-1:py+2] 89 | _vel_ax = _make_single_axis( 90 | i, 3, _vel_data, cmap='plasma', vmin=0, vmax=1.5) 91 | __ax_list.append(_vel_ax) 92 | 93 | _wght_data = delta.water_weights[px, py, :].reshape((3, 3)) 94 | _wght_ax = _make_single_axis( 95 | i, 4, _wght_data, cmap='YlGn', vmin=0, vmax=1) 96 | __ax_list.append(_wght_ax) 97 | 98 | return __ax_list 99 | 100 | 101 | # define the example location set 102 | _ex_set = [(10, 94), (20, 78), (38, 72), (22, 87), (47, 43)] 103 | 104 | 105 | # plot the points 106 | ax0 = plot_pxpy_weights(_ex_set[0], hdr+0) 107 | ax1 = plot_pxpy_weights(_ex_set[1], hdr+1) 108 | ax2 = plot_pxpy_weights(_ex_set[2], hdr+2) 109 | ax3 = plot_pxpy_weights(_ex_set[3], hdr+3) 110 | ax4 = plot_pxpy_weights(_ex_set[4], hdr+4) 111 | 112 | # labels 113 | for a, axx in enumerate([ax0, ax1, ax2, ax3, ax4]): 114 | axx[0].set_ylabel(str(a), rotation=0, labelpad=10, 115 | ha='center', va='center') 116 | 117 | albls = ['bed elevation\n(eta)', 'depth', 118 | 'stage', 'velocity\n(uw)', 'water weights'] 119 | for a, (axx, albl) in enumerate(zip(ax4, albls)): 120 | axx.set_xlabel(albl) 121 | 122 | # show 123 | plt.show() 124 | -------------------------------------------------------------------------------- /docs/source/reference/debug_tools/index.rst: -------------------------------------------------------------------------------- 1 | .. api.debug_tools: 2 | 3 | *********** 4 | debug_tools 5 | *********** 6 | 7 | .. currentmodule:: pyDeltaRCM.debug_tools 8 | 9 | The debugging tools are defined in ``pyDeltaRCM.debug_tools``. 10 | 11 | .. todo:: 12 | 13 | Add paragraph description of the module. What stages are defined here generally? 14 | 15 | 16 | Public API methods attached to model 17 | ------------------------------------ 18 | 19 | The following methods are defined in the ``debug_tools`` class, of the ``pyDeltaRCM.debug_tools`` module. 20 | They are then attached as methods of the `DeltaModel` and can be called at any time during run. 21 | 22 | .. autosummary:: 23 | 24 | debug_tools 25 | 26 | .. autoclass:: debug_tools 27 | 28 | 29 | Public plotting methods 30 | ----------------------- 31 | 32 | The functions defined below are (generally) the actual workers that handle the plotting for the methods defined above and attached to model. 33 | We expose these functions here because they are be useful in the documentation, where they are used extensively. 34 | 35 | .. autofunction:: plot_domain 36 | .. autofunction:: plot_ind 37 | .. autofunction:: plot_line 38 | -------------------------------------------------------------------------------- /docs/source/reference/hook_tools/index.rst: -------------------------------------------------------------------------------- 1 | ********************************* 2 | hook_tools 3 | ********************************* 4 | 5 | .. currentmodule:: pyDeltaRCM.hook_tools 6 | 7 | .. todo:: 8 | 9 | Add paragraph description of the module. What stages are defined here generally? Link to relevant documentation about hooks in user guide and model list. 10 | 11 | 12 | Public API methods attached to model 13 | ------------------------------------ 14 | 15 | The following methods are defined in the ``hook_tools`` class, of the ``pyDeltaRCM.hook_tools`` module. 16 | 17 | .. autosummary:: 18 | 19 | hook_tools 20 | 21 | .. autoclass:: hook_tools 22 | -------------------------------------------------------------------------------- /docs/source/reference/index.rst: -------------------------------------------------------------------------------- 1 | .. api: 2 | 3 | ============= 4 | API reference 5 | ============= 6 | 7 | The :obj:`DeltaModel` class, defined in `pyDeltaRCM.model`, is the main class of pyDeltaRCM, which provides the object that is manipulated to evolve the numerical delta model. 8 | This class uses "mix-in" classes, which are defined in separate files (Python `modules`), that break out logically based on the various stages of model use, and components of the model iteration sequence. 9 | Most model functionality is organized into the various mix-in classes, that are then inherited by the `DeltaModel`. 10 | Additionally, several routines of the model are organized into module-level functions, which are "jitted" via the `numba `_ code optimizer library for Python. 11 | 12 | This index lists the `pyDeltaRCM` organization, hopefully providing enough information to begin to determine where various components of the model are implemented. 13 | The index includes model classes, methods, and attributes, as well as additionally utility classes and functions. 14 | 15 | .. toctree:: 16 | :maxdepth: 2 17 | 18 | model/index 19 | preprocessor/index 20 | iteration_tools/index 21 | init_tools/index 22 | water_tools/index 23 | sed_tools/index 24 | shared_tools/index 25 | hook_tools/index 26 | debug_tools/index 27 | 28 | 29 | References 30 | ---------- 31 | 32 | * :ref:`modindex` 33 | * :ref:`search` 34 | 35 | 36 | Search the Index 37 | ================== 38 | 39 | * :ref:`genindex` 40 | -------------------------------------------------------------------------------- /docs/source/reference/init_tools/index.rst: -------------------------------------------------------------------------------- 1 | .. api.init_tools: 2 | 3 | ********** 4 | init_tools 5 | ********** 6 | 7 | .. currentmodule:: pyDeltaRCM.init_tools 8 | 9 | 10 | The model initialization is managed by :obj:`~pyDeltaRCM.model.DeltaModel.__init__`, but the actual initialization is mostly handled by routines in `init_tools`. 11 | The major steps of initialization are: 12 | 13 | .. autosummary:: 14 | 15 | init_tools.import_files 16 | init_tools.init_logger 17 | init_tools.process_input_to_model 18 | init_tools.determine_random_seed 19 | init_tools.create_other_variables 20 | init_tools.create_domain 21 | init_tools.init_sediment_routers 22 | init_tools.init_subsidence 23 | 24 | and then depending on the checkpointing configuration, the following methods may be called: 25 | 26 | .. autosummary:: 27 | 28 | init_tools.load_checkpoint 29 | init_tools.init_output_file 30 | pyDeltaRCM.iteration_tools.iteration_tools.output_data 31 | pyDeltaRCM.iteration_tools.iteration_tools.output_checkpoint 32 | pyDeltaRCM.iteration_tools.iteration_tools.log_model_time 33 | 34 | 35 | Public API methods attached to model 36 | ------------------------------------ 37 | 38 | The following methods are defined in the ``init_tools`` class, of the ``pyDeltaRCM.init_tools`` module. 39 | 40 | .. currentmodule:: pyDeltaRCM.init_tools 41 | 42 | .. autosummary:: 43 | 44 | init_tools 45 | 46 | .. autoclass:: init_tools 47 | -------------------------------------------------------------------------------- /docs/source/reference/iteration_tools/index.rst: -------------------------------------------------------------------------------- 1 | .. api.iteration_tools: 2 | 3 | *************** 4 | iteration_tools 5 | *************** 6 | 7 | .. currentmodule:: pyDeltaRCM.iteration_tools 8 | 9 | .. todo:: 10 | 11 | Add paragraph description of the module. What stages are defined here generally? Make a table with the main ones like in water tools? 12 | 13 | 14 | Public API methods attached to model 15 | ------------------------------------ 16 | 17 | The following methods are defined in the ``iteration_tools`` class, of the ``pyDeltaRCM.iteration_tools`` module. 18 | 19 | .. autosummary:: 20 | 21 | iteration_tools 22 | 23 | .. autoclass:: iteration_tools 24 | -------------------------------------------------------------------------------- /docs/source/reference/model/index.rst: -------------------------------------------------------------------------------- 1 | .. api.model: 2 | 3 | ***** 4 | model 5 | ***** 6 | 7 | This is the main model code. 8 | 9 | This class is defined in ``pyDeltaRCM.model``. 10 | 11 | 12 | The DeltaModel class and all attributes and methods 13 | --------------------------------------------------- 14 | 15 | .. currentmodule:: pyDeltaRCM.model 16 | 17 | .. autosummary:: 18 | :toctree: ../../_autosummary 19 | 20 | ~DeltaModel 21 | 22 | 23 | 24 | 25 | Model configuration reference 26 | ----------------------------- 27 | 28 | .. toctree:: 29 | :maxdepth: 1 30 | 31 | yaml_defaults 32 | model_hooks 33 | -------------------------------------------------------------------------------- /docs/source/reference/model/model_hooks.rst: -------------------------------------------------------------------------------- 1 | Available Model Hooks 2 | ===================== 3 | 4 | .. important:: 5 | 6 | Have a suggestion for another `hook` in the DeltaModel? Get in touch via 7 | the GitHub issue tracker! 8 | 9 | 10 | Method hooks 11 | ------------ 12 | 13 | As described extensively in the :ref:`User Guide on how to customize the model 14 | `, hooks are methods in the model sequence that do 15 | nothing by default, but can be augmented to provide arbitrary desired 16 | behavior in the model. Hooks have been integrated throughout the model 17 | initialization and update sequences, to allow the users to achieve complex 18 | behavior at various stages of the model sequence. 19 | 20 | A complete list of hooks in the model follows: 21 | 22 | .. currentmodule:: pyDeltaRCM.hook_tools 23 | 24 | .. csv-table:: Available model method hooks 25 | :header: "Initializing", "Updating" 26 | :widths: 40, 40 27 | 28 | :obj:`~hook_tools.hook_import_files`, :obj:`~hook_tools.hook_solve_water_and_sediment_timestep` 29 | :obj:`~hook_tools.hook_process_input_to_model`, :obj:`~hook_tools.hook_apply_subsidence` 30 | :obj:`~hook_tools.hook_create_other_variables`, :obj:`~hook_tools.hook_finalize_timestep` 31 | :obj:`~hook_tools.hook_create_domain`, :obj:`~hook_tools.hook_route_water` 32 | :obj:`~hook_tools.hook_load_checkpoint`, :obj:`~hook_tools.hook_init_water_iteration` 33 | :obj:`~hook_tools.hook_init_output_file`, :obj:`~hook_tools.hook_run_water_iteration` 34 | , :obj:`~hook_tools.hook_compute_free_surface` 35 | , :obj:`~hook_tools.hook_finalize_water_iteration` 36 | , :obj:`~hook_tools.hook_route_sediment` 37 | , :obj:`~hook_tools.hook_route_all_sand_parcels` 38 | , :obj:`~hook_tools.hook_topo_diffusion` 39 | , :obj:`~hook_tools.hook_route_all_mud_parcels` 40 | , :obj:`~hook_tools.hook_compute_sand_frac` 41 | , :obj:`~hook_tools.hook_after_route_water` 42 | , :obj:`~hook_tools.hook_after_route_sediment` 43 | , :obj:`~hook_tools.hook_output_data` 44 | , :obj:`~hook_tools.hook_output_checkpoint` 45 | 46 | 47 | Array hooks 48 | ----------- 49 | 50 | The `DeltaModel` also incorporates a few arrays that enable a similar effect 51 | to method hooks. These arrays are initialized with all ``1`` or all ``0`` 52 | values by default (depending on the scenario), and provide a convenient 53 | location to augment the model with varied behavior. 54 | 55 | A complete list of behavior-modifying arrays in the model follows: 56 | 57 | .. csv-table:: Available model array hooks 58 | :header: "Array name", "function", "default value" 59 | :widths: 20, 50, 10 60 | 61 | `mod_water_weight`, modifies the neighbor-weighting of water parcels during routing according to ``(depth * mod_water_weight)**theta_water``, 1 62 | `mod_sed_weight`, modifies the neighbor-weighting of the sediment parcel routing according to ``(depth * mod_sed_weight)**theta_sed``, 1 63 | `mod_erosion`, linearly modifies the "erodibility" of cells according to ``mod_erosion * Vp_sed * (U_loc**beta - U_ero**beta) / U_ero**beta``, 1 64 | 65 | -------------------------------------------------------------------------------- /docs/source/reference/model/yaml_defaults.rst: -------------------------------------------------------------------------------- 1 | Default Model Variable Values 2 | ============================= 3 | 4 | .. hint:: 5 | 6 | A complete list of the meaning of each YAML parameter can be found at 7 | :doc:`../../info/yamlparameters`. 8 | 9 | 10 | Default model parameter values are defined as: 11 | 12 | .. literalinclude:: ../../../../pyDeltaRCM/default.yml 13 | :language: yaml 14 | :linenos: 15 | -------------------------------------------------------------------------------- /docs/source/reference/preprocessor/index.rst: -------------------------------------------------------------------------------- 1 | .. api.preprocessor: 2 | 3 | ********************************* 4 | Preprocessor 5 | ********************************* 6 | 7 | .. currentmodule:: pyDeltaRCM.preprocessor 8 | 9 | The high-level API is principally defined in ``pyDeltaRCM.preprocessor``. 10 | 11 | .. todo:: 12 | 13 | add paragraph description of the module. What can we do with this? Why does it exist? Link to the relevant documentation in the user guide and examples. 14 | 15 | 16 | Preprocessor classes and API 17 | ---------------------------- 18 | 19 | The following classes are defined in the ``pyDeltaRCM.preprocessor`` module and enable the high-level model API to work at both the command line and as a Python object. 20 | 21 | .. autosummary:: 22 | :toctree: ../../_autosummary 23 | 24 | PreprocessorCLI 25 | :members: 26 | :inherited-members: 27 | 28 | Preprocessor 29 | :members: 30 | :inherited-members: 31 | 32 | BasePreprocessor 33 | 34 | Preprocessor function and utilities 35 | ----------------------------------- 36 | 37 | .. todo:: add description, what are these? 38 | 39 | .. autofunction:: preprocessor_wrapper 40 | .. autofunction:: scale_relative_sea_level_rise_rate 41 | .. autofunction:: _write_yaml_config_to_file 42 | -------------------------------------------------------------------------------- /docs/source/reference/sed_tools/index.rst: -------------------------------------------------------------------------------- 1 | .. api.sed_tools: 2 | 3 | ********************************* 4 | sed_tools 5 | ********************************* 6 | 7 | .. currentmodule:: pyDeltaRCM.sed_tools 8 | 9 | .. todo:: add paragraph description of the module 10 | 11 | 12 | The tools are defined in ``pyDeltaRCM.sed_tools``. 13 | 14 | 15 | Public API methods attached to model 16 | ------------------------------------ 17 | 18 | The following methods are defined in the ``sed_tools`` class, of the ``pyDeltaRCM.sed_tools`` module. 19 | 20 | .. autosummary:: 21 | 22 | sed_tools 23 | 24 | .. autoclass:: sed_tools 25 | 26 | 27 | Router classes 28 | -------------- 29 | 30 | The following classes are defined in the ``pyDeltaRCM.sed_tools`` module. These sediment routing classes are jitted for speed. 31 | 32 | .. autosummary:: 33 | :toctree: ../../_autosummary 34 | 35 | SandRouter 36 | :members: 37 | :inherited-members: 38 | :private-members: 39 | 40 | MudRouter 41 | :members: 42 | :inherited-members: 43 | :private-members: 44 | 45 | BaseRouter 46 | :members: 47 | :inherited-members: 48 | :private-members: 49 | 50 | sed_tools helper functions 51 | ---------------------------- 52 | 53 | Additionally, the sediment parcel step-weighting function is defined at the module level in ``pyDeltaRCM.sed_tools``. 54 | 55 | .. autofunction:: _get_weight_at_cell_sediment 56 | -------------------------------------------------------------------------------- /docs/source/reference/shared_tools/index.rst: -------------------------------------------------------------------------------- 1 | .. api.shared_tools: 2 | 3 | ********************************* 4 | shared_tools 5 | ********************************* 6 | 7 | .. currentmodule:: pyDeltaRCM.shared_tools 8 | 9 | 10 | .. todo:: add paragraph description of the module 11 | 12 | 13 | The tools are defined in ``pyDeltaRCM.shared_tools``. 14 | 15 | 16 | Shared functions 17 | ---------------- 18 | 19 | This module defines several functions that are used throughout the model, and so are organized here for convenience. 20 | 21 | .. autofunction:: get_random_uniform 22 | .. autofunction:: get_inlet_weights 23 | .. autofunction:: get_start_indices 24 | .. autofunction:: get_steps 25 | .. autofunction:: random_pick 26 | .. autofunction:: custom_unravel 27 | .. autofunction:: custom_ravel 28 | .. autofunction:: custom_pad 29 | .. autofunction:: get_weight_sfc_int 30 | .. autofunction:: custom_yaml_loader 31 | 32 | 33 | Time scaling functions 34 | ---------------------- 35 | 36 | Scaling of real-world time and model time is an important topic covered in detail in :doc:`/info/modeltime`. 37 | Several functions are defined here which can help with scaling between model and real-world time. 38 | 39 | .. autofunction:: scale_model_time 40 | .. autofunction:: _scale_factor 41 | 42 | 43 | Utilities 44 | --------- 45 | 46 | Additionally, functions defined in ``pyDeltaRCM.shared_tools`` manage the random state of the model, and help with documentation and version management. 47 | 48 | .. autofunction:: set_random_seed 49 | .. autofunction:: get_random_state 50 | .. autofunction:: set_random_state 51 | .. autofunction:: _docs_temp_directory 52 | .. autofunction:: _get_version 53 | -------------------------------------------------------------------------------- /docs/source/reference/water_tools/index.rst: -------------------------------------------------------------------------------- 1 | .. api.water_tools: 2 | 3 | ********************************* 4 | water_tools 5 | ********************************* 6 | 7 | .. currentmodule:: pyDeltaRCM.water_tools 8 | 9 | 10 | The :obj:`~pyDeltaRCM.water_tools.water_tools.route_water` routine manages the water routing. 11 | During :obj:`~pyDeltaRCM.water_tools.water_tools.route_water`, water iteration is repeated a total of :obj:`~pyDeltaRCM.model.DeltaModel.itermax` times. 12 | During each of these iterations of the water routing, the following methods are called *in order*: 13 | 14 | .. autosummary:: 15 | 16 | water_tools.init_water_iteration 17 | water_tools.run_water_iteration 18 | water_tools.compute_free_surface 19 | water_tools.finalize_water_iteration 20 | 21 | 22 | Public API methods attached to model 23 | ------------------------------------ 24 | 25 | The following methods are defined in the ``water_tools`` class, of the ``pyDeltaRCM.water_tools`` module. 26 | 27 | .. autosummary:: 28 | 29 | water_tools 30 | 31 | .. autoclass:: water_tools 32 | 33 | 34 | water_tools helper functions 35 | ---------------------------- 36 | 37 | The following routines are jitted for speed. 38 | They generally take a large number of arrays and constants and return a new array(s) to continue with the model progression within the methods defined above. 39 | 40 | .. autofunction:: _get_weight_at_cell_water 41 | .. autofunction:: _choose_next_directions 42 | .. autofunction:: _calculate_new_inds 43 | .. autofunction:: _check_for_loops 44 | .. autofunction:: _update_dirQfield 45 | .. autofunction:: _update_absQfield 46 | .. autofunction:: _accumulate_free_surface_walks 47 | .. autofunction:: _smooth_free_surface 48 | -------------------------------------------------------------------------------- /pyDeltaRCM/__init__.py: -------------------------------------------------------------------------------- 1 | from .model import DeltaModel 2 | from .preprocessor import Preprocessor 3 | from .shared_tools import _get_version 4 | 5 | __all__ = ['DeltaModel', 'Preprocessor'] 6 | __version__: str = _get_version() 7 | -------------------------------------------------------------------------------- /pyDeltaRCM/__main__.py: -------------------------------------------------------------------------------- 1 | from . import preprocessor 2 | 3 | if __name__ == '__main__': 4 | preprocessor.preprocessor_wrapper() 5 | -------------------------------------------------------------------------------- /pyDeltaRCM/_version.py: -------------------------------------------------------------------------------- 1 | def __version__() -> str: 2 | """ 3 | Private version declaration, gets assigned to pyDeltaRCM.__version__ 4 | during import 5 | """ 6 | return "2.1.6" 7 | -------------------------------------------------------------------------------- /pyDeltaRCM/default.yml: -------------------------------------------------------------------------------- 1 | out_dir: 2 | type: 'str' 3 | default: 'deltaRCM_Output' 4 | verbose: 5 | type: 'int' 6 | default: 0 7 | seed: 8 | type: ['int', 'None'] 9 | default: null 10 | Length: 11 | type: ['float', 'int'] 12 | default: 5000. 13 | Width: 14 | type: ['float', 'int'] 15 | default: 10000. 16 | dx: 17 | type: ['float', 'int'] 18 | default: 50. 19 | L0_meters: 20 | type: ['float', 'int'] 21 | default: 150.0 22 | S0: 23 | type: ['float', 'int'] 24 | default: 0.00015 25 | itermax: 26 | type: 'int' 27 | default: 3 28 | Np_water: 29 | type: 'int' 30 | default: 2000 31 | u0: 32 | type: ['float', 'int'] 33 | default: 1.0 34 | N0_meters: 35 | type: ['float', 'int'] 36 | default: 250.0 37 | h0: 38 | type: ['float', 'int'] 39 | default: 5.0 40 | hb: 41 | type: ['float', 'int', 'None'] 42 | default: null 43 | H_SL: 44 | type: ['float', 'int'] 45 | default: 0.0 46 | SLR: 47 | type: ['float', 'int'] 48 | default: 0.0 49 | Np_sed: 50 | type: 'int' 51 | default: 2000 52 | f_bedload: 53 | type: ['float', 'int'] 54 | default: 0.5 55 | active_layer_thickness: 56 | type: ['float', 'int', 'None'] 57 | default: null 58 | C0_percent: 59 | type: ['float', 'int'] 60 | default: 0.1 61 | Csmooth: 62 | type: ['float', 'int'] 63 | default: 0.9 64 | toggle_subsidence: 65 | type: 'bool' 66 | default: False 67 | subsidence_rate: 68 | type: ['float', 'int'] 69 | default: 2e-9 70 | start_subsidence: 71 | type: ['float', 'int'] 72 | default: 216000 73 | save_eta_figs: 74 | type: 'bool' 75 | default: False 76 | save_stage_figs: 77 | type: 'bool' 78 | default: False 79 | save_depth_figs: 80 | type: 'bool' 81 | default: False 82 | save_discharge_figs: 83 | type: 'bool' 84 | default: False 85 | save_velocity_figs: 86 | type: 'bool' 87 | default: False 88 | save_sedflux_figs: 89 | type: 'bool' 90 | default: False 91 | save_sandfrac_figs: 92 | type: 'bool' 93 | default: False 94 | save_figs_sequential: 95 | type: 'bool' 96 | default: True 97 | save_metadata: 98 | type: 'bool' 99 | default: False 100 | save_eta_grids: 101 | type: 'bool' 102 | default: False 103 | save_stage_grids: 104 | type: 'bool' 105 | default: False 106 | save_depth_grids: 107 | type: 'bool' 108 | default: False 109 | save_discharge_grids: 110 | type: 'bool' 111 | default: False 112 | save_velocity_grids: 113 | type: 'bool' 114 | default: False 115 | save_sedflux_grids: 116 | type: 'bool' 117 | default: False 118 | save_sandfrac_grids: 119 | type: 'bool' 120 | default: False 121 | save_discharge_components: 122 | type: 'bool' 123 | default: False 124 | save_velocity_components: 125 | type: 'bool' 126 | default: False 127 | save_dt: 128 | type: 'int' 129 | default: 86400 130 | checkpoint_dt: 131 | type: ['int', 'None'] 132 | default: null 133 | save_checkpoint: 134 | type: 'bool' 135 | default: False 136 | resume_checkpoint: 137 | type: ['bool', 'str'] 138 | default: False 139 | omega_sfc: 140 | type: ['float', 'int'] 141 | default: 0.1 142 | omega_flow: 143 | type: ['float', 'int'] 144 | default: 0.9 145 | Nsmooth: 146 | type: 'int' 147 | default: 10 148 | theta_water: 149 | type: ['float', 'int'] 150 | default: 1.0 151 | coeff_theta_sand: 152 | type: ['float', 'int'] 153 | default: 2.0 154 | coeff_theta_mud: 155 | type: ['float', 'int'] 156 | default: 1.0 157 | beta: 158 | type: 'int' 159 | default: 3 160 | sed_lag: 161 | type: ['float', 'int'] 162 | default: 1.0 163 | coeff_U_dep_mud: 164 | type: ['float', 'int'] 165 | default: 0.3 166 | coeff_U_ero_mud: 167 | type: ['float', 'int'] 168 | default: 1.5 169 | coeff_U_ero_sand: 170 | type: ['float', 'int'] 171 | default: 1.05 172 | alpha: 173 | type: ['float', 'int'] 174 | default: 0.1 175 | stepmax: 176 | type: ['float', 'int', 'None'] 177 | default: null 178 | sand_frac_bc: 179 | type: ['float', 'int'] 180 | default: 0 181 | clobber_netcdf: 182 | type: 'bool' 183 | default: False 184 | legacy_netcdf: 185 | type: 'bool' 186 | default: False -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "pyDeltaRCM" 3 | requires-python = ">=3.11" 4 | description = "Python version of original Matlab DeltaRCM." 5 | keywords = [] 6 | authors = [ 7 | { name = "Andrew Moodie", email = "amoodie@tamu.edu" }, 8 | ] 9 | maintainers = [ 10 | { name = "Andrew Moodie", email = "amoodie@tamu.edu" }, 11 | ] 12 | classifiers = [ 13 | "Intended Audience :: Science/Research", 14 | "License :: OSI Approved :: MIT License", 15 | "Operating System :: OS Independent", 16 | "Programming Language :: Python :: 3 :: Only", 17 | "Programming Language :: Python :: 3.11", 18 | "Programming Language :: Python :: 3.12", 19 | "Programming Language :: Python :: 3.13", 20 | "Topic :: Scientific/Engineering :: Hydrology", 21 | "Topic :: Scientific/Engineering :: Physics", 22 | ] 23 | dependencies = [ 24 | "importlib-resources; python_version < '3.12'", 25 | "matplotlib", 26 | "scipy", 27 | "netCDF4", 28 | "pyyaml", 29 | "numba", 30 | "numpy" 31 | ] 32 | dynamic = [ 33 | "version", 34 | "readme", 35 | ] 36 | 37 | [project.license] 38 | text = "MIT" 39 | 40 | [project.urls] 41 | documentation = "https://deltarcm.org/pyDeltaRCM" 42 | homepage = "https://deltarcm.org/pyDeltaRCM" 43 | repository = "https://github.com/DeltaRCM/pyDeltaRCM" 44 | 45 | [project.optional-dependencies] 46 | docs = [ 47 | "sphinx", 48 | ] 49 | testing = [ 50 | "coveralls", 51 | "pytest", 52 | "pytest-cov", 53 | "pytest-mpl" 54 | ] 55 | 56 | [build-system] 57 | requires = [ 58 | "setuptools >=61", 59 | ] 60 | build-backend = "setuptools.build_meta" 61 | 62 | [tool.setuptools] 63 | include-package-data = true 64 | 65 | [tool.setuptools.dynamic.readme] 66 | file = "README.rst" 67 | content-type = "text/x-rst" 68 | 69 | [tool.setuptools.dynamic.version] 70 | attr = "pyDeltaRCM._version.__version__" 71 | 72 | [tool.setuptools.packages.find] 73 | where = [ 74 | ".", 75 | ] 76 | include = [ 77 | "pyDeltaRCM*", 78 | ] 79 | 80 | [project.scripts] 81 | pyDeltaRCM = "pyDeltaRCM.preprocessor:preprocessor_wrapper" 82 | 83 | [tool.coverage.run] 84 | relative_files = true 85 | 86 | [tool.pytest.ini_options] 87 | minversion = "6.0" 88 | testpaths = [ 89 | "tests", 90 | ] 91 | norecursedirs = [ 92 | ".*", 93 | "*.egg*", 94 | "build", 95 | "dist", 96 | ] 97 | addopts = [ 98 | "--ignore=setup.py", 99 | "--tb=native", 100 | "--durations=16", 101 | "--strict-markers", 102 | "--doctest-modules", 103 | "-vvv", 104 | ] 105 | doctest_optionflags = [ 106 | "NORMALIZE_WHITESPACE", 107 | "IGNORE_EXCEPTION_DETAIL", 108 | "ELLIPSIS", 109 | ] -------------------------------------------------------------------------------- /requirements-docs.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | -------------------------------------------------------------------------------- /requirements-test.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | pytest-mpl 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib>=3.6.1 2 | scipy>=1.5 3 | netCDF4 4 | pyyaml>=5.1 5 | numba 6 | numpy 7 | -------------------------------------------------------------------------------- /strat_preprocess.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy as sp 3 | from PIL import Image, ImageDraw 4 | import netCDF4 5 | 6 | vertical_spacing = 0.05 # in meters 7 | max_depth_of_section = 5 # meters 8 | 9 | fp = 'deltaRCM_Output/pyDeltaRCM_output.nc' 10 | nc = netCDF4.Dataset(fp) 11 | 12 | strata_sf = nc.variables['strata_sand_frac'][:] 13 | strata_depth = nc.variables['strata_depth'][:] 14 | 15 | 16 | # shortcuts for array sizes 17 | dz, dx, dy = strata_depth.shape 18 | nx, ny, nz = dx, dy, int(5/vertical_spacing) 19 | 20 | # preserves only the oldest surface when cross-cutting 21 | strata = np.zeros_like(strata_depth) 22 | strata[-1,:,:] = strata_depth[-1,:,:] 23 | 24 | for i in range(1,dz): 25 | strata[-i-1,:,:] = np.minimum(strata_depth[-i-1,:,:], strata[-i,:,:]) 26 | 27 | 28 | # combines depths and sand fractions into stratigraphy 29 | stratigraphy = np.zeros((nz, nx, ny)) 30 | 31 | for j in range(dx): 32 | 33 | mask = np.ones((nz,ny)) * -1 34 | 35 | for i in np.arange(dz-1,-1,-1): 36 | 37 | seds = strata[i,j,:] + max_depth_of_section 38 | 39 | sf = strata_sf[i,j,:] 40 | sf[sf<0] = 0 41 | 42 | poly = list(zip(np.arange(ny), seds / vertical_spacing)) + list(zip(np.arange(ny)*2, np.arange(ny)*0)) 43 | 44 | img = Image.new("L", [ny, nz], 0) 45 | ImageDraw.Draw(img).polygon(poly, outline=1, fill=1) 46 | img = np.flipud(img).astype(float) 47 | 48 | img *= sf 49 | mask[img > 0] = img[img > 0] 50 | 51 | stratigraphy[:,j,:] = mask 52 | 53 | print('Saving stratigraphy...') 54 | np.save('deltaRCM_Output/stratigraphy.npy', stratigraphy) 55 | print('Done') -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/__init__.py -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_cell_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_cell_type.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_cell_type_list_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_cell_type_list_index.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_cell_type_list_mix_tuple_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_cell_type_list_mix_tuple_index.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_cell_type_list_tuple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_cell_type_list_tuple.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_cell_type_multiple_diff_args.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_cell_type_multiple_diff_args.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_cell_type_multiple_diff_kwargs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_cell_type_multiple_diff_kwargs.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_cell_type_multiple_index_calls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_cell_type_multiple_index_calls.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_cell_type_no_grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_cell_type_no_grid.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_cell_type_single_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_cell_type_single_index.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_cell_type_single_tuple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_cell_type_single_tuple.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_velocity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_velocity.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_domain_withlabel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_domain_withlabel.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_iwalk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_iwalk.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_plot_multiple_subplots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_plot_multiple_subplots.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_show_line_pts_Nx2_array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_show_line_pts_Nx2_array.png -------------------------------------------------------------------------------- /tests/imgs_baseline/test_show_line_set_points.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/imgs_baseline/test_show_line_set_points.png -------------------------------------------------------------------------------- /tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeltaRCM/pyDeltaRCM/cfc01e47542bffc98e394fe1ca07d7f41f8588c7/tests/integration/__init__.py -------------------------------------------------------------------------------- /tests/test_sed_tools.py: -------------------------------------------------------------------------------- 1 | # unit tests for sed_tools.py 2 | 3 | import numpy as np 4 | from pathlib import Path 5 | 6 | import pytest 7 | import unittest.mock as mock 8 | 9 | from pyDeltaRCM.model import DeltaModel 10 | from . import utilities 11 | 12 | 13 | class TestSedimentRoute: 14 | 15 | def test_route_sediment(self, tmp_path: Path) -> None: 16 | # create a delta with default settings 17 | p = utilities.yaml_from_dict(tmp_path, 'input.yaml') 18 | _delta = DeltaModel(input_file=p) 19 | 20 | # mock top-level methods 21 | _delta.log_info = mock.MagicMock() 22 | _delta.init_sediment_iteration = mock.MagicMock() 23 | _delta.route_all_sand_parcels = mock.MagicMock() 24 | _delta.topo_diffusion = mock.MagicMock() 25 | _delta.route_all_mud_parcels = mock.MagicMock() 26 | 27 | # run the method 28 | _delta.route_sediment() 29 | 30 | # methods called 31 | assert (_delta.log_info.call_count == 4) 32 | assert (_delta.init_sediment_iteration.called is True) 33 | assert (_delta.route_all_sand_parcels.called is True) 34 | assert (_delta.topo_diffusion.called is True) 35 | assert (_delta.route_all_mud_parcels.called is True) 36 | 37 | def test_sed_route_deprecated(self, tmp_path: Path) -> None: 38 | # create a delta with default settings 39 | p = utilities.yaml_from_dict(tmp_path, 'input.yaml') 40 | _delta = DeltaModel(input_file=p) 41 | 42 | # mock top-level methods 43 | _delta.logger = mock.MagicMock() 44 | _delta.route_sediment = mock.MagicMock() 45 | 46 | # check warning raised 47 | with pytest.warns(UserWarning): 48 | _delta.sed_route() 49 | 50 | # and logged 51 | assert (_delta.logger.warning.called is True) 52 | 53 | 54 | class TestInitSedimentIteration: 55 | 56 | def test_fields_cleared(self, tmp_path: Path) -> None: 57 | # create a delta with default settings 58 | p = utilities.yaml_from_dict(tmp_path, 'input.yaml') 59 | _delta = DeltaModel(input_file=p) 60 | 61 | # alter field for initial values going into function 62 | _delta.qs += np.random.uniform(0, 1, size=_delta.eta.shape) 63 | _delta.Vp_dep_sand += np.random.uniform(0, 1, size=_delta.eta.shape) 64 | _delta.Vp_dep_mud += np.random.uniform(0, 1, size=_delta.eta.shape) 65 | 66 | assert not np.all(_delta.qs == 0) # field has info 67 | 68 | # call the method 69 | _delta.init_sediment_iteration() 70 | 71 | # assertions 72 | assert np.all(_delta.pad_depth[1:-1, 1:-1] == _delta.depth) 73 | assert np.all(_delta.qs == 0) # field is cleared 74 | assert np.all(_delta.Vp_dep_sand == 0) 75 | assert np.all(_delta.Vp_dep_mud == 0) 76 | 77 | 78 | class TestRouteAllSandParcels: 79 | 80 | def test_route_sand_parcels(self, tmp_path: Path) -> None: 81 | # create a delta with default settings 82 | p = utilities.yaml_from_dict(tmp_path, 'input.yaml', 83 | {'Np_sed': 1000, 84 | 'f_bedload': 0.6}) 85 | _delta = DeltaModel(input_file=p) 86 | 87 | # mock top-level methods / objects 88 | _delta.log_info = mock.MagicMock() 89 | _delta._sr = mock.MagicMock() 90 | 91 | # mock the shared tools start indices 92 | def _patched_starts(inlet, inlet_weights, num_starts): 93 | return np.random.randint(0, 5, size=(num_starts,)) 94 | 95 | patcher = mock.patch( 96 | 'pyDeltaRCM.shared_tools.get_start_indices', 97 | new=_patched_starts) 98 | patcher.start() 99 | 100 | # run the method 101 | _delta.route_all_sand_parcels() 102 | 103 | # methods called 104 | assert (_delta._sr.run.call_count == 1) 105 | assert (_delta.log_info.call_count == 3) 106 | 107 | # stop the patch 108 | patcher.stop() 109 | 110 | 111 | class TestRouteAllMudParcels: 112 | 113 | def test_route_mud_parcels(self, tmp_path: Path) -> None: 114 | # create a delta with default settings 115 | p = utilities.yaml_from_dict(tmp_path, 'input.yaml', 116 | {'Np_sed': 1000, 117 | 'f_bedload': 0.6}) 118 | _delta = DeltaModel(input_file=p) 119 | 120 | # mock top-level methods / objects 121 | _delta.log_info = mock.MagicMock() 122 | _delta._mr = mock.MagicMock() 123 | 124 | # mock the shared tools start indices 125 | def _patched_starts(inlet, inlet_weights, num_starts): 126 | return np.random.randint(0, 5, size=(num_starts,)) 127 | 128 | patcher = mock.patch( 129 | 'pyDeltaRCM.shared_tools.get_start_indices', 130 | new=_patched_starts) 131 | patcher.start() 132 | 133 | # run the method 134 | _delta.route_all_mud_parcels() 135 | 136 | # methods called 137 | assert (_delta._mr.run.call_count == 1) 138 | assert (_delta.log_info.call_count == 3) 139 | 140 | # stop the patch 141 | patcher.stop() 142 | -------------------------------------------------------------------------------- /tests/utilities.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import io 3 | import os 4 | from pathlib import Path 5 | from typing import Any, Dict, List, Optional, Tuple, Union 6 | 7 | import numpy as np 8 | 9 | import pytest 10 | from pyDeltaRCM.model import DeltaModel 11 | from pyDeltaRCM import shared_tools 12 | 13 | # utilities for file writing 14 | 15 | 16 | def create_temporary_file(tmp_path: Path, file_name: str) -> Tuple[Path, io.TextIOWrapper]: 17 | d = tmp_path / 'configs' 18 | d.mkdir(parents=True, exist_ok=True) 19 | p = d / file_name 20 | f = open(p, "w") 21 | return p, f 22 | 23 | 24 | def write_parameter_to_file(f: io.TextIOWrapper, varname: str, varvalue: Any) -> None: 25 | f.write(varname + ': ' + str(varvalue) + '\n') 26 | 27 | 28 | def write_matrix_to_file(f: io.TextIOWrapper, keys: List[str], lists) -> None: 29 | # assert len(keys) == len(lists) 30 | f.write('matrix' + ': ' + '\n') 31 | for i in range(len(keys)): 32 | f.write(' ' + keys[i] + ': ' + '\n') 33 | for j in range(len(lists[i])): 34 | f.write(' ' + '- ' + str(lists[i][j]) + '\n') 35 | 36 | 37 | def write_set_to_file(f: io.TextIOWrapper, set_list: List[Dict[str, Union[int, float]]]) -> None: 38 | f.write('set' + ': ' + '\n') 39 | for i, _set in enumerate(set_list): 40 | f.write(' - {') 41 | for j, (k, v) in enumerate(_set.items()): 42 | f.write(k + ': ' + str(v) + ', ') 43 | f.write('}' + '\n') 44 | 45 | 46 | def yaml_from_dict(tmp_path: Path, file_name: str, _dict: Optional[Dict[str, Any]]=None) -> Path: 47 | p, f = create_temporary_file(tmp_path, file_name) 48 | if (_dict is None): 49 | _dict = {'out_dir': tmp_path / 'out_dir'} 50 | elif ('out_dir' not in _dict.keys()): 51 | _dict['out_dir'] = tmp_path / 'out_dir' 52 | 53 | for k in _dict.keys(): 54 | write_parameter_to_file(f, k, _dict[k]) 55 | f.close() 56 | return p 57 | 58 | 59 | @pytest.fixture(scope='function') 60 | def test_DeltaModel(tmp_path: Path) -> DeltaModel: 61 | file_name = 'user_parameters.yaml' 62 | p, f = create_temporary_file(tmp_path, file_name) 63 | write_parameter_to_file(f, 'out_dir', tmp_path / 'out_dir') 64 | write_parameter_to_file(f, 'Length', 10.0) 65 | write_parameter_to_file(f, 'Width', 10.0) 66 | write_parameter_to_file(f, 'seed', 0) 67 | write_parameter_to_file(f, 'dx', 1.0) 68 | write_parameter_to_file(f, 'L0_meters', 1.0) 69 | write_parameter_to_file(f, 'S0', 0.0002) 70 | write_parameter_to_file(f, 'itermax', 1) 71 | write_parameter_to_file(f, 'Np_water', 10) 72 | write_parameter_to_file(f, 'u0', 1.0) 73 | write_parameter_to_file(f, 'N0_meters', 2.0) 74 | write_parameter_to_file(f, 'h0', 1.0) 75 | write_parameter_to_file(f, 'H_SL', 0.0) 76 | write_parameter_to_file(f, 'SLR', 0.001) 77 | write_parameter_to_file(f, 'Np_sed', 10) 78 | write_parameter_to_file(f, 'f_bedload', 0.5) 79 | write_parameter_to_file(f, 'C0_percent', 0.1) 80 | write_parameter_to_file(f, 'toggle_subsidence', False) 81 | write_parameter_to_file(f, 'subsidence_rate', 0.0) 82 | write_parameter_to_file(f, 'start_subsidence', 50.) 83 | write_parameter_to_file(f, 'save_eta_figs', False) 84 | write_parameter_to_file(f, 'save_stage_figs', False) 85 | write_parameter_to_file(f, 'save_depth_figs', False) 86 | write_parameter_to_file(f, 'save_discharge_figs', False) 87 | write_parameter_to_file(f, 'save_velocity_figs', False) 88 | write_parameter_to_file(f, 'save_eta_grids', False) 89 | write_parameter_to_file(f, 'save_stage_grids', False) 90 | write_parameter_to_file(f, 'save_depth_grids', False) 91 | write_parameter_to_file(f, 'save_discharge_grids', False) 92 | write_parameter_to_file(f, 'save_velocity_grids', False) 93 | write_parameter_to_file(f, 'save_dt', 500) 94 | f.close() 95 | _delta = DeltaModel(input_file=p) 96 | return _delta 97 | 98 | 99 | class FastIteratingDeltaModel: 100 | """A Fast iterating DeltaModel 101 | 102 | This class is useful in patching the DeltaModel for timing tests. The 103 | patched DeltaModel uses the random number generation internally, so it 104 | will verify functionality in any checkpointing scenarios, and overwriting 105 | only the `solve_water_and_sediment_timestep` method removes most of the jitting compilation 106 | time and much of the actual computation time. 107 | """ 108 | 109 | def solve_water_and_sediment_timestep(self) -> None: 110 | """PATCH""" 111 | 112 | def _get_random_field(shp: Tuple[int, ...]) -> np.ndarray: 113 | """Get a field or randoms using the shared function. 114 | 115 | It is critical to use the `shared_tools.get_random_uniform` for 116 | reproducibility. 117 | """ 118 | field = np.zeros(shp, dtype=np.float32) 119 | for i in range(shp[0]): 120 | for j in range(shp[1]): 121 | field[i, j] = shared_tools.get_random_uniform(1) 122 | return field 123 | 124 | shp = self.eta.shape 125 | self.eta += _get_random_field(shp) 126 | self.uw += _get_random_field(shp) 127 | self.ux += _get_random_field(shp) 128 | self.uy += _get_random_field(shp) 129 | self.depth += _get_random_field(shp) 130 | self.stage += _get_random_field(shp) 131 | 132 | 133 | def read_endtime_from_log(log_folder) -> float: 134 | _logs = glob.glob(os.path.join(log_folder, '*.log')) 135 | assert len(_logs) == 1 # log file exists 136 | with open(_logs[0], 'r') as _logfile: 137 | _lines = _logfile.readlines() 138 | _t = 0 139 | for i, _line in enumerate(_lines): 140 | if 'Time: ' in _line: 141 | _t = _line.split(' ')[6] 142 | _t = _t.strip(' ;') 143 | return float(_t) 144 | --------------------------------------------------------------------------------