├── .devcontainer
├── devcontainer.json
└── docker-compose.yml
├── .gitattributes
├── .github
└── workflows
│ └── CI.yml
├── .gitignore
├── .readthedocs.yml
├── .zenodo.json
├── CHANGELOG.md
├── Dockerfile
├── LICENSE.md
├── MANIFEST.in
├── README.md
├── UWGeodynamics
├── LecodeIsostasy
│ ├── LecodeIsostasy.py
│ └── __init__.py
├── __init__.py
├── _boundary_conditions.py
├── _density.py
├── _freesurface.py
├── _frictional_boundary.py
├── _material.py
├── _melt.py
├── _mesh_advector.py
├── _model.py
├── _net
│ └── __init__.py
├── _rcParams.py
├── _remeshing.py
├── _rheology.py
├── _utils.py
├── _validate.py
├── _visugrid.py
├── lithopress
│ ├── __init__.py
│ └── lithopress.py
├── postprocessing
│ ├── __init__.py
│ ├── _logFile.py
│ └── _tracers.py
├── ressources
│ ├── Liquidus.json
│ ├── Materials.json
│ ├── PlasticRheologies.json
│ ├── Solidus.json
│ └── ViscousRheologies.json
├── shapes.py
├── surfaceProcesses.py
├── utilities
│ ├── UWtoAscii.py
│ └── __init__.py
├── uwgeo-data
│ └── uwgeodynamicsrc
└── version.py
├── conda
└── meta.yaml
├── docker-compose.yaml
├── docs
├── .gitignore
├── README.md
├── benchmarks
│ ├── 1_12_Slab_Detachment_Benchmark.ipynb
│ ├── 1_22_Indentor_Benchmark.ipynb
│ ├── 2D_Self_Subduction_Case1.ipynb
│ ├── 2D_Self_Subduction_Case2.ipynb
│ ├── Kaus_BrickBenchmark-Compression.ipynb
│ └── Kaus_BrickBenchmark_Extension.ipynb
├── examples
│ ├── 1_01_Steady_State_Heat.ipynb
│ ├── 1_02_Convection_Example.ipynb
│ ├── 1_03_BlankenbachBenchmark.ipynb
│ ├── 1_05_StokesSinker.ipynb
│ ├── 1_06_HypnicJerk.ipynb
│ ├── 1_07_SlabSubduction.ipynb
│ ├── 1_08_ViscoElasticHalfSpace.ipynb
│ ├── 1_09_ViscoElasticShear.ipynb
│ ├── 1_10_Viscoelastoplasticity-in-simple-shear.ipynb
│ ├── 1_11_StokesSinker3D.ipynb
│ ├── 1_20_ColumnsTractionBottom.ipynb
│ ├── 1_21_3D_ColumnsTractionBottom.ipynb
│ ├── 1_23_01_FreeSurface_Simple_Example.ipynb
│ ├── 1_23_02_FreeSurface_Kaus2010_Rayleigh-Taylor_Instability.ipynb
│ ├── 1_23_03_FreeSurface_Crameri2012Case1_Relaxation.ipynb
│ ├── 1_23_04_FreeSurface_Crameri2012Case2_Rising_Plume.ipynb
│ ├── 1_24_Define_3D_volumes.ipynb
│ ├── 1_25_Hot_Canon_Ball.ipynb
│ ├── 1_26_NumericalSandboxCompression-MovingWall.ipynb
│ ├── 1_27_ColumnPureThermalAdvection.ipynb
│ ├── 1_28_Kaus2010_Free_Surface_Stabilization.ipynb
│ ├── 1_30_Poiseuille_Under_Pressure.ipynb
│ ├── 1_31_User_defined_geotherm_and_TP_dependent_densities.ipynb
│ ├── 1_32_Passive_Tracers_tests.ipynb
│ ├── 2_09_ShearBandsPureShear.ipynb
│ ├── 2_15_Rayleigh-Taylor_van_Keken_et_al_1997.ipynb
│ └── images
│ │ ├── 3D_hafspaces.png
│ │ ├── 3D_layer.png
│ │ ├── CompressionSetUp.png
│ │ ├── Extension.png
│ │ ├── ExtensionA.png
│ │ ├── ExtensionB.png
│ │ ├── HotCanonFig.png
│ │ ├── HypnicJerk.gif
│ │ ├── MovingWall.gif
│ │ ├── SlabDetachment.png
│ │ ├── Stokes2D.gif
│ │ └── vanKekken.gif
├── readthedocs
│ ├── Makefile
│ ├── make.bat
│ ├── requirements.txt
│ └── src
│ │ ├── Benchmarks.rst
│ │ ├── Examples.rst
│ │ ├── Installation.rst
│ │ ├── Troubleshoot.rst
│ │ ├── Tutorials.rst
│ │ ├── UserGuide.rst
│ │ ├── conf.py
│ │ ├── img
│ │ ├── 2D_polygon.png
│ │ ├── 3D_halfspaces.png
│ │ ├── 3D_halfspaces2.png
│ │ ├── 3D_layer.png
│ │ ├── Design.svg
│ │ ├── Material1.png
│ │ ├── MaterialRegistry.gif
│ │ ├── PlasticityRegistry.gif
│ │ ├── SandboxCompression.gif
│ │ ├── Tutorial1.gif
│ │ ├── Tutorial11.gif
│ │ ├── Tutorial4.png
│ │ ├── Tutorial_9.gif
│ │ ├── ViscousCreepRegistry.gif
│ │ ├── annulus.png
│ │ ├── box.png
│ │ ├── collision_wedge.gif
│ │ ├── density.png
│ │ ├── disk.png
│ │ ├── gif1.gif
│ │ ├── kitematic.gif
│ │ ├── layers.png
│ │ ├── logos.png
│ │ ├── mechanicalBCs1.png
│ │ ├── mechanicalBCs2.png
│ │ ├── multiple_materials.png
│ │ ├── multishape-1.png
│ │ ├── multishape.png
│ │ ├── polygon.png
│ │ ├── tabtab.gif
│ │ ├── thermalBCs1.png
│ │ ├── thermalBCs2.png
│ │ └── underworld.png
│ │ └── index.rst
├── tutorials
│ ├── .gitignore
│ ├── Tutorial_10_Thrust_Wedges.ipynb
│ ├── Tutorial_11_Coupling_with_Badlands.ipynb
│ ├── Tutorial_1_ThermoMechanical_Model.ipynb
│ ├── Tutorial_2_Melt.ipynb
│ ├── Tutorial_3B_SandboxExtension_deform_mesh.ipynb
│ ├── Tutorial_3_SandboxExtension_static_mesh.ipynb
│ ├── Tutorial_4_NumericalSandboxCompression.ipynb
│ ├── Tutorial_5_Convergence_Model.ipynb
│ ├── Tutorial_6_1_sedimentation_erosion_rates.ipynb
│ ├── Tutorial_6_2_diffusive_surface.ipynb
│ ├── Tutorial_6_Simple_Surface_Processes.ipynb
│ ├── Tutorial_7_3D_Lithospheric_Model.ipynb
│ ├── Tutorial_8_Subduction_ViscoElastic.ipynb
│ ├── Tutorial_9_passive_margins.ipynb
│ ├── images
│ │ ├── CompressionA.png
│ │ ├── CompressionB.png
│ │ ├── CompressionSetUp.png
│ │ ├── Extension.png
│ │ ├── ExtensionA.png
│ │ ├── ExtensionB.png
│ │ ├── LAnson2018.png
│ │ ├── Rey_et_al2009.png
│ │ ├── Tutorial1.gif
│ │ ├── Tutorial11.gif
│ │ ├── Tutorial4.png
│ │ ├── Tutorial_10.gif
│ │ ├── Tutorial_10_bcs.png
│ │ ├── Tutorial_9.gif
│ │ └── underworld.png
│ └── ressources
│ │ └── badlands.xml
└── uwgeodynamicsrc.template
├── joss
├── codemeta.json
├── paper.bib
└── paper.md
├── requirements.txt
├── setup.cfg
├── setup.py
└── tests
├── __init__.py
├── doctests.py
├── image_tests.py
├── image_tests
└── examples
│ ├── 1_01_Steady_State_Heat
│ └── expected
│ │ ├── Figure_1.png
│ │ └── Figure_2.png
│ ├── 1_02_Convection_Example
│ └── expected
│ │ ├── Figure_1.png
│ │ ├── Figure_2.png
│ │ └── Figure_3.png
│ ├── 1_25_Hot_Canon_Ball
│ └── expected
│ │ ├── Figure_1.png
│ │ └── Figure_2.png
│ └── runtest.py
├── test_benchmarks.py
├── test_examples.py
├── test_results
├── benchmarks
│ └── .gitignore
├── examples
│ └── .gitignore
└── tutorials
│ └── .gitignore
├── test_simple.py
├── test_tutorials.py
└── utils.py
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
2 | {
3 | "name": "Existing Docker Compose (Extend)",
4 |
5 | // Update the 'dockerComposeFile' list if you have more compose files or use different names.
6 | // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
7 | "dockerComposeFile": [
8 | "../docker-compose.yaml",
9 | "docker-compose.yml"
10 | ],
11 |
12 | // The 'service' property is the name of the service for the container that VS Code should
13 | // use. Update this value and .devcontainer/docker-compose.yml to the real service name.
14 | "service": "underworld",
15 |
16 | // The optional 'workspaceFolder' property is the path VS Code should open by default when
17 | // connected. This is typically a file mount in .devcontainer/docker-compose.yml
18 | "workspaceFolder": "/home/jovyan/UWGeodynamics",
19 |
20 | // Use 'settings' to set *default* container specific settings.json values on container create.
21 | // You can edit these settings after create using File > Preferences > Settings > Remote.
22 | "settings": {
23 | // This will ignore your local shell user setting for Linux since shells like zsh are typically
24 | // not in base container images. You can also update this to an specific shell to ensure VS Code
25 | // uses the right one for terminals and tasks. For example, /bin/bash (or /bin/ash for Alpine).
26 | "terminal.integrated.shell.linux": "/bin/bash",
27 | "python.pythonPath": "/opt/venv/bin/python3.7"
28 | },
29 |
30 | // Uncomment the next line if you want start specific services in your Docker Compose config.
31 | // "runServices": [],
32 |
33 | // Uncomment the next line if you want to keep your containers running after VS Code shuts down.
34 | // "shutdownAction": "none",
35 |
36 | // Uncomment the next line to run commands after the container is created - for example installing git.
37 | "postCreateCommand": "pip3 install -e .",
38 |
39 | // Add the IDs of extensions you want installed when the container is created in the array below.
40 | "extensions": ["ms-python.python", "ms-vscode.cpptools"]
41 | }
42 |
--------------------------------------------------------------------------------
/.devcontainer/docker-compose.yml:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------------------------------------------------------------------
2 | # Copyright (c) Microsoft Corporation. All rights reserved.
3 | # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
4 | #-------------------------------------------------------------------------------------------------------------
5 |
6 | version: '3.7'
7 | services:
8 | # Update this to the name of the service you want to work with in your docker-compose.yml file
9 | underworld:
10 | # You may want to add a non-root user to your Dockerfile. On Linux, this will prevent
11 | # new files getting created as root. See https://aka.ms/vscode-remote/containers/non-root-user
12 | # for the needed Dockerfile updates and then uncomment the next line.
13 | user: root
14 | privileged: true
15 |
16 | # Uncomment if you want to add a different Dockerfile in the .devcontainer folder
17 | # build:
18 | # context: .
19 | # dockerfile: Dockerfile
20 |
21 | # Uncomment if you want to expose any additional ports. The snippet below exposes port 3000.
22 | # ports:
23 | # - 3000:3000
24 |
25 | volumes:
26 | # Update this to wherever you want VS Code to mount the folder of your project
27 | - .:/home/jovyan/UWGeodynamics
28 |
29 | # Uncomment the next line to use Docker from inside the container. See https://aka.ms/vscode-remote/samples/docker-in-docker-compose for details.
30 | # - /var/run/docker.sock:/var/run/docker.sock
31 |
32 | # Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust.
33 | # cap_add:
34 | # - SYS_PTRACE
35 | # security_opt:
36 | # - seccomp:unconfined
37 |
38 | # Overrides default command so things don't shut down after the process ends.
39 | entrypoint: /bin/bash -c "while sleep 1000; do :; done"
40 |
41 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | docs/* linguist-vendored
2 |
--------------------------------------------------------------------------------
/.github/workflows/CI.yml:
--------------------------------------------------------------------------------
1 | name: docker images build
2 |
3 | on:
4 | push:
5 | workflow_dispatch:
6 |
7 | jobs:
8 |
9 | build_uwgeo_image:
10 | name: Build Docker image
11 | runs-on: ubuntu-latest
12 | steps:
13 |
14 | - name: Checkout
15 | uses: actions/checkout@v2
16 |
17 | - name: Set up Docker Buildx
18 | uses: docker/setup-buildx-action@v1
19 |
20 | - name: Login to DockerHub
21 | uses: docker/login-action@v1
22 | with:
23 | username: ${{ secrets.DOCKER_USERNAME }}
24 | password: ${{ secrets.DOCKER_PASSWORD }}
25 |
26 | - name: Build Docker Image
27 | uses: docker/build-push-action@v2
28 | with:
29 | context: .
30 | push: true
31 | file: ./Dockerfile
32 | platforms: linux/amd64
33 | tags: underworldcode/uwgeodynamics:amd64
34 |
35 | # Manifeset is still experimental - so comment out for now.
36 | # - name: Update manifest
37 | # run: |
38 | # docker manifest create underworldcode/uwgeodynamics --amend underworldcode/uwgeodynamics:amd64 --amend underworldcode/uwgeodynamics:arm64
39 | # docker manifest push underworldcode/uwgeodynamics
40 |
41 | test_in_UW_Container:
42 | name: Test in UW Container
43 | runs-on: ubuntu-latest
44 | container:
45 | image: underworldcode/underworld2:latest
46 | options: --user root
47 | steps:
48 | - name: Checkout
49 | uses: actions/checkout@v2
50 |
51 | - name: Test in UW Container
52 | run: |
53 | pip install -e .
54 | pip install pytest
55 | pytest -vvv
56 |
57 | conda_build:
58 | name: Conda Build (Python ${{matrix.python-version}} ${{ matrix.os }})
59 | runs-on: ${{ matrix.os }}
60 | strategy:
61 | fail-fast: false
62 | matrix:
63 | os: ["ubuntu-latest", "macos-latest"]
64 | python-version: ["3.7", "3.8", "3.9"]
65 | steps:
66 | - uses: actions/checkout@v2
67 | - uses: conda-incubator/setup-miniconda@v2
68 | with:
69 | auto-update-conda: true
70 | python-version: ${{ matrix.python-version }}
71 |
72 | - name: Config Conda
73 | shell: bash -l {0}
74 | run: |
75 | conda install --channel conda-forge conda-build anaconda-client conda-verify
76 | conda config --add channels conda-forge
77 | conda config --add channels underworldcode
78 | conda config --set anaconda_upload no
79 |
80 | - name: Config Conda For Upload
81 | if: github.event_name == 'release'
82 | shell: bash -l {0}
83 | run: conda config --set anaconda_upload yes
84 |
85 | - name: Upload new Packages
86 | if: github.event_name == 'release'
87 | shell: bash -l {0}
88 | run: |
89 | anaconda login --hostname github-actions-${{ matrix.os }}-$RANDOM --username ${{ secrets.ANACONDA_USERNAME }} --password ${{ secrets.ANACONDA_PASSWORD }}
90 | conda-build --channel conda-forge --user geo-down-under conda
91 | anaconda logout
92 |
93 | pypi:
94 | runs-on: ${{ matrix.os }}
95 | env:
96 | TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
97 | TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
98 | strategy:
99 | matrix:
100 | os: [ubuntu-latest, macos-latest]
101 | python-version: [3.7, 3.8, 3.9]
102 | steps:
103 | - uses: actions/checkout@v2
104 | - name: Set up Python
105 | uses: actions/setup-python@v2
106 | with:
107 | python-version: ${{ matrix.python-version }}
108 | - name: build wheel
109 | if: ${{ matrix.os }} == 'ubuntu-latest'
110 | run: |
111 | pip install wheel
112 | python setup.py bdist_wheel --universal
113 | - name: build wheel
114 | if: ${{ matrix.os }} == 'macos-latest'
115 | run: |
116 | pip install wheel
117 | python setup.py bdist_wheel
118 | - name: upload wheel
119 | if: github.event_name == 'release'
120 | run: |
121 | pip install twine
122 | python -m twine upload dist/*
123 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # general things to ignore
2 | build/
3 | dist/
4 | *.egg-info/
5 | *.egg
6 | *.py[cod]
7 | __pycache__/
8 | *.so
9 | *~
10 | */.ipynb_checkpoints
11 | tests/test_results/*
12 | tutorials/*.png
13 | examples/*.png
14 | tutorials/out*
15 | UWGeodynamics/version.py
16 |
17 | # due to using tox and pytest
18 | .tox
19 | .cache
20 |
21 | *.h5
22 | *.xmf
23 | *.xdmf
24 | *.hdf5
25 |
--------------------------------------------------------------------------------
/.readthedocs.yml:
--------------------------------------------------------------------------------
1 | # .readthedocs.yml
2 | # Read the Docs configuration file
3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4 |
5 | # Required
6 | version: 2
7 |
8 | # Build documentation in the docs/ directory with Sphinx
9 | sphinx:
10 | configuration: docs/readthedocs/src/conf.py
11 |
12 | # Optionally build your docs in additional formats such as PDF
13 | formats:
14 | - pdf
15 |
16 | # Optionally set the version of Python and requirements required to build your docs
17 | python:
18 | version: "3.8"
19 | install:
20 | - requirements: docs/readthedocs/requirements.txt
21 |
--------------------------------------------------------------------------------
/.zenodo.json:
--------------------------------------------------------------------------------
1 | {
2 | "creators": [
3 | {
4 | "name": "Romain Beucher",
5 | "affiliation": "Research School of Earth Sciences, The Australian National University",
6 | "orcid": "0000-0003-3891-5444"
7 | },
8 | {
9 | "name": "Louis Moresi",
10 | "affiliation": "Research School of Earth Sciences, The Australian National University",
11 | "orcid": "0000-0003-3685-174X"
12 | },
13 | {
14 | "name": "Julian Giordani",
15 | "affiliation": "School of Geosciences, The University of Sydney",
16 | "orcid": "0000-0003-4515-9296"
17 | },
18 | {
19 | "name": "John Mansour",
20 | "affiliation": "Monash eResearch Centre, Monash University",
21 | "orcid": "0000-0001-5865-1664"
22 | },
23 | {
24 | "name": "Dan Sandiford",
25 | "affiliation": "University of Tasmania",
26 | "orcid": "0000-0002-2207-6837"
27 | },
28 | {
29 | "name": "Rebecca Farrington",
30 | "affiliation": "School of Earth Science, The University of Melbourne",
31 | "orcid": "0000-0002-2594-6965"
32 | },
33 | {
34 | "name": "Luke Mondy",
35 | "affiliation": "School of Geosciences, Earthbyte Research Group, The University of Sydney",
36 | "orcid": "0000-0001-7779-509X"
37 | },
38 | {
39 | "name": "Claire Mallard",
40 | "affiliation": "School of Geosciences, Earthbyte Research Group, The University of Sydney",
41 | "orcid": "0000-0003-2595-2414"
42 | },
43 | {
44 | "name": "Patrice Rey",
45 | "affiliation": "School of Geosciences, Earthbyte Research Group, The University of Sydney",
46 | "orcid": "0000-0002-1767-8593"
47 | },
48 | {
49 | "name": "Guillaume Duclaux",
50 | "affiliation": "Laboratoire Géoazur, Université Nice Sophia Antipolis, Nice",
51 | "orcid": "0000-0002-9512-7252"
52 | },
53 | {
54 | "name": "owen kaluza",
55 | "affiliation": "Monash eResearch Centre, Monash University",
56 | "orcid": "0000-0001-6303-5671"
57 | },
58 | {
59 | "name": "Arijit Laik",
60 | "affiliation": "Department of Earth Science, Faculty of Science, Vrije Universiteit",
61 | "orcid": "0000-0002-3484-7985"
62 | },
63 | {
64 | "name": "Sara Morón",
65 | "affiliation": "School of Geosciences, Earthbyte Research Group, The University of Sydney",
66 | "orcid": "0000-0002-1270-4377"
67 | }
68 | {
69 | "name": "Ben Knight",
70 | "affiliation": "Monash University",
71 | "orcid": "0000-0001-7919-2575"
72 | }
73 | {
74 | "name": "Neng Lu",
75 | "affiliation": "Research School of Earth Sciences, The Australian National University",
76 | "orcid": "0000-0001-9424-2315"
77 | }
78 | ],
79 | "license": "lgpl-3.0",
80 | "title": "UWGeodynamics: A teaching an research tool for numerical geodynamic modelling",
81 | "upload_type": "software",
82 | "access_right": "open"
83 | }
84 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Version 2.12
2 |
3 | - 2D surface processes implementation. Update to surface processes file to include erosion & sedimentation rate or diffusive surface in 2D.
4 | - Tutorials that outline how to use the different surface processes.
5 | - Free Surface examples.
6 |
7 | ### Bug Fixes:
8 | - Drucker Prager Yield Criterion in 3D. A sign error resulted in a lower Yield Stress which resulted in more diffuse weakening when using plasticity with a DP criterion. This has likely impacted all 3D models since early versions of UWGeodynamics. We recommend updating asap.
9 | - Fix some typos in the Rheology references (Asthenospheric type rheology from Watremez et al was referred as Lithospheric)
10 | - Fix Free surface implementation.
11 |
12 | # Version 2.11
13 |
14 | - Change Passive Tracers Interface. The ``Model.add_passive_tracers`` method now return ``None``. Tracers can be accessed via the Model object. This is to avoid orphans and usage errors when doing a restart.
15 | - Add option to pass UW function (or mesh variable) to the density material properties.
16 | - `Model.init_model()` excepts arguments to optional to initiliase temperature and pressure fields with an UW function or a mesh variable.
17 | - Various bug fixes.
18 |
19 | # Version 2.10
20 |
21 | - Layer2D which has now been deprecated for a while has been removed
22 |
23 | # Version 2.9
24 |
25 | ### User related changes:
26 | - The 'visualisation' python module replaces the 'glucifer' python module (as per UW 2.9)
27 | To update in your model, replace the line
28 | `import glucifer`
29 | with
30 | `from UWGeodynamics import visualisation as vis`
31 | 'vis' can be used as 'glucifer' was.
32 |
33 | - Compatible with UW 2.9
34 | - New Numpy Pressure Smoother
35 |
36 | ### Enhancements:
37 | - Upgrade to Dockerfile configuration, using "muli-stage" builds.
38 |
39 | ### Bug Fixes:
40 | - Passive tracer initialisation in 3D.
41 | - Restarting with track fields and swarm global indices.
42 | - Passive tracer interface changes. vertices must be passed as a numpy array
43 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Stage 1: Inherit from underworldcode/underworld2 and install dependency packages for Badlands
2 | ##########
3 | FROM underworldcode/underworld2:latest as base_runtime
4 | # install runtime requirements
5 | USER root
6 | RUN /usr/bin/python3 -m virtualenv --python=/usr/bin/python3 ${VIRTUAL_ENV}
7 |
8 | # Stage 2: Build and install Badlands
9 | ##########
10 | FROM base_runtime AS build_base
11 | RUN apt-get update -qq
12 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \
13 | build-essential \
14 | gfortran \
15 | python3-dev \
16 | swig \
17 | libxml2-dev
18 | RUN /usr/bin/python3 -m virtualenv --python=/usr/bin/python3 ${VIRTUAL_ENV}
19 | WORKDIR /tmp
20 | COPY --chown=jovyan:users . /tmp/UWGeodynamics
21 | RUN pip3 install -vvv UWGeodynamics/
22 | RUN pip3 install -U badlands
23 |
24 |
25 | # Stage 3: Resultant images
26 | ##########
27 | FROM base_runtime
28 | COPY --from=build_base ${VIRTUAL_ENV} ${VIRTUAL_ENV}
29 | # Record Python packages, but only record system packages!
30 | # Not venv packages, which will be copied directly in.
31 | RUN PYTHONPATH= /usr/bin/pip3 freeze >/opt/requirements.txt
32 | # Record manually install apt packages.
33 | RUN apt-mark showmanual >/opt/installed.txt
34 | USER $NB_USER
35 | WORKDIR $NB_WORK
36 | CMD ["jupyter", "notebook", "--ip='0.0.0.0'", "--no-browser"]
37 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | GNU Lesser General Public License
2 | =================================
3 |
4 | _Version 3, 29 June 2007_
5 | _Copyright © 2007 Free Software Foundation, Inc. <>_
6 |
7 | Everyone is permitted to copy and distribute verbatim copies
8 | of this license document, but changing it is not allowed.
9 |
10 |
11 | This version of the GNU Lesser General Public License incorporates
12 | the terms and conditions of version 3 of the GNU General Public
13 | License, supplemented by the additional permissions listed below.
14 |
15 | ### 0. Additional Definitions
16 |
17 | As used herein, “this License” refers to version 3 of the GNU Lesser
18 | General Public License, and the “GNU GPL” refers to version 3 of the GNU
19 | General Public License.
20 |
21 | “The Library” refers to a covered work governed by this License,
22 | other than an Application or a Combined Work as defined below.
23 |
24 | An “Application” is any work that makes use of an interface provided
25 | by the Library, but which is not otherwise based on the Library.
26 | Defining a subclass of a class defined by the Library is deemed a mode
27 | of using an interface provided by the Library.
28 |
29 | A “Combined Work” is a work produced by combining or linking an
30 | Application with the Library. The particular version of the Library
31 | with which the Combined Work was made is also called the “Linked
32 | Version”.
33 |
34 | The “Minimal Corresponding Source” for a Combined Work means the
35 | Corresponding Source for the Combined Work, excluding any source code
36 | for portions of the Combined Work that, considered in isolation, are
37 | based on the Application, and not on the Linked Version.
38 |
39 | The “Corresponding Application Code” for a Combined Work means the
40 | object code and/or source code for the Application, including any data
41 | and utility programs needed for reproducing the Combined Work from the
42 | Application, but excluding the System Libraries of the Combined Work.
43 |
44 | ### 1. Exception to Section 3 of the GNU GPL
45 |
46 | You may convey a covered work under sections 3 and 4 of this License
47 | without being bound by section 3 of the GNU GPL.
48 |
49 | ### 2. Conveying Modified Versions
50 |
51 | If you modify a copy of the Library, and, in your modifications, a
52 | facility refers to a function or data to be supplied by an Application
53 | that uses the facility (other than as an argument passed when the
54 | facility is invoked), then you may convey a copy of the modified
55 | version:
56 |
57 | * **a)** under this License, provided that you make a good faith effort to
58 | ensure that, in the event an Application does not supply the
59 | function or data, the facility still operates, and performs
60 | whatever part of its purpose remains meaningful, or
61 |
62 | * **b)** under the GNU GPL, with none of the additional permissions of
63 | this License applicable to that copy.
64 |
65 | ### 3. Object Code Incorporating Material from Library Header Files
66 |
67 | The object code form of an Application may incorporate material from
68 | a header file that is part of the Library. You may convey such object
69 | code under terms of your choice, provided that, if the incorporated
70 | material is not limited to numerical parameters, data structure
71 | layouts and accessors, or small macros, inline functions and templates
72 | (ten or fewer lines in length), you do both of the following:
73 |
74 | * **a)** Give prominent notice with each copy of the object code that the
75 | Library is used in it and that the Library and its use are
76 | covered by this License.
77 | * **b)** Accompany the object code with a copy of the GNU GPL and this license
78 | document.
79 |
80 | ### 4. Combined Works
81 |
82 | You may convey a Combined Work under terms of your choice that,
83 | taken together, effectively do not restrict modification of the
84 | portions of the Library contained in the Combined Work and reverse
85 | engineering for debugging such modifications, if you also do each of
86 | the following:
87 |
88 | * **a)** Give prominent notice with each copy of the Combined Work that
89 | the Library is used in it and that the Library and its use are
90 | covered by this License.
91 |
92 | * **b)** Accompany the Combined Work with a copy of the GNU GPL and this license
93 | document.
94 |
95 | * **c)** For a Combined Work that displays copyright notices during
96 | execution, include the copyright notice for the Library among
97 | these notices, as well as a reference directing the user to the
98 | copies of the GNU GPL and this license document.
99 |
100 | * **d)** Do one of the following:
101 | - **0)** Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 | - **1)** Use a suitable shared library mechanism for linking with the
109 | Library. A suitable mechanism is one that **(a)** uses at run time
110 | a copy of the Library already present on the user's computer
111 | system, and **(b)** will operate properly with a modified version
112 | of the Library that is interface-compatible with the Linked
113 | Version.
114 |
115 | * **e)** Provide Installation Information, but only if you would otherwise
116 | be required to provide such information under section 6 of the
117 | GNU GPL, and only to the extent that such information is
118 | necessary to install and execute a modified version of the
119 | Combined Work produced by recombining or relinking the
120 | Application with a modified version of the Linked Version. (If
121 | you use option **4d0**, the Installation Information must accompany
122 | the Minimal Corresponding Source and Corresponding Application
123 | Code. If you use option **4d1**, you must provide the Installation
124 | Information in the manner specified by section 6 of the GNU GPL
125 | for conveying Corresponding Source.)
126 |
127 | ### 5. Combined Libraries
128 |
129 | You may place library facilities that are a work based on the
130 | Library side by side in a single library together with other library
131 | facilities that are not Applications and are not covered by this
132 | License, and convey such a combined library under terms of your
133 | choice, if you do both of the following:
134 |
135 | * **a)** Accompany the combined library with a copy of the same work based
136 | on the Library, uncombined with any other library facilities,
137 | conveyed under the terms of this License.
138 | * **b)** Give prominent notice with the combined library that part of it
139 | is a work based on the Library, and explaining where to find the
140 | accompanying uncombined form of the same work.
141 |
142 | ### 6. Revised Versions of the GNU Lesser General Public License
143 |
144 | The Free Software Foundation may publish revised and/or new versions
145 | of the GNU Lesser General Public License from time to time. Such new
146 | versions will be similar in spirit to the present version, but may
147 | differ in detail to address new problems or concerns.
148 |
149 | Each version is given a distinguishing version number. If the
150 | Library as you received it specifies that a certain numbered version
151 | of the GNU Lesser General Public License “or any later version”
152 | applies to it, you have the option of following the terms and
153 | conditions either of that published version or of any later version
154 | published by the Free Software Foundation. If the Library as you
155 | received it does not specify a version number of the GNU Lesser
156 | General Public License, you may choose any version of the GNU Lesser
157 | General Public License ever published by the Free Software Foundation.
158 |
159 | If the Library as you received it specifies that a proxy can decide
160 | whether future versions of the GNU Lesser General Public License shall
161 | apply, that proxy's public statement of acceptance of any version is
162 | permanent authorization for you to choose that version for the
163 | Library.
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | # Include the license file
2 | include LICENSE.md
3 | include uwgeodynamicsrc.template
4 | recursive-include utils *.sh
5 | recursive-include UWGeodynamics/ressources *.json
6 | recursive-include UWGeodynamics/uwgeo-data *
7 |
8 | prune docs
9 |
--------------------------------------------------------------------------------
/UWGeodynamics/LecodeIsostasy/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 | from .LecodeIsostasy import LecodeIsostasy
3 | __version__ = "0.1"
4 |
5 |
--------------------------------------------------------------------------------
/UWGeodynamics/_density.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 | import underworld.function as fn
3 | from UWGeodynamics import non_dimensionalise as nd
4 | from UWGeodynamics import UnitRegistry as u
5 |
6 |
7 | class Density(object):
8 |
9 | def __init__(self):
10 | self.temperatureField = None
11 | self.pressureField = None
12 | self.name = None
13 |
14 |
15 | class ConstantDensity(Density):
16 |
17 | def __init__(self, reference_density):
18 | """Constant density function
19 |
20 | Parameters
21 | ----------
22 |
23 | reference_density : density
24 |
25 | Returns
26 | -------
27 |
28 | An UWGeodynamics Constant Density object
29 | """
30 | self.reference_density = reference_density
31 | self._density = nd(reference_density)
32 | self.name = "Constant ({0})".format(str(reference_density))
33 |
34 | def effective_density(self):
35 | return fn.Function.convert(self._density)
36 |
37 |
38 | class LinearDensity(Density):
39 |
40 | def __init__(self, reference_density, thermalExpansivity=3e-5 / u.kelvin,
41 | reference_temperature=273.15 * u.degK, beta=0. / u.pascal,
42 | reference_pressure=0. * u.pascal):
43 | """ The LinearDensity function calculates:
44 | density = rho0 * (1 + (beta * deltaP) - (alpha * deltaT))
45 | where deltaP is the difference between P and the reference P,
46 | and deltaT is the difference between T and the reference T
47 |
48 | Parameters
49 | ----------
50 |
51 | reference_density : reference density
52 | thermalExpansivity : thermal expansivity of the material at the
53 | temperature of reference.
54 | reference_temperature : reference temperature
55 | beta : coefficient of compressibility
56 | reference_pressure : reference pressure
57 |
58 | Returns
59 | -------
60 |
61 | An UWGeodynamics Linear Density object.
62 | """
63 |
64 | super(LinearDensity, self).__init__()
65 |
66 | self.name = "Linear (ref: {0})".format(str(reference_density))
67 | self.reference_density = reference_density
68 | self.reference_temperature = reference_temperature
69 | self.thermalExpansivity = thermalExpansivity
70 | self.reference_pressure = reference_pressure
71 | self._alpha = nd(thermalExpansivity)
72 | self._beta = nd(beta)
73 | self._Tref = nd(reference_temperature)
74 | self._Pref = nd(reference_pressure)
75 |
76 | def effective_density(self):
77 | """calculate effective_density based
78 | on PT conditions"""
79 |
80 | density = nd(self.reference_density)
81 |
82 | # Temperature dependency
83 | if not self.temperatureField:
84 | raise RuntimeError("No temperatureField found!")
85 |
86 | t_term = self._alpha * (self.temperatureField - self._Tref)
87 |
88 | # Pressure dependency
89 | if not self.pressureField:
90 | raise RuntimeError("No pressureField found!")
91 |
92 | p_term = self._beta * (self.pressureField - self._Pref)
93 |
94 | return density * (1.0 + p_term - t_term)
95 |
96 |
--------------------------------------------------------------------------------
/UWGeodynamics/_freesurface.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 | from scipy.interpolate import interp1d
3 | import underworld as uw
4 | from UWGeodynamics import nd
5 | from mpi4py import MPI as _MPI
6 |
7 | comm = _MPI.COMM_WORLD
8 | rank = comm.rank
9 | size = comm.size
10 |
11 | class FreeSurfaceProcessor(object):
12 | """FreeSurfaceProcessor"""
13 |
14 | def __init__(self, model):
15 | """Create a Freesurface processor
16 |
17 | Parameters
18 | ----------
19 |
20 | model : UWGeodynamics Model
21 |
22 | """
23 | self.model = model
24 |
25 | minCoord = tuple([nd(val) for val in self.model.minCoord])
26 | maxCoord = tuple([nd(val) for val in self.model.maxCoord])
27 |
28 | # Initialize model mesh
29 | self._init_mesh = uw.mesh.FeMesh_Cartesian(elementType=self.model.elementType,
30 | elementRes=self.model.elementRes,
31 | minCoord=minCoord,
32 | maxCoord=maxCoord,
33 | periodic=self.model.periodic)
34 |
35 | # Create the tools
36 | self.TField = self._init_mesh.add_variable(nodeDofCount=1)
37 | self.TField.data[:, 0] = self._init_mesh.data[:, 1].copy()
38 |
39 | self.top = self.model.top_wall
40 | self.bottom = self.model.bottom_wall
41 |
42 | # Create boundary condition
43 | self._conditions = uw.conditions.DirichletCondition(
44 | variable=self.TField,
45 | indexSetsPerDof=(self.top + self.bottom,))
46 |
47 | # Create Eq System
48 | self._system = uw.systems.SteadyStateHeat(
49 | temperatureField=self.TField,
50 | fn_diffusivity=1.0,
51 | conditions=self._conditions)
52 |
53 | self._solver = uw.systems.Solver(self._system)
54 |
55 | def _solve_sle(self):
56 | self._solver.solve()
57 |
58 | def _advect_surface(self, dt):
59 |
60 | if self.top:
61 | # Extract top surface
62 | x = self.model.mesh.data[self.top.data][:, 0]
63 | y = self.model.mesh.data[self.top.data][:, 1]
64 |
65 | # Extract velocities from top
66 | vx = self.model.velocityField.data[self.top.data][:, 0]
67 | vy = self.model.velocityField.data[self.top.data][:, 1]
68 |
69 | # Advect top surface
70 | x2 = x + vx * nd(dt)
71 | y2 = y + vy * nd(dt)
72 |
73 | # Spline top surface
74 | f = interp1d(x2, y2, kind='cubic', fill_value='extrapolate')
75 |
76 | self.TField.data[self.top.data, 0] = f(x)
77 | comm.Barrier()
78 | self.TField.syncronise()
79 |
80 | def _update_mesh(self):
81 |
82 | with self.model.mesh.deform_mesh():
83 | # Last dimension is the vertical dimension
84 | self.model.mesh.data[:, -1] = self.TField.data[:, 0].copy()
85 |
86 | def solve(self, dtime):
87 | """ Advect free surface through dt and update the mesh """
88 |
89 | # First we advect the surface
90 | self._advect_surface(dtime)
91 | # Then we solve the system of linear equation
92 | self._solve_sle()
93 | # Finally we update the mesh
94 | self._update_mesh()
95 |
--------------------------------------------------------------------------------
/UWGeodynamics/_frictional_boundary.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 | import numpy as np
3 | import underworld as uw
4 | import underworld.function as fn
5 |
6 |
7 | class FrictionBoundaries(object):
8 | """ This class flags elements at the boundaries
9 |
10 | """
11 | def __init__(self, Model, rightFriction=None, leftFriction=None,
12 | topFriction=None, bottomFriction=None, frontFriction=None,
13 | backFriction=None, thickness=2):
14 | """Frictional boundaries processor_
15 |
16 | Parameters
17 | ----------
18 |
19 | Model : UWGeodynamics Model
20 | rightFriction : coefficient of friction on the right wall
21 | (tangent of the friction angle in radians)
22 |
23 | leftFriction : coefficient of friction on the left wall
24 | (tangent of the friction angle in radians)
25 |
26 | topFriction : coefficient of friction on the top wall
27 | (tangent of the friction angle in radians)
28 |
29 | bottomFriction : coefficient of friction on the bottom wall
30 | (tangent of the friction angle in radians)
31 |
32 | frontFriction : coefficient of friction on the front wall
33 | (tangent of the friction angle in radians)
34 |
35 | backFriction : coefficient of friction on the back wall
36 | (tangent of the friction angle in radians)
37 |
38 | thickness : Thickness of the friction layer.
39 |
40 | Returns
41 | -------
42 | """
43 |
44 | self.Model = Model
45 | self.thickness = thickness
46 |
47 | # Build borders
48 | globalIndices = np.arange(np.prod(Model.mesh.elementRes))
49 | globalIndices = globalIndices.reshape((Model.mesh.elementRes[::-1]))
50 |
51 | self.bottomFriction = bottomFriction
52 | self.rightFriction = rightFriction
53 | self.leftFriction = leftFriction
54 | self.topFriction = topFriction
55 | self.frontFriction = frontFriction
56 | self.backFriction = backFriction
57 |
58 | self.subMesh = Model.mesh.subMesh
59 | conditions = list()
60 |
61 | self._mask = uw.mesh.MeshVariable(mesh=self.subMesh, nodeDofCount=1)
62 | self._mask.data[:] = 0
63 |
64 | if self.rightFriction:
65 | self._right_mask = uw.mesh.MeshVariable(mesh=self.subMesh, nodeDofCount=1)
66 | self._right_mask.data[:] = 0
67 |
68 | if Model.mesh.dim < 3:
69 | right = globalIndices[:, -thickness:].ravel()
70 | else:
71 | right = globalIndices[:, :, -thickness:].ravel()
72 |
73 | intersect = np.intersect1d(self.subMesh.data_nodegId.ravel(), right)
74 | mask = np.in1d(self.subMesh.data_nodegId.ravel(), intersect)
75 | self._right_mask.data[mask, 0] = 1
76 | self._mask.data[mask, 0] = 1
77 | conditions.append((self._right_mask > 0., self.rightFriction))
78 |
79 | if self.leftFriction:
80 | self._left_mask = uw.mesh.MeshVariable(mesh=self.subMesh, nodeDofCount=1)
81 | self._left_mask.data[:] = 0
82 |
83 | if Model.mesh.dim < 3:
84 | left = globalIndices[:, :thickness].ravel()
85 | else:
86 | left = globalIndices[:, :, :thickness].ravel()
87 |
88 | intersect = np.intersect1d(self.subMesh.data_nodegId.ravel(), left)
89 | mask = np.in1d(self.subMesh.data_nodegId.ravel(), intersect)
90 | self._left_mask.data[mask, 0] = 1
91 | self._mask.data[mask, 0] = 1
92 | conditions.append((self._left_mask > 0., self.leftFriction))
93 |
94 | if self.frontFriction:
95 | self._front_mask = uw.mesh.MeshVariable(mesh=self.subMesh, nodeDofCount=1)
96 | self._front_mask.data[:] = 0
97 |
98 | if Model.mesh.dim > 2:
99 | front = globalIndices[:, :thickness, :].ravel()
100 | else:
101 | raise ValueError("Mesh is 2D")
102 |
103 | intersect = np.intersect1d(self.subMesh.data_nodegId.ravel(), front)
104 | mask = np.in1d(self.subMesh.data_nodegId.ravel(), intersect)
105 | self._front_mask.data[mask, 0] = 1
106 | self._mask.data[mask, 0] = 1
107 | conditions.append((self._front_mask > 0., self.frontFriction))
108 |
109 | if self.backFriction:
110 | self._back_mask = uw.mesh.MeshVariable(mesh=self.subMesh, nodeDofCount=1)
111 | self._back_mask.data[:] = 0
112 |
113 | if Model.mesh.dim > 2:
114 | back = globalIndices[:, -thickness:, :].ravel()
115 | else:
116 | raise ValueError("Mesh is 2D")
117 |
118 | intersect = np.intersect1d(self.subMesh.data_nodegId.ravel(), back)
119 | mask = np.in1d(self.subMesh.data_nodegId.ravel(), intersect)
120 | self._back_mask.data[mask, 0] = 1
121 | self._mask.data[mask, 0] = 1
122 | conditions.append((self._back_mask > 0., self.backFriction))
123 |
124 | if self.bottomFriction:
125 | self._bottom_mask = uw.mesh.MeshVariable(mesh=self.subMesh, nodeDofCount=1)
126 | self._bottom_mask.data[:] = 0
127 |
128 | bottom = globalIndices[:thickness].ravel()
129 | # Take the intersection between the globalID and the boundaries where
130 | # friction is to be applied
131 | intersect = np.intersect1d(self.subMesh.data_nodegId.ravel(), bottom)
132 | # Create a mask to highlight those elements in the local domain
133 | mask = np.in1d(self.subMesh.data_nodegId.ravel(), intersect)
134 | self._bottom_mask.data[mask, 0] = 1
135 | self._mask.data[mask, 0] = 1
136 | conditions.append((self._bottom_mask > 0., self.bottomFriction))
137 |
138 | if self.topFriction:
139 | self._top_mask = uw.mesh.MeshVariable(mesh=self.subMesh, nodeDofCount=1)
140 | self._top_mask.data[:] = 0
141 |
142 | top = globalIndices[-thickness:].ravel()
143 | intersect = np.intersect1d(self.subMesh.data_nodegId.ravel(), top)
144 | mask = np.in1d(self.subMesh.data_nodegId.ravel(), intersect)
145 | self._top_mask.data[mask, 0] = 1
146 | self._mask.data[mask, 0] = 1
147 | conditions.append((self._top_mask > 0., self.topFriction))
148 |
149 | conditions.append((True, -1.0))
150 | self.friction = fn.branching.conditional(conditions)
151 |
--------------------------------------------------------------------------------
/UWGeodynamics/_melt.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 | from UWGeodynamics import non_dimensionalise as nd
3 | from UWGeodynamics import UnitRegistry as u
4 | from UWGeodynamics import dimensionalise
5 | import json
6 | from copy import copy
7 |
8 |
9 | class _Polynom(object):
10 |
11 | def __init__(self, A1, A2=0., A3=0., A4=0.):
12 |
13 | self.A1 = A1
14 | self.A2 = A2
15 | self.A3 = A3
16 | self.A4 = A4
17 |
18 | def temperature(self, pressure):
19 | T = nd(self.A1)
20 | T += nd(self.A2) * pressure
21 | T += nd(self.A3) * pressure**2
22 | T += nd(self.A4) * pressure**3
23 | return T
24 |
25 | def plot(self, pressure):
26 | import pylab as plt
27 | temperature = dimensionalise(self.temperature(pressure), u.kelvin)
28 | pressure = dimensionalise(pressure, u.pascal)
29 | plt.plot(temperature, pressure)
30 | plt.gca().invert_yaxis()
31 | plt.show()
32 |
33 |
34 | class Solidus(_Polynom):
35 | """ This class defines a solidus using the
36 | form suggested by Hirshmann, 2000"""
37 |
38 | def __init__(self, A1, A2=0., A3=0., A4=0.):
39 | super(Solidus, self).__init__(A1, A2, A3, A4)
40 |
41 |
42 | class Liquidus(_Polynom):
43 | """ This class defines a liquidus using the
44 | form suggested by Hirshmann, 2000"""
45 |
46 | def __init__(self, A1, A2=0., A3=0., A4=0.):
47 | super(Liquidus, self).__init__(A1, A2, A3, A4)
48 |
49 |
50 | class SolidusRegistry(object):
51 | """SolidusRegistry Class"""
52 | def __init__(self, filename=None):
53 | """Create a regustry of Solidus polynomials
54 |
55 | Parameters
56 | ----------
57 |
58 | filename : Name of the json file database
59 |
60 | Returns
61 | -------
62 | """
63 |
64 | if not filename:
65 | import pkg_resources
66 | filename = pkg_resources.resource_filename(
67 | __name__, "ressources/Solidus.json")
68 |
69 | with open(filename, "r") as infile:
70 | _solidii = json.load(infile)
71 |
72 | for key in _solidii.keys():
73 | coefficients = _solidii[key]["coefficients"]
74 | for key2 in coefficients.keys():
75 | value = coefficients[key2]["value"]
76 | units = coefficients[key2]["units"]
77 | if units != "None":
78 | coefficients[key2] = u.Quantity(value, units)
79 | else:
80 | coefficients[key2] = value
81 |
82 | self._dir = {}
83 | for key in _solidii.keys():
84 | name = key.replace(" ", "_").replace(",", "").replace(".", "")
85 | name = name.replace(")", "").replace("(", "")
86 | self._dir[name] = Solidus(**_solidii[key]["coefficients"])
87 |
88 | def __dir__(self):
89 | # Make all the rheology available through autocompletion
90 | return list(self._dir.keys())
91 |
92 | def __getattr__(self, item):
93 | # Make sure to return a new instance of ViscousCreep
94 | return copy(self._dir[item])
95 |
96 |
97 | class LiquidusRegistry(object):
98 | """LiquidusRegistry class"""
99 | def __init__(self, filename=None):
100 | """Create a regustry of Liquidus polynomials
101 |
102 | Parameters
103 | ----------
104 |
105 | filename : Name of the json file database
106 |
107 | Returns
108 | -------
109 | """
110 |
111 | if not filename:
112 | import pkg_resources
113 | filename = pkg_resources.resource_filename(
114 | __name__, "ressources/Liquidus.json")
115 |
116 | with open(filename, "r") as infile:
117 | _liquidii = json.load(infile)
118 |
119 | for key in _liquidii.keys():
120 | coefficients = _liquidii[key]["coefficients"]
121 | for key2 in coefficients.keys():
122 | value = coefficients[key2]["value"]
123 | units = coefficients[key2]["units"]
124 | if units != "None":
125 | coefficients[key2] = u.Quantity(value, units)
126 | else:
127 | coefficients[key2] = value
128 |
129 | self._dir = {}
130 | for key in _liquidii.keys():
131 | name = key.replace(" ", "_").replace(",", "").replace(".", "")
132 | name = name.replace(")", "").replace("(", "")
133 | self._dir[name] = Liquidus(**_liquidii[key]["coefficients"])
134 |
135 | def __dir__(self):
136 | # Make all the rheology available through autocompletion
137 | return list(self._dir.keys())
138 |
139 | def __getattr__(self, item):
140 | # Make sure to return a new instance of ViscousCreep
141 | return copy(self._dir[item])
142 |
--------------------------------------------------------------------------------
/UWGeodynamics/_mesh_advector.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 | from copy import copy
3 | import underworld as uw
4 | import numpy as np
5 | import sys
6 | from mpi4py import MPI as _MPI
7 |
8 | comm = _MPI.COMM_WORLD
9 | size = comm.Get_size()
10 | rank = comm.Get_rank()
11 |
12 |
13 | class Mesh_advector(object):
14 | """Mesh_advector class"""
15 |
16 | def __init__(self, Model, axis):
17 |
18 | self._mesh2nd = copy(Model.mesh)
19 | self.Model = Model
20 | self.axis = axis
21 |
22 | def advect_mesh(self, dt):
23 |
24 | axis = self.axis
25 |
26 | if axis != 0:
27 | raise ValueError("Axis not supported yet")
28 |
29 | # Get minimum and maximum coordinates for the current mesh
30 | minX, maxX = self._get_minmax_coordinates_mesh(axis)
31 |
32 | minvxLeftWall, maxvxLeftWall = self._get_minmax_velocity_wall(self.Model.left_wall, axis)
33 | minvxRightWall, maxvxRightWall = self._get_minmax_velocity_wall(self.Model.right_wall, axis)
34 |
35 | if np.abs(maxvxRightWall) > np.abs(minvxRightWall):
36 | vxRight = maxvxRightWall
37 | else:
38 | vxRight = minvxRightWall
39 |
40 | if (np.abs(maxvxLeftWall) > np.abs(minvxLeftWall)):
41 | vxLeft = maxvxLeftWall
42 | else:
43 | vxLeft = minvxLeftWall
44 |
45 | minX += vxLeft * dt
46 | maxX += vxRight * dt
47 |
48 | if self.Model.mesh.dim <3:
49 | newValues = np.linspace(minX, maxX, self.Model.mesh.elementRes[axis]+1)
50 | newValues = np.repeat(newValues[np.newaxis,:], self.Model.mesh.elementRes[1] + 1, axis)
51 | else:
52 | newValues = np.linspace(minX, maxX, self.Model.mesh.elementRes[axis]+1)
53 | newValues = np.repeat(newValues[np.newaxis, :], self.Model.mesh.elementRes[1] + 1, axis)
54 | newValues = np.repeat(newValues[np.newaxis, :, :], self.Model.mesh.elementRes[2] + 1, axis)
55 |
56 | with self._mesh2nd.deform_mesh():
57 | values = newValues.flatten()
58 | self._mesh2nd.data[:, axis] = values[self._mesh2nd.data_nodegId.ravel()]
59 |
60 | comm.Barrier()
61 |
62 | with self.Model.mesh.deform_mesh():
63 | self.Model.mesh.data[:, axis] = self._mesh2nd.data[:, axis]
64 |
65 | self.Model.velocityField.data[...] = np.copy(self.Model.velocityField.evaluate(self.Model.mesh))
66 | self.Model.pressureField.data[...] = np.copy(self.Model.pressureField.evaluate(self.Model.mesh.subMesh))
67 |
68 | if self.Model.right_wall.data.size > 0:
69 | self.Model.velocityField.data[self.Model.right_wall.data, axis] = vxRight
70 |
71 | if self.Model.left_wall.data.size > 0:
72 | self.Model.velocityField.data[self.Model.left_wall.data, axis] = vxLeft
73 |
74 | def _get_minmax_velocity_wall(self, wall, axis=0):
75 | """ Return the minimum and maximum velocity component on the wall
76 |
77 | parameters:
78 | -----------
79 | wall: (indexSet)
80 | The wall.
81 | axis:
82 | axis (velocity component).
83 | """
84 |
85 | # Initialise value to max and min sys values
86 | maxV = np.ones((1)) * sys.float_info.min
87 | minV = np.ones((1)) * sys.float_info.max
88 |
89 | # if local domain has wall, get velocities
90 | if wall.data.size > 0:
91 | velocities = self.Model.velocityField.data[wall.data, axis]
92 | # get local min and max
93 | maxV[0] = velocities.max()
94 | minV[0] = velocities.min()
95 |
96 | # reduce operation
97 | comm.Barrier()
98 | comm.Allreduce(_MPI.IN_PLACE, maxV, op=_MPI.MAX)
99 | comm.Allreduce(_MPI.IN_PLACE, minV, op=_MPI.MIN)
100 | comm.Barrier()
101 |
102 | return minV, maxV
103 |
104 | def _get_minmax_coordinates_mesh(self, axis=0):
105 | """ Return the minimum and maximum coordinates along axis
106 |
107 | parameter:
108 | ----------
109 | axis:
110 | axis
111 |
112 | returns:
113 | -------
114 | tuple: minV, maxV
115 |
116 | """
117 | maxVal = np.zeros((1))
118 | minVal = np.zeros((1))
119 | maxVal[0] = self.Model.mesh.data[:, axis].max()
120 | minVal[0] = self.Model.mesh.data[:, axis].min()
121 |
122 | comm.Barrier()
123 | comm.Allreduce(_MPI.IN_PLACE, maxVal, op=_MPI.MAX)
124 | comm.Allreduce(_MPI.IN_PLACE, minVal, op=_MPI.MIN)
125 | comm.Barrier()
126 |
127 | return minVal, maxVal
128 |
129 |
130 |
--------------------------------------------------------------------------------
/UWGeodynamics/_net/__init__.py:
--------------------------------------------------------------------------------
1 | ##~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~##
2 | ## ##
3 | ## This file forms part of the Underworld geophysics modelling application. ##
4 | ## ##
5 | ## For full license and copyright information, please refer to the LICENSE.md file ##
6 | ## located at the project root, or contact the authors. ##
7 | ## ##
8 | ##~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~##
9 | """
10 | This module implements some basic functionality for posting usage metrics
11 | to google analytics.
12 | """
13 |
14 | from __future__ import print_function, absolute_import
15 | import json,urllib
16 | try:
17 | import http.client
18 | except ImportError as e:
19 | import httplib
20 | import urllib
21 | import uuid
22 | import underworld as uw
23 | from mpi4py import MPI as _MPI
24 |
25 | comm = _MPI.COMM_WORLD
26 | rank = comm.rank
27 | size = comm.size
28 |
29 | GA_TRACKING_ID = "UA-115593169-1"
30 | GA_CLIENT_ID = uw._id
31 |
32 | def PostGAEvent( category, action, label=None, value=None ):
33 | """
34 | Posts an Event Tracking message to Google Analytics.
35 |
36 | Current Underworld2 only dispatches a GA event when the underworld module
37 | is imported. This is effected by the calling of this function from
38 | underworld/__init__.py.
39 |
40 | Google Analytics uses the client id (GA_CLIENT_ID) to determine unique users. In
41 | Underworld, we generate a random string for this id and record it in _uwid.py (the
42 | value is available via the uw._id attribute). If the file (_uwid.py) exists, it
43 | is not recreated, so generally it will only be created the first time you build
44 | underworld. As this is a 'per build' identifier, it means that all users of a
45 | particular docker image will be identified as the same GA user. Likewise, all
46 | users of a particular HPC Underworld module will also be identified as the same
47 | GA user. Note that users are able to set the UW_USER_ID environment variable
48 | which overrides the randomly generated string, though this is probably of limited
49 | use.
50 |
51 | Regarding HPC usage, it seems that the compute nodes on most machines are closed
52 | to external network access, and hence GA analytics will not be dispatched
53 | successfully. Unfortunately this means that most high proc count simulations
54 | will not be captured in GA data.
55 |
56 | GA also reports on number of 'sessions'. The single session in GA is considered
57 | to be usage where concurrent events occur within 30 minutes of each other. So if
58 | you `import underworld` 5 times every 29 minutes, it will count as a single session.
59 | However if you `import underworld` 5 times every 31 minutes it will count as 5
60 | sessions.
61 |
62 | Full GA parameter reference may be found here:
63 | https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#ev
64 |
65 | Note, this function will return quietly on any errors.
66 |
67 | Parameters
68 | ----------
69 | category: str
70 | Textual name for event category.
71 | action: str
72 | Textual name for event action.
73 | label: str
74 | Optional label for event.
75 | value: non-negative integer
76 | Optional value for event.
77 |
78 |
79 | Add the following test here to ensure we're catching out when we're
80 | running from doctests to avoid dispatching metrics.
81 | >>> print('Running in doctest? {}'.format(uw._in_doctest()))
82 | Running in doctest? True
83 |
84 |
85 | """
86 | try:
87 | connection = http.client.HTTPSConnection('www.google-analytics.com')
88 | form_fields = {
89 | "v" : "1", # Version.
90 | "aip": "1", # Enable IP anonymizing.
91 | "tid": GA_TRACKING_ID, # Tracking ID / Web property / Property ID.
92 | "ds" : "app", # Data Source.
93 | "cid": GA_CLIENT_ID, # Anonymous Client ID.
94 | "t" : "event", # Event hit type.
95 | "an" : "UWGeodynamics", # Application name.
96 | "av" : uw.__version__, # Application version.
97 | "ec" : category, # Event Category. Required.
98 | "ea" : action, # Event Action. Required.
99 | "el" : label, # Event label.
100 | "ev" : value, # Event value.
101 | "cm2": size, # Number of processes used. Stored into custom metric 2.
102 | "cd5": str(size),# Number of processes used. Stored into custom dim 2. Not sure if necessary.
103 | }
104 | import os
105 | # add user id if set
106 | if "UW_USER_ID" in os.environ:
107 | form_fields["uid"] = os.environ["UW_USER_ID"]
108 | form_fields["cd4"] = os.environ["UW_USER_ID"]
109 |
110 | if "UW_MACHINE" in os.environ:
111 | form_fields["cd6"] = os.environ["UW_MACHINE"]
112 |
113 | params = urllib.urlencode(form_fields)
114 | connection.connect()
115 | connection.request('POST', '/collect?%s' % params, '', { "Content-Type": "application/x-www-form-urlencoded" })
116 | except:
117 | pass
118 |
119 |
--------------------------------------------------------------------------------
/UWGeodynamics/_rcParams.py:
--------------------------------------------------------------------------------
1 | # Configuration file
2 | from __future__ import print_function, absolute_import
3 | from UWGeodynamics import u
4 | from ._validate import *
5 |
6 |
7 | rcParams = {
8 |
9 | "CFL": [0.5, validate_float],
10 |
11 | "rebuild.solver": [False, validate_bool],
12 | "initial.nonlinear.tolerance": [1e-2, validate_float],
13 | "nonlinear.tolerance": [1e-2, validate_float],
14 | "initial.nonlinear.min.iterations": [2, validate_int],
15 | "initial.nonlinear.max.iterations": [500, validate_int],
16 | "nonlinear.min.iterations": [2, validate_int],
17 | "nonlinear.max.iterations": [500, validate_int],
18 |
19 | "default.outputs" : [["temperature",
20 | "pressureField",
21 | "strainRateField",
22 | "velocityField",
23 | "projStressField",
24 | "projTimeField",
25 | "projMaterialField",
26 | "projViscosityField",
27 | "projStressField",
28 | "projMeltField",
29 | "projPlasticStrain",
30 | "projDensityField"], validate_stringlist],
31 |
32 | "swarm.particles.per.cell.2D": [40, validate_int],
33 | "swarm.particles.per.cell.3D": [120, validate_int],
34 |
35 | "popcontrol.aggressive" : [True, validate_bool],
36 | "popcontrol.split.threshold" : [0.15, validate_float],
37 | "popcontrol.max.splits" : [10, validate_int],
38 | "popcontrol.particles.per.cell.2D" : [40, validate_int],
39 | "popcontrol.particles.per.cell.3D" : [120, validate_int],
40 |
41 | "time.SIunits": [u.years, validate_quantity],
42 | "timeField.SIunits": [u.years, validate_quantity],
43 | "viscosityField.SIunits" : [u.pascal * u.second, validate_quantity],
44 | "densityField.SIunits" : [u.kilogram / u.metre**3, validate_quantity],
45 | "velocityField.SIunits" : [u.centimeter / u.year, validate_quantity],
46 | "temperature.SIunits" : [u.degK, validate_quantity],
47 | "pressureField.SIunits" : [u.pascal , validate_quantity],
48 | "projStressTensor.SIunits" : [u.pascal , validate_quantity],
49 | "projStressField.SIunits" : [u.pascal , validate_quantity],
50 | "strainRateField.SIunits" : [1.0 / u.second, validate_quantity],
51 | "projViscosityField.SIunits" : [u.pascal * u.second, validate_quantity],
52 | "projDensityField.SIunits" : [u.kilogram / u.metre**3, validate_quantity],
53 | "projTimeField.SIunits" : [u.megayears, validate_quantity],
54 |
55 | "shear.heating": [False, validate_bool],
56 | "surface.pressure.normalization": [True, validate_bool],
57 | "pressure.smoothing": [True, validate_bool],
58 | "advection.diffusion.method": ["SUPG", validate_string],
59 | "rheologies.combine.method": ["Minimum", validate_string],
60 | "averaging.method": ["arithmetic", validate_averaging]
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/UWGeodynamics/_remeshing.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from UWGeodynamics import non_dimensionalise as nd
3 | from underworld.mesh import MeshVariable
4 | from scipy.interpolate import interp1d
5 | import copy
6 |
7 |
8 | class ReMesher(object):
9 |
10 | def __init__(self, Model, x, y, z, reset=False, adaptive=False):
11 |
12 | self.mesh = Model.mesh
13 | self.initial_mesh = copy.copy(self.mesh)
14 | self.x = x
15 | self.y = y
16 | self.z = z
17 | self.reset = reset
18 |
19 | if adaptive:
20 | Model.post_solve_functions["Remesher"] = self.remesh
21 |
22 | def reset_mesh(self):
23 | with self.mesh.deform_mesh():
24 | self.mesh.data[...] = self.initial_mesh.data[...]
25 |
26 | def remesh(self):
27 |
28 | if self.reset:
29 | self.reset_mesh()
30 |
31 | if self.mesh.dim > 2:
32 | nx, ny, nz = self.mesh.elementRes
33 | else:
34 | nx, ny = self.mesh.elementRes
35 |
36 | def new_points(intervals, elements):
37 | pts = []
38 | for idx in range(len(intervals) - 1):
39 | pts.append(np.linspace(intervals[idx], intervals[idx + 1], elements[idx] + 1))
40 | pts = np.unique(np.hstack(pts))
41 | pts.sort()
42 | return pts
43 |
44 | def check_vals(intervals, elements, axis):
45 | if ((intervals[0] != self.mesh.minCoord[axis]) or
46 | (intervals[-1] != self.mesh.maxCoord[axis])):
47 | raise ValueError("""Intervals do not match mesh extent""")
48 |
49 | if np.sum(np.array(elements)) != self.mesh.elementRes[axis]:
50 | raise ValueError("""Total nb of elements do not match the nb of elements in the mesh""")
51 |
52 | def new_points_from_field(field, axis):
53 | nx, ny = self.mesh.elementRes
54 | A = field.data.reshape((nx + 1, ny + 1))
55 | B = A.max(axis=axis)
56 | C = B / B.max()
57 | D = C.cumsum()
58 | E = D - D[0]
59 | E = E / E.max()
60 | if axis == 1:
61 | coords = self.mesh.data[:, axis].reshape((nx + 1, ny + 1))[:, -1]
62 | if axis == 0:
63 | coords = self.mesh.data[:, axis].reshape((nx + 1, ny + 1))[0, :]
64 | ys = np.linspace(0., 1.0, self.mesh.elementRes[axis] + 1)
65 | func = interp1d(E, coords, fill_value=(coords[0], coords[-1]),
66 | bounds_error=False)
67 | vals = func(ys)
68 | return vals
69 |
70 | new_valsx = None
71 | new_valsy = None
72 | new_valsz = None
73 |
74 | if self.x:
75 |
76 | if isinstance(self.x, tuple):
77 | intervals, elements = self.x
78 | intervals = [nd(val) for val in intervals]
79 | elements = [nd(val) for val in elements]
80 | check_vals(intervals, elements, 0)
81 | pts = new_points(intervals, elements)
82 | if isinstance(self.x, MeshVariable):
83 | pts = new_points_from_field(self.x, 0)
84 |
85 | if self.mesh.dim > 2:
86 | new_valsx = np.tile(pts.flatten(), nz + 1)
87 | new_valsx = np.tile(new_valsx.flatten(), ny + 1)
88 | else:
89 | new_valsx = np.tile(pts.flatten(), ny + 1)
90 |
91 | if self.y:
92 |
93 | if isinstance(self.y, tuple):
94 | intervals, elements = self.y
95 | intervals = [nd(val) for val in intervals]
96 | elements = [nd(val) for val in elements]
97 | check_vals(intervals, elements, 1)
98 | pts = new_points(intervals, elements)
99 | if isinstance(self.y, MeshVariable):
100 | pts = new_points_from_field(self.y, 1)
101 |
102 | if self.mesh.dim > 2:
103 | new_valsy = np.repeat(pts.flatten(), nz + 1)
104 | new_valsy = np.tile(new_valsy.flatten(), nx + 1)
105 | else:
106 | new_valsy = np.repeat(pts.flatten(), nx + 1)
107 |
108 | if self.z:
109 |
110 | if isinstance(self.z, tuple):
111 | intervals, elements = self.z
112 | intervals = [nd(val) for val in intervals]
113 | elements = [nd(val) for val in elements]
114 | check_vals(intervals, elements, -1)
115 | pts = new_points(intervals, elements)
116 | if isinstance(self.z, MeshVariable):
117 | raise ValueError("""This functionality has not been implemented
118 | for 3D meshes""")
119 |
120 | new_valsz = np.repeat(pts, nx + 1)
121 | new_valsz = np.repeat(new_valsz, ny + 1)
122 |
123 | with self.mesh.deform_mesh():
124 | if new_valsx is not None:
125 | self.mesh.data[:, 0] = new_valsx[self.mesh.data_nodegId.flatten()]
126 | if new_valsy is not None:
127 | self.mesh.data[:, 1] = new_valsy[self.mesh.data_nodegId.flatten()]
128 | if new_valsz is not None:
129 | self.mesh.data[:, -1] = new_valsz[self.mesh.data_nodegId.flatten()]
130 |
131 | return self.mesh
132 |
133 |
--------------------------------------------------------------------------------
/UWGeodynamics/_validate.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 | from UWGeodynamics import u
3 | from pint import UndefinedUnitError
4 | import six
5 | try:
6 | import collections.abc as abc
7 | except ImportError:
8 | # python 2
9 | import collections as abc
10 |
11 |
12 | def validate_gravity(s):
13 | return u.check('[length]')(s)
14 |
15 |
16 | def _listify_validator(scalar_validator, allow_stringlist=False):
17 | def f(s):
18 | if isinstance(s, six.string_types):
19 | try:
20 | return [scalar_validator(v.strip()) for v in s.split(',')
21 | if v.strip()]
22 | except Exception:
23 | if allow_stringlist:
24 | # Sometimes, a list of colors might be a single string
25 | # of single-letter colornames. So give that a shot.
26 | return [scalar_validator(v.strip()) for v in s if v.strip()]
27 | else:
28 | raise
29 | # We should allow any generic sequence type, including generators,
30 | # Numpy ndarrays, and pandas data structures. However, unordered
31 | # sequences, such as sets, should be allowed but discouraged unless the
32 | # user desires pseudorandom behavior.
33 | elif isinstance(s, abc.Iterable) and not isinstance(s, abc.Mapping):
34 | # The condition on this list comprehension will preserve the
35 | # behavior of filtering out any empty strings (behavior was
36 | # from the original validate_stringlist()), while allowing
37 | # any non-string/text scalar values such as numbers and arrays.
38 | return [scalar_validator(v) for v in s
39 | if not isinstance(v, six.string_types) or v]
40 | else:
41 | msg = "{0!r} must be of type: string or non-dictionary iterable.".format(s)
42 | raise ValueError(msg)
43 | f.__doc__ = scalar_validator.__doc__
44 | return f
45 |
46 |
47 | def validate_quantity(s):
48 | # Convert to quantity
49 | s = u.Quantity(s)
50 | if s.dimensionless:
51 | return s.magnitude
52 | return s
53 |
54 |
55 | def validate_float(s):
56 | try:
57 | return float(s)
58 | except ValueError:
59 | raise ValueError("Could not convert value to float")
60 |
61 |
62 | def validate_solver(s):
63 | if s in ["mg", "mumps", "lu", "superlu", "superludist"]:
64 | return s
65 | else:
66 | raise ValueError("Wrong solver option")
67 |
68 |
69 | def validate_int(s):
70 | try:
71 | return int(s)
72 | except ValueError:
73 | raise ValueError("Could not convert value to int")
74 |
75 |
76 | def validate_int_or_none(s):
77 | if s:
78 | return validate_int(s)
79 | if s is None:
80 | return
81 | else:
82 | raise ValueError("Must be int or None")
83 |
84 |
85 | def validate_path(s):
86 | return str(s)
87 |
88 |
89 | def validate_bool(b):
90 | """Convert b to a boolean or raise"""
91 | if isinstance(b, six.string_types):
92 | b = b.lower()
93 | if b in ('t', 'y', 'yes', 'on', 'true', '1', 1, True):
94 | return True
95 | elif b in ('f', 'n', 'no', 'off', 'false', '0', 0, False):
96 | return False
97 | else:
98 | raise ValueError('Could not convert "%s" to boolean' % b)
99 |
100 |
101 | def validate_string(s):
102 | return s
103 |
104 |
105 | def validate_any(s):
106 | return s
107 |
108 |
109 | def validate_viscosity(s):
110 | try:
111 | s = u.Quantity(s)
112 | except UndefinedUnitError:
113 | try:
114 | from UWGeodynamics import rheologies
115 | s = s.replace(" ", "_")
116 | s = s.replace(",", "")
117 | s = s.replace(".", "")
118 |
119 | if s in rheologies._dir:
120 | return rheologies._dir[s]
121 | except KeyError:
122 | raise ValueError(
123 | """Can not find {0} rheology in databases""".format(s))
124 |
125 | def validate_averaging(s):
126 | options = {"arithmetic": 1,
127 | "geometric": 0,
128 | "harmonic": -1,
129 | "maximum": 30,
130 | "minimum": -30,
131 | "root mean square": 2}
132 | if s not in options.keys():
133 | raise ValueError(
134 | """{0} is not a valid option, valid options are {1}""".format(
135 | s, options.keys()))
136 |
137 | return options[s]
138 |
139 | validate_stringlist = _listify_validator(six.text_type)
140 | validate_stringlist.__doc__ = 'return a list'
141 |
--------------------------------------------------------------------------------
/UWGeodynamics/_visugrid.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 | import underworld as uw
3 | from UWGeodynamics import non_dimensionalise as nd
4 | import numpy as np
5 | from scipy import spatial
6 |
7 |
8 | class Visugrid(object):
9 |
10 | def __init__(self, Model, elementRes, minCoord, maxCoord, velocityField):
11 |
12 | self.minCoord = minCoord
13 | self.maxCoord = maxCoord
14 | self.elementRes = elementRes
15 | self.velocityField = velocityField
16 |
17 | minCoord = tuple([nd(val) for val in self.minCoord])
18 | maxCoord = tuple([nd(val) for val in self.maxCoord])
19 |
20 | self.mesh = uw.mesh.FeMesh_Cartesian(elementType="Q1/dQ0",
21 | elementRes=self.elementRes,
22 | minCoord=minCoord,
23 | maxCoord=maxCoord)
24 |
25 | boundaryNodes = (Model.left_wall + Model.right_wall +
26 | Model.top_wall + Model.bottom_wall)
27 |
28 | self.Model = Model
29 |
30 | # Build a KDTree to handle boundaries
31 | self.boundaries = boundaryNodes.data
32 | x = Model.mesh.data[self.boundaries, 0]
33 | y = Model.mesh.data[self.boundaries, 1]
34 | coords = np.zeros((x.size, 2))
35 | coords[:, 0] = x.ravel()
36 | coords[:, 1] = y.ravel()
37 | self.tree = spatial.cKDTree(coords)
38 |
39 | def advect(self, dt):
40 |
41 | with self.mesh.deform_mesh():
42 | for index, coords in enumerate(self.mesh.data):
43 | try:
44 | self.mesh.data[index] += self.velocityField.evaluate(np.array([coords]))[0] * dt
45 | except:
46 | _, loc = self.tree.query(self.mesh.data[index])
47 | loc = self.boundaries[loc]
48 | coords = self.Model.mesh.data[loc]
49 | self.mesh.data[index] += self.velocityField.data[loc] * dt
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/UWGeodynamics/lithopress/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 | from .lithopress import Lithostatic_pressure
3 | __version__ = "0.1"
4 |
--------------------------------------------------------------------------------
/UWGeodynamics/lithopress/lithopress.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 |
3 | import underworld as uw
4 | import underworld.function as fn
5 | import numpy as np
6 | from mpi4py import MPI
7 |
8 | comm = MPI.COMM_WORLD
9 | size = comm.Get_size()
10 | rank = comm.Get_rank()
11 |
12 | supported_elem_mesh = ["Q1", "Q2"]
13 | supported_elem_subMesh = ["DQ1", "DQ0", "DPC1"]
14 |
15 |
16 | class Lithostatic_pressure(fn.Function):
17 | """Class that calculates the lithostatic pressure field based on
18 | material densities.
19 |
20 | inputs
21 |
22 | mesh: regular mesh
23 | densityFn: underworld function, shall return material densities
24 | gravity
25 |
26 | outputs:
27 |
28 | tuple: lithostatic pressure field, pressure at the bottom of the
29 | model
30 | """
31 |
32 | def __init__(self, mesh, densityFn, gravity):
33 |
34 | self.mesh = mesh
35 | self._densityFn = fn.Function.convert(densityFn)
36 | self.gravity = fn.Function.convert(gravity)
37 |
38 | self.lithostatic_field_nodes = uw.mesh.MeshVariable(self.mesh, nodeDofCount=1)
39 | self.lithostatic_field = uw.mesh.MeshVariable(self.mesh.subMesh, nodeDofCount=1)
40 | self.Cell2Nodes = uw.utils.MeshVariable_Projection(
41 | self.lithostatic_field_nodes, self.lithostatic_field, type=0)
42 | # Create Utilities
43 | self.DensityVar = uw.mesh.MeshVariable(self.mesh, nodeDofCount=1)
44 | self.projectorDensity = uw.utils.MeshVariable_Projection(self.DensityVar, self._densityFn, type=0 )
45 |
46 | if not self.mesh.elementType.upper() in supported_elem_mesh:
47 | raise ValueError("Unsupported element: {0}".format(self.mesh.elementType))
48 |
49 | if not self.mesh.subMesh.elementType.upper() in supported_elem_subMesh:
50 | raise ValueError("Unsupported element: {0}".format(self.mesh.subMesh.elementType))
51 |
52 | super(Lithostatic_pressure, self).__init__(
53 | argument_fns=[self._densityFn,
54 | self.gravity])
55 | # 2D case
56 | if self.mesh.dim == 2:
57 | self._fn = self._lithoPressure2D()
58 | # 3D case
59 | if self.mesh.dim == 3:
60 | self._fn = self._lithoPressure3D()
61 |
62 | self._fncself = self._fn._fncself
63 |
64 | def _lithoPressure2D(self):
65 |
66 | self.projectorDensity.solve()
67 |
68 | # Get Dimension of the global domain
69 | ncol, nrow = self.mesh.elementRes
70 | if self.mesh.elementType == "Q2":
71 | fact = 2
72 | elif self.mesh.elementType == "Q1":
73 | fact = 1
74 |
75 | ncol *= fact
76 | nrow *= fact
77 |
78 | # Create some work arrays.
79 | local_y = np.zeros((nrow + 1, ncol + 1))
80 | global_y = np.zeros((nrow + 1, ncol + 1))
81 | local_density = np.zeros((nrow + 1, ncol + 1))
82 | global_density = np.zeros((nrow + 1, ncol + 1))
83 | local_pressure = np.zeros((nrow, ncol))
84 |
85 | # Now we need to get the dimension as well as
86 | # the location of the local domain
87 | # in the global domain.
88 |
89 | # Get the global ids, note that we must get rid of the shadow nodes
90 | all_nodes = self.mesh.subMesh.data_nodegId # local + shadow
91 | node_gids = self.mesh.data_nodegId[:self.mesh.nodesLocal]
92 |
93 | # Get an I,J representation of the node coordinates
94 | Jpositions = (node_gids.astype("float") / (ncol + 1)).astype("int")
95 | Ipositions = node_gids - Jpositions * (ncol + 1)
96 |
97 | # Get local domain data
98 | local_y[Jpositions, Ipositions] = self.mesh.data[:self.mesh.nodesLocal, 1]
99 | local_density[Jpositions, Ipositions] = self.DensityVar.data[:self.mesh.nodesLocal, 0]
100 |
101 | comm.Allreduce(local_y, global_y)
102 | comm.Allreduce(local_density, global_density)
103 |
104 | # Remember that the nodes coordinates start from the bottom left so that the first
105 | # row in the numpy array is actually the bottom of the mesh.
106 | # Top Left - Bottom Left
107 | dyleft = np.abs(global_y[1:, :-1] - global_y[:-1, :-1])
108 | # Top Right - Bottom Right
109 | dyright = np.abs(global_y[1:, 1:] - global_y[:-1, 1:])
110 | dy = (dyleft + dyright) / 2.
111 |
112 | # Calculate pressure from the top half of the element.
113 | # (Takes the average density of the 2 top nodes)
114 | EpressureTop = self.gravity.value * dy / 2.0 * (global_density[1:, :-1] + global_density[1:, 1:]) / 2.0
115 | # Calculate pressure from the bottom half of the element.
116 | # (Takes the average density of the 2 bottom nodes)
117 | EpressureBot = self.gravity.value * dy / 2.0 * (global_density[:-1, :-1] + global_density[:-1, 1:]) / 2.0
118 |
119 | # Add pressure from element above except at the top.
120 | pressure = np.copy(EpressureTop)
121 | pressure[:-1, :] += EpressureBot[1:, :]
122 | residual = EpressureBot[0, :]
123 |
124 | # Flip the array upside down, do a cumul sum, flip it back.
125 | Tpressure = np.cumsum(pressure[::-1, :], axis=0)[::-1, :]
126 | bottom = Tpressure[0, :] + residual
127 |
128 | local_pressure = Tpressure.flatten()[all_nodes]
129 |
130 | self.lithostatic_field.data[:, 0] = local_pressure
131 | self.lithostatic_field.syncronise()
132 |
133 | self.Cell2Nodes.solve()
134 |
135 | return self.lithostatic_field_nodes
136 |
137 | def _lithoPressure3D(self):
138 |
139 | self.projectorDensity.solve()
140 |
141 | # Get Dimension of the global domain
142 | nx, ny, nz = self.mesh.elementRes
143 | if self.mesh.elementType == "Q2":
144 | fact = 2
145 | elif self.mesh.elementType == "Q1":
146 | fact = 1
147 |
148 | nx *= fact
149 | ny *= fact
150 | nz *= fact
151 |
152 | # Create some work arrays.
153 | local_z = np.zeros((nz + 1, ny + 1, nx + 1))
154 | global_z = np.zeros((nz + 1, ny + 1, nx + 1))
155 | local_density = np.zeros((nz + 1, ny + 1, nx + 1))
156 | global_density = np.zeros((nz + 1, ny + 1, nx + 1))
157 | local_pressure = np.zeros((nz, ny, nx))
158 |
159 | # Get the global ids, note that we must get rid of the shadow nodes
160 | all_nodes = self.mesh.subMesh.data_nodegId # local + shadow
161 | node_gids = self.mesh.data_nodegId[:self.mesh.nodesLocal]
162 |
163 | GlobalIndices3d = np.arange(self.mesh.nodesGlobal).reshape(nz + 1, ny + 1, nx + 1)
164 | # Get an I,J representation of the node coordinates
165 | Ipositions = np.array([int(np.where(GlobalIndices3d == i)[2]) for i in node_gids])
166 | Jpositions = np.array([int(np.where(GlobalIndices3d == i)[1]) for i in node_gids])
167 | Kpositions = np.array([int(np.where(GlobalIndices3d == i)[0]) for i in node_gids])
168 |
169 | # Get local domain data
170 | local_z[Kpositions, Jpositions, Ipositions] = self.mesh.data[:self.mesh.nodesLocal, 2]
171 | local_density[Kpositions, Jpositions, Ipositions] = self.DensityVar.data[:self.mesh.nodesLocal].flatten()
172 |
173 | comm.Allreduce(local_z, global_z)
174 | comm.Allreduce(local_density, global_density)
175 |
176 | # Remember that the nodes coordinates start from the bottom left so that the first
177 | # row in the numpy array is actually the bottom of the mesh.
178 | # Top Left - Bottom Left
179 | top1 = global_z[1:, :-1, :-1]
180 | top2 = global_z[1:, 1:, :-1]
181 | top3 = global_z[1:, 1:, 1:]
182 | top4 = global_z[1:, :-1, 1:]
183 |
184 | top = (top1 + top2 + top3 + top4) / 4.0
185 |
186 | bot1 = global_z[:-1, :-1, :-1]
187 | bot2 = global_z[:-1, 1:, :-1]
188 | bot3 = global_z[:-1, 1:, 1:]
189 | bot4 = global_z[:-1, :-1, 1:]
190 |
191 | bot = (bot1 + bot2 + bot3 + bot4) / 4.0
192 |
193 | dy = top - bot
194 |
195 | # Calculate pressure from the top half of the element.
196 | # (Takes the average density of the 2 top nodes)
197 | EpressureTop = (self.gravity.value * dy / 2.0 *
198 | (global_density[1:, :-1, :-1] +
199 | global_density[1:, 1:, :-1] +
200 | global_density[1:, 1:, 1:] +
201 | global_density[1:, :-1, 1:]) / 4.0)
202 | # Calculate pressure from the bottom half of the element.
203 | # (Takes the average density of the 2 bottom nodes)
204 | EpressureBot = (self.gravity.value * dy / 2.0 *
205 | (global_density[:-1, :-1, :-1] +
206 | global_density[:-1, 1:, :-1] +
207 | global_density[:-1, 1:, 1:] +
208 | global_density[:-1, :-1, 1:]) / 4.0)
209 |
210 | # Add pressure from element above except at the top.
211 | pressure = np.copy(EpressureTop)
212 | pressure[:-1, :, :] += EpressureBot[1:, :, :]
213 | residual = EpressureBot[0, :, :]
214 |
215 | # Flip the array upside down, do a cumul sum, flip it back.
216 | Tpressure = np.cumsum(pressure[::-1, :, :], axis=0)[::-1, :, :]
217 | bottom = Tpressure[0, :, :] + residual
218 |
219 | local_pressure = Tpressure.flatten()[all_nodes]
220 |
221 | self.lithostatic_field.data[:, 0] = local_pressure
222 | self.lithostatic_field.syncronise()
223 |
224 | self.Cell2Nodes.solve()
225 |
226 | return self.lithostatic_field_nodes
227 |
--------------------------------------------------------------------------------
/UWGeodynamics/postprocessing/__init__.py:
--------------------------------------------------------------------------------
1 | from ._tracers import *
2 | from ._logFile import *
3 |
--------------------------------------------------------------------------------
/UWGeodynamics/postprocessing/_logFile.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class NonLinearBlock(object):
4 | def __init__(self, string):
5 | self.string = string
6 | self.data = dict()
7 | self.data["Pressure Solve times"] = self.get_vals(["Pressure Solve"], 3)
8 | self.data["Final V Solve times"] = self.get_vals(["Final V Solve"], 4)
9 | self.data["Total BSSCR times"] = self.get_vals(["Total BSSCR Linear solve time"], 5)
10 | self.data["Residuals"] = self.get_vals(["converged", "Residual", "Tolerance"], 5, func=str)
11 | self.data["Residuals"] = [float(val[:-1]) for val in self.data["Residuals"]]
12 | self.data["Iterations"] = self.get_vals(["Non linear solver - iteration"], -1, func=int)
13 | self.data["Solution Time"] = self.get_vals(["solution time"], 5)
14 |
15 | def get_vals(self, FINDSTRING, pos, func=float):
16 | f = self.string.splitlines()
17 | vals = [func(line.split()[pos]) for line in f if all([F.lower() in line.lower() for F in FINDSTRING])]
18 | return vals
19 |
20 |
21 | class LogFile(object):
22 | def __init__(self, filename):
23 | self.filename = filename
24 | self.nonLinear_blocks = self.get_nonLinear_blocks()
25 | self.pressure_solve_times = list()
26 | for obj in self.nonLinear_blocks:
27 | self.pressure_solve_times += obj.data["Pressure Solve times"]
28 | self.finalV_solve_times = list()
29 | for obj in self.nonLinear_blocks:
30 | self.finalV_solve_times += obj.data["Final V Solve times"]
31 | self.total_BSSCR_times = list()
32 | for obj in self.nonLinear_blocks:
33 | self.total_BSSCR_times += obj.data["Total BSSCR times"]
34 | self.residuals = list()
35 | for obj in self.nonLinear_blocks:
36 | self.residuals += obj.data["Residuals"]
37 | self.iterations = list()
38 | for obj in self.nonLinear_blocks:
39 | self.iterations.append(obj.data["Iterations"][-1])
40 | self.solution_times = list()
41 | for obj in self.nonLinear_blocks:
42 | self.solution_times += obj.data["Solution Time"]
43 |
44 | def get_nonLinear_blocks(self):
45 | non_linear_blocks = list()
46 | with open(self.filename, "r") as f:
47 | block = ""
48 | inBlock = False
49 | step = 0
50 | for line in f:
51 | if "Non linear solver" in line:
52 | inBlock = True
53 | step += 1
54 | if inBlock:
55 | if "Converged" not in line:
56 | block += line
57 | else:
58 | block += line
59 | inBlock = False
60 | block = NonLinearBlock(block)
61 | non_linear_blocks.append(block)
62 | block = ""
63 | # Process last potentially non-converged block
64 | if block:
65 | block = NonLinearBlock(block)
66 | non_linear_blocks.append(block)
67 | self.nonLinear_blocks = non_linear_blocks
68 | return self.nonLinear_blocks
69 |
--------------------------------------------------------------------------------
/UWGeodynamics/postprocessing/_tracers.py:
--------------------------------------------------------------------------------
1 | import os, re, glob
2 | import h5py
3 |
4 | def find_swarm_files(folder, tracers_name):
5 | res = [f for f in os.listdir(folder) if re.search(r'^'+tracers_name+'(-\d.*.h5)', f)]
6 | res.sort()
7 | indices = [int(re.search(r'^'+tracers_name+'-(.+?)(.h5)$', f).group(1)) for f in res]
8 | return res, indices
9 |
10 | def find_tracked_fields(folder, tracers_name):
11 | """ Returns a list of field tracked by the tracers"""
12 | files = glob.glob(os.path.join(folder, tracers_name)+"*")
13 | files = [os.path.split(file)[-1][len(tracers_name):] for file in files if "h5" in file]
14 | out = []
15 | for file in files:
16 | match = re.search("^_(.+?)(-[0-9].h5)$", file)
17 | if match:
18 | out.append(match.group(1))
19 | return list(set(out))
20 |
21 | def extract_global_indices(output_folder, tracers_name, index):
22 | global_index_file = """{0}_global_index-{1}.h5""".format(tracers_name, index)
23 | with h5py.File(os.path.join(output_folder, global_index_file), "r") as h5f:
24 | global_indices = h5f["data"].value
25 | return global_indices.ravel()
26 |
27 | def extract_tracers_data(output_folder, tracers_name, csv=True):
28 | import pandas as pd
29 | swarm_files, indices = find_swarm_files(output_folder, tracers_name)
30 | if not swarm_files:
31 | raise ValueError("""Cannot find tracers {0}""".format(tracers_name))
32 |
33 | tracked_fields = find_tracked_fields(output_folder, tracers_name)
34 | global_indices = extract_global_indices(output_folder, tracers_name, 0)
35 |
36 | id_dict = {}
37 | id_ = 0
38 | for index in global_indices:
39 | id_dict[index] = id_
40 | id_ += 1
41 |
42 | default_columns = ["Coord1", "Coord2", "Coord3", "FileIndex", "TracerId"]
43 | df = pd.DataFrame(columns=default_columns + tracked_fields)
44 | for index in indices:
45 | dftempo = pd.DataFrame(columns=default_columns + tracked_fields)
46 | # Extract Coordinates
47 | file = """{0}-{1}.h5""".format(tracers_name, index)
48 | file = os.path.join(output_folder, file)
49 | with h5py.File(file, "r") as h5f:
50 | dftempo["Coord1"] = h5f["data"].value[:,0]
51 | dftempo["Coord2"] = h5f["data"].value[:,1]
52 | try:
53 | dftempo["Coord3"] = h5f["data"].value[:,2]
54 | except:
55 | dftempo["Coord3"] = None
56 | dftempo["FileIndex"] = index
57 | dftempo["Time"] = h5f.attrs["time"]
58 |
59 | for field in tracked_fields:
60 | file = """{0}_{1}-{2}.h5""".format(tracers_name, field, index)
61 | file = os.path.join(output_folder, file)
62 | with h5py.File(file, "r") as h5f:
63 | dftempo[field] = h5f["data"].value.ravel()
64 |
65 | dftempo["TracerId"] = dftempo["global_index"].map(id_dict)
66 | df = pd.concat([df, dftempo], ignore_index=True, sort=False)
67 |
68 | if csv:
69 | df.to_csv(tracers_name+".csv")
70 |
71 | return df
72 |
--------------------------------------------------------------------------------
/UWGeodynamics/ressources/Liquidus.json:
--------------------------------------------------------------------------------
1 | {
2 | "Crustal Liquidus": {
3 | "coefficients": {
4 | "A1": {
5 | "units": "kelvin",
6 | "value": 1493
7 | },
8 | "A2": {
9 | "units": "kelvin / pascal",
10 | "value": -1.2e-07
11 | },
12 | "A3": {
13 | "units": "kelvin / pascal ** 2",
14 | "value": 1.6e-16
15 | },
16 | "A4": {
17 | "units": "None",
18 | "value": 0.0
19 | }
20 | }
21 | },
22 | "Mantle Liquidus": {
23 | "coefficients": {
24 | "A1": {
25 | "units": "kelvin",
26 | "value": 2013
27 | },
28 | "A2": {
29 | "units": "kelvin / pascal",
30 | "value": 6.15e-08
31 | },
32 | "A3": {
33 | "units": "kelvin / pascal ** 2",
34 | "value": -3.12e-18
35 | },
36 | "A4": {
37 | "units": "None",
38 | "value": 0.0
39 | }
40 | }
41 | },
42 | "Mid Crustal Liquidus": {
43 | "coefficients": {
44 | "A1": {
45 | "units": "kelvin",
46 | "value": 1563
47 | },
48 | "A2": {
49 | "units": "kelvin / pascal",
50 | "value": -1.2e-07
51 | },
52 | "A3": {
53 | "units": "kelvin / pascal ** 2",
54 | "value": 1.6e-16
55 | },
56 | "A4": {
57 | "units": "None",
58 | "value": 0.0
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/UWGeodynamics/ressources/Materials.json:
--------------------------------------------------------------------------------
1 | {
2 | "Air":{
3 | "density": {
4 | "value": 1.0 ,
5 | "units": "kilogram / metre**3"},
6 | "diffusivity": {
7 | "value": 1.0e-6,
8 | "units": "metre**2 / second"},
9 | "capacity":{
10 | "value": 100.0 ,
11 | "units": "joule / kelvin / kilogram"},
12 | "radiogenicHeatProd":{
13 | "value": 0.0,
14 | "units": "milliwatts / metre**3"},
15 | "viscosity": {
16 | "value": 1e19,
17 | "units": "pascal * second"}
18 | },
19 | "Sticky Air":{
20 | "density": {
21 | "value": 1.0 ,
22 | "units": "kilogram / metre**3"},
23 | "diffusivity": {
24 | "value": 1.0e-6,
25 | "units": "metre**2 / second"},
26 | "capacity":{
27 | "value": 100.0 ,
28 | "units": "joule / kelvin / kilogram"},
29 | "radiogenicHeatProd":{
30 | "value": 0.0,
31 | "units": "milliwatts / metre**3"},
32 | "viscosity": {
33 | "value": 1e20,
34 | "units": "pascal * second"}
35 | },
36 | "Wet Quartz Upper crust":{
37 | "density": {
38 | "reference_density": {
39 | "value": 2620.0,
40 | "units": "kilogram / metre**3"},
41 | "thermalExpansivity":{
42 | "value": 3e-5,
43 | "units": "kelvin**-1"}},
44 | "diffusivity": {
45 | "value": 1.0e-6,
46 | "units": "metre**2 / second"},
47 | "capacity":{
48 | "value": 1000.0 ,
49 | "units": "joule / kelvin / kilogram"},
50 | "radiogenicHeatProd":{
51 | "value": 0.7,
52 | "units": "milliwatts / metre**3"},
53 | "viscosity": "Wet Quartz, Viscous Dislocation Creep, Gleason and Tullis, 1995",
54 | "plasticity": "Rey and Muller, 2010 (UpperCrust)"
55 | },
56 |
57 |
58 | "Mid crust":{
59 | "density": {
60 | "value": 2900.0 ,
61 | "units": "kilogram / metre**3"},
62 | "diffusivity": {
63 | "value": 1.0e-6,
64 | "units": "metre**2 / second"},
65 | "capacity":{
66 | "value": 1000.0 ,
67 | "units": "joule / kelvin / kilogram"},
68 | "radiogenicHeatProd":{
69 | "value": 0.6,
70 | "units": "milliwatts / metre**3"},
71 | "viscosity": null ,
72 | "plasticity": null
73 | },
74 |
75 | "Wet Quartz Lower crust":{
76 | "density": {
77 | "value": 2800.0 ,
78 | "units": "kilogram / metre**3"},
79 | "diffusivity": {
80 | "value": 1.0e-6,
81 | "units": "metre**2 / second"},
82 | "capacity":{
83 | "value": 1000.0 ,
84 | "units": "joule / kelvin / kilogram"},
85 | "radiogenicHeatProd":{
86 | "value": 0.4,
87 | "units": "milliwatts / metre**3"},
88 | "viscosity": "Wet Quartz, Viscous Dislocation Creep, Goetze et al., 1978" ,
89 | "plasticity": "Rey and Muller, 2010 (LowerCrust)"
90 | },
91 |
92 | "Oceanic crust":{
93 | "density": {
94 | "value": 2900.0 ,
95 | "units": "kilogram / metre**3"},
96 | "diffusivity": {
97 | "value": 1.0e-6,
98 | "units": "metre**2 / second"},
99 | "capacity":{
100 | "value": 1000.0 ,
101 | "units": "joule / kelvin / kilogram"},
102 | "radiogenicHeatProd":{
103 | "value": 0.0,
104 | "units": "milliwatts / metre**3"},
105 | "viscosity": null ,
106 | "plasticity": null
107 | },
108 |
109 | "Dry Olivine Lithospheric Mantle":{
110 | "density": {
111 | "value": 3370.0 ,
112 | "units": "kilogram / metre**3"},
113 | "diffusivity": {
114 | "value": 1.0e-6,
115 | "units": "metre**2 / second"},
116 | "capacity":{
117 | "value": 1000.0 ,
118 | "units": "joule / kelvin / kilogram"},
119 | "radiogenicHeatProd":{
120 | "value": 0.02,
121 | "units": "milliwatts / metre**3"},
122 | "viscosity": "Dry Olivine, Viscous Dislocation Creep, Karato and Wu, 1990",
123 | "plasticity": "Rey and Muller, 2010 (LithosphericMantle)"
124 | },
125 |
126 |
127 | "Dry Olivine Asthenosphere":{
128 | "density": {
129 | "value": 3395.0 ,
130 | "units": "kilogram / metre**3"},
131 | "diffusivity": {
132 | "value": 1.0e-6,
133 | "units": "metre**2 / second"},
134 | "capacity":{
135 | "value": 1000.0 ,
136 | "units": "joule / kelvin / kilogram"},
137 | "radiogenicHeatProd":{
138 | "value": 0.7,
139 | "units": "milliwatts / metre**3"},
140 | "viscosity": "Dry Olivine, Viscous Dislocation Creep, Karato and Wu, 1990"
141 | }
142 |
143 | }
144 |
--------------------------------------------------------------------------------
/UWGeodynamics/ressources/PlasticRheologies.json:
--------------------------------------------------------------------------------
1 | {
2 | "Huismans and Beaumont, 2007 (WeakCrust)": {
3 | "citation": "Huismans, R. S., & Beaumont, C. (2007). Roles of lithospheric strain softening and heterogeneity in determining the geometry of rifts and continental margins. Geological Society, London, Special Publications, 282(1), 111-138. https://doi.org/10.1144/SP282.6",
4 | "onlinePDF": "http://sp.lyellcollection.org/content/282/1/111.short",
5 | "coefficients": {
6 | "cohesion": {
7 | "units": "megapascal",
8 | "value": 20.0
9 | },
10 | "cohesionAfterSoftening": {
11 | "units": "megapascal",
12 | "value": 20.0
13 | },
14 | "frictionAfterSoftening": {
15 | "units": "None",
16 | "value": 0.017
17 | },
18 | "frictionCoefficient": {
19 | "units": "None",
20 | "value": 0.123
21 | },
22 | "epsilon1": {
23 | "units": "None",
24 | "value": 0.5
25 | },
26 | "epsilon2": {
27 | "units": "None",
28 | "value": 1.5
29 | }
30 | }
31 | },
32 | "Huismans et al. 2011, (Crust)": {
33 | "coefficients": {
34 | "cohesion": {
35 | "units": "megapascal",
36 | "value": 20.0
37 | },
38 | "cohesionAfterSoftening": {
39 | "units": "megapascal",
40 | "value": 20.0
41 | },
42 | "frictionAfterSoftening": {
43 | "units": "None",
44 | "value": 0.02
45 | },
46 | "frictionCoefficient": {
47 | "units": "None",
48 | "value": 0.12
49 | },
50 | "epsilon1": {
51 | "units": "None",
52 | "value": 0.5
53 | },
54 | "epsilon2": {
55 | "units": "None",
56 | "value": 1.5
57 | }
58 | }
59 | },
60 | "Rey and Muller, 2010 (LowerCrust)": {
61 | "citation": "Rey, P., Muller, R. (2010). Fragmentation of active continental plate margins owing to the buoyancy of the mantle wedge. Nature Geoscience, 3(4), 257-261",
62 | "onlinePDF": "http://earthbyte.org/Resources/Pdf/Rey_Muller_mantle_wedge_buyoancy_and_active_margin_fragmentation_NatGeosci2010.pdf",
63 | "coefficients": {
64 | "cohesion": {
65 | "units": "megapascal",
66 | "value": 20.0
67 | },
68 | "cohesionAfterSoftening": {
69 | "units": "megapascal",
70 | "value": 4.0
71 | },
72 | "frictionAfterSoftening": {
73 | "units": "None",
74 | "value": 0.1154
75 | },
76 | "frictionCoefficient": {
77 | "units": "None",
78 | "value": 0.577
79 | },
80 | "epsilon1": {
81 | "units": "None",
82 | "value": 0.0
83 | },
84 | "epsilon2": {
85 | "units": "None",
86 | "value": 0.2
87 | }
88 | }
89 | },
90 | "Rey et al., 2014 (LowerCrust)": {
91 | "citation": "Rey, P. F., Coltice, N., & Flament, N. (2014). Spreading continents kick-started plate tectonics. Nature. https://doi.org/10.1038/nature13728",
92 | "onlinePDF": "https://www.researchgate.net/publication/273754982_Rey_Coltice_Flament_Nature14",
93 | "coefficients": {
94 | "cohesion": {
95 | "units": "megapascal",
96 | "value": 20.0
97 | },
98 | "cohesionAfterSoftening": {
99 | "units": "megapascal",
100 | "value": 0.8
101 | },
102 | "frictionAfterSoftening": {
103 | "units": "None",
104 | "value": 0.02308
105 | },
106 | "frictionCoefficient": {
107 | "units": "None",
108 | "value": 0.577
109 | },
110 | "epsilon1": {
111 | "units": "None",
112 | "value": 0.0
113 | },
114 | "epsilon2": {
115 | "units": "None",
116 | "value": 0.2
117 | }
118 | }
119 | },
120 | "Rey and Muller, 2010 (LithosphericMantle)": {
121 | "citation": "Rey, P., Muller, R. (2010). Fragmentation of active continental plate margins owing to the buoyancy of the mantle wedge. Nature Geoscience, 3(4), 257-261",
122 | "onlinePDF": "http://earthbyte.org/Resources/Pdf/Rey_Muller_mantle_wedge_buyoancy_and_active_margin_fragmentation_NatGeosci2010.pdf",
123 | "coefficients": {
124 | "cohesion": {
125 | "units": "megapascal",
126 | "value": 10.0
127 | },
128 | "cohesionAfterSoftening": {
129 | "units": "megapascal",
130 | "value": 2.0
131 | },
132 | "frictionAfterSoftening": {
133 | "units": "None",
134 | "value": 0.1154
135 | },
136 | "frictionCoefficient": {
137 | "units": "None",
138 | "value": 0.577
139 | },
140 | "epsilon1": {
141 | "units": "None",
142 | "value": 0.0
143 | },
144 | "epsilon2": {
145 | "units": "None",
146 | "value": 0.2
147 | }
148 | }
149 | },
150 | "Rey et al., 2014 (LithosphericMantle)": {
151 | "citation": "Rey, P. F., Coltice, N., & Flament, N. (2014). Spreading continents kick-started plate tectonics. Nature. https://doi.org/10.1038/nature13728",
152 | "onlinePDF": "https://www.researchgate.net/publication/273754982_Rey_Coltice_Flament_Nature14",
153 | "coefficients": {
154 | "cohesion": {
155 | "units": "megapascal",
156 | "value": 10.0
157 | },
158 | "cohesionAfterSoftening": {
159 | "units": "megapascal",
160 | "value": 0.4
161 | },
162 | "frictionAfterSoftening": {
163 | "units": "None",
164 | "value": 0.02308
165 | },
166 | "frictionCoefficient": {
167 | "units": "None",
168 | "value": 0.577
169 | },
170 | "epsilon1": {
171 | "units": "None",
172 | "value": 0.0
173 | },
174 | "epsilon2": {
175 | "units": "None",
176 | "value": 0.2
177 | }
178 | }
179 | },
180 | "Watremez et al., 2013 (AsthenosphericMantle)": {
181 | "citation": "Watremez, L., E.Burov, E.d'Acremont, S.Leroy, B.Huet, L.LePourhiet, and N.Bellahsen (2013), Buoyancy and localizing properties of continental mantle lithosphere: Insights from thermomechanical models of the eastern Gulf of Aden, Geochem. Geophys. Geosyst., 14, 2800-2817, doi: 10.1002/ggge.20179",
182 | "onlinePDF": "https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1002/ggge.20179",
183 | "coefficients": {
184 | "cohesion": {
185 | "units": "megapascal",
186 | "value": 300.0
187 | },
188 | "frictionCoefficient": {
189 | "units": "None",
190 | "value": 0.0349
191 | }
192 | }
193 | },
194 | "Rey and Muller, 2010 (UpperCrust)": {
195 | "citation": "Rey, P., Muller, R. (2010). Fragmentation of active continental plate margins owing to the buoyancy of the mantle wedge. Nature Geoscience, 3(4), 257-261",
196 | "onlinePDF": "http://earthbyte.org/Resources/Pdf/Rey_Muller_mantle_wedge_buyoancy_and_active_margin_fragmentation_NatGeosci2010.pdf",
197 | "coefficients": {
198 | "cohesion": {
199 | "units": "megapascal",
200 | "value": 10.0
201 | },
202 | "cohesionAfterSoftening": {
203 | "units": "megapascal",
204 | "value": 2.0
205 | },
206 | "frictionAfterSoftening": {
207 | "units": "None",
208 | "value": 0.1154
209 | },
210 | "frictionCoefficient": {
211 | "units": "None",
212 | "value": 0.577
213 | },
214 | "epsilon1": {
215 | "units": "None",
216 | "value": 0.0
217 | },
218 | "epsilon2": {
219 | "units": "None",
220 | "value": 0.2
221 | }
222 | }
223 | },
224 |
225 | "Rey et al., 2014 (UpperCrust)": {
226 | "citation": "Rey, P. F., Coltice, N., & Flament, N. (2014). Spreading continents kick-started plate tectonics. Nature. https://doi.org/10.1038/nature13728",
227 | "onlinePDF": "https://www.researchgate.net/publication/273754982_Rey_Coltice_Flament_Nature14",
228 | "coefficients": {
229 | "cohesion": {
230 | "units": "megapascal",
231 | "value": 10.0
232 | },
233 | "cohesionAfterSoftening": {
234 | "units": "megapascal",
235 | "value": 0.4
236 | },
237 | "frictionAfterSoftening": {
238 | "units": "None",
239 | "value": 0.2308
240 | },
241 | "frictionCoefficient": {
242 | "units": "None",
243 | "value": 0.577
244 | },
245 | "epsilon1": {
246 | "units": "None",
247 | "value": 0.0
248 | },
249 | "epsilon2": {
250 | "units": "None",
251 | "value": 0.2
252 | }
253 | }
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/UWGeodynamics/ressources/Solidus.json:
--------------------------------------------------------------------------------
1 | {
2 | "Crustal Solidus": {
3 | "coefficients": {
4 | "A1": {
5 | "units": "kelvin",
6 | "value": 993
7 | },
8 | "A2": {
9 | "units": "kelvin / pascal",
10 | "value": -1.2e-07
11 | },
12 | "A3": {
13 | "units": "kelvin / pascal ** 2",
14 | "value": 1.2e-16
15 | },
16 | "A4": {
17 | "units": "None",
18 | "value": 0.0
19 | }
20 | }
21 | },
22 | "Mantle Solidus": {
23 | "coefficients": {
24 | "A1": {
25 | "units": "kelvin",
26 | "value": 1393.661
27 | },
28 | "A2": {
29 | "units": "kelvin / pascal",
30 | "value": 1.32899e-07
31 | },
32 | "A3": {
33 | "units": "kelvin / pascal ** 2",
34 | "value": -5.104e-18
35 | },
36 | "A4": {
37 | "units": "None",
38 | "value": 0.0
39 | }
40 | }
41 | },
42 | "Mid Crustal Solidus": {
43 | "coefficients": {
44 | "A1": {
45 | "units": "kelvin",
46 | "value": 1063
47 | },
48 | "A2": {
49 | "units": "kelvin / pascal",
50 | "value": -1.2e-07
51 | },
52 | "A3": {
53 | "units": "kelvin / pascal ** 2",
54 | "value": 1.2e-16
55 | },
56 | "A4": {
57 | "units": "None",
58 | "value": 0.0
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/UWGeodynamics/shapes.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 | import numpy as np
3 | import underworld as uw
4 | import underworld.function as fn
5 | from UWGeodynamics import non_dimensionalise as nd
6 |
7 |
8 | class Polygon(fn.Function):
9 | """Polygon Shape Class"""
10 |
11 | def __init__(self, vertices):
12 | """Create a polygon shape
13 |
14 | Parameters
15 | ----------
16 |
17 | vertices : vertices of the polygon as (x,y) pairs.
18 |
19 | Returns
20 | -------
21 |
22 | Polygon Shape Class
23 | """
24 | self.vertices = vertices
25 | self.top = min([y for x, y in self.vertices])
26 | self.bottom = max([y for x, y in self.vertices])
27 | vertices = [(nd(x), nd(y)) for x, y in self.vertices]
28 | self._fn = uw.function.shape.Polygon(np.array(vertices))
29 | super(Polygon, self).__init__(argument_fns=None)
30 | self._fncself = self._fn._fncself
31 |
32 |
33 | class HalfSpace(fn.Function):
34 | """ Class to define a HalfSpace
35 |
36 | A plan defined by a normal vector is used to split the space
37 | in two half spaces. By default the origin of the coordinate
38 | system is at (0., 0.).
39 |
40 | Particles tested against this class are assigned a boolean value.
41 | """
42 |
43 | def __init__(self, normal, origin=None, reverse=False):
44 | """ HalfSpace
45 |
46 | Parameters:
47 | -----------
48 |
49 | normal: A vector defining the normal to the plan.
50 | origin: Origin
51 | reverse: by default, particles tested against this class are
52 | assigned "True" if they lay on or below the plan.
53 | You can reverse than behavior by setting reverse=True.
54 |
55 | Returns:
56 | --------
57 |
58 | A UWGeodynamics Shape object.
59 |
60 | """
61 |
62 | if isinstance(normal, (tuple, list)):
63 | self.normal = fn.misc.constant([float(nd(val)) for val in normal])
64 | else:
65 | raise ValueError("{0} must be a list or tuple".format(normal))
66 |
67 | if isinstance(origin, (tuple, list)):
68 | self.origin = fn.misc.constant([float(nd(val)) for val in origin])
69 | else:
70 | self.origin = fn.misc.constant([0.] * len(normal))
71 |
72 | self.reverse = reverse
73 |
74 | coords = fn.input()
75 | new_coords = coords - self.origin
76 | func = fn.math.dot(self.normal, new_coords)
77 |
78 | # True if below, False if above
79 | if not self.reverse:
80 | conditions = [(func <= 0., True), (func > 0., False)]
81 | else:
82 | conditions = [(func >= 0., True), (func < 0., False)]
83 |
84 | self._fn = fn.branching.conditional(conditions)
85 | super(HalfSpace, self).__init__(argument_fns=None)
86 | self._fncself = self._fn._fncself
87 |
88 |
89 | class Layer2D(fn.Function):
90 | """Layer 2D"""
91 |
92 | def __init__(self, top, bottom):
93 | """Create a 2D Layer object
94 |
95 | Parameters
96 | ----------
97 |
98 | top : top of the layer
99 | bottom : bottom of the layer
100 |
101 | Returns
102 | -------
103 |
104 | AN UWGeodynamics Shape object
105 | """
106 | self.top = top
107 | self.bottom = bottom
108 |
109 | coord = fn.input()
110 | self._fn = ((coord[1] <= nd(self.top)) &
111 | (coord[1] >= nd(self.bottom)))
112 | super(Layer2D, self).__init__(argument_fns=None)
113 | self._fncself = self._fn._fncself
114 |
115 | Layer = Layer2D
116 |
117 | class Layer3D(fn.Function):
118 | """Layer3D"""
119 |
120 | def __init__(self, top, bottom):
121 | """Create a 3D Layer object
122 |
123 | Parameters
124 | ----------
125 |
126 | top : top of the layer
127 | bottom : bottom of the layer
128 |
129 | Returns
130 | -------
131 |
132 | AN UWGeodynamics Shape object
133 | """
134 | self.top = top
135 | self.bottom = bottom
136 |
137 | coord = fn.input()
138 | self._fn = ((coord[2] <= nd(self.top)) &
139 | (coord[2] >= nd(self.bottom)))
140 | super(Layer3D, self).__init__(argument_fns=None)
141 | self._fncself = self._fn._fncself
142 |
143 |
144 | class Box(fn.Function):
145 | """Box"""
146 |
147 | def __init__(self, top, bottom, minX=0., maxX=0., minY=None, maxY=None):
148 | """Create a Box Shape
149 |
150 | Parameters
151 | ----------
152 |
153 | top : Top of the Box
154 | bottom : Bottom of the Box
155 | minX : Minimum extent of the Box along the x-axis
156 | maxX : Maximum extent of the Box along the x-axis
157 |
158 | Only in 3D:
159 |
160 | minY : Minimum extent of the Box along the y-axis
161 | maxY : Maximum extent of the Box along the y-axis
162 |
163 | Returns
164 | -------
165 | """
166 | self.top = top
167 | self.bottom = bottom
168 | self.minX = minX
169 | self.maxX = maxX
170 | self.minY = minY
171 | self.maxY = maxY
172 |
173 | coord = fn.input()
174 | if (self.minY is not None) and (self.maxY is not None):
175 | func = ((coord[1] <= nd(self.maxY)) &
176 | (coord[1] >= nd(self.minY)) &
177 | (coord[0] <= nd(self.maxX)) &
178 | (coord[0] >= nd(self.minX)) &
179 | (coord[2] <= nd(self.top)) &
180 | (coord[2] >= nd(self.bottom)))
181 | else:
182 | func = ((coord[1] <= nd(self.top)) &
183 | (coord[1] >= nd(self.bottom)) &
184 | (coord[0] <= nd(self.maxX)) &
185 | (coord[0] >= nd(self.minX)))
186 | self._fn = func
187 | super(Box, self).__init__(argument_fns=None)
188 | self._fncself = self._fn._fncself
189 |
190 |
191 | class Disk(fn.Function):
192 | """Disk"""
193 |
194 | def __init__(self, center, radius):
195 | """Create a Disk shape
196 |
197 | Parameters
198 | ----------
199 |
200 | center : center of the disk
201 | radius : radius of the disk
202 |
203 | Returns
204 | -------
205 |
206 | An UWGeodynamics Shape
207 | """
208 | self.center = center
209 | self.radius = radius
210 | self.top = center[1] + self.radius
211 | self.bottom = center[1] - self.radius
212 |
213 | center = tuple(nd(x) for x in list(self.center))
214 | radius = nd(self.radius)
215 | coord = fn.input() - center
216 | self._fn = fn.math.dot(coord, coord) < radius**2
217 | super(Disk, self).__init__(argument_fns=None)
218 | self._fncself = self._fn._fncself
219 |
220 |
221 | Sphere = Disk
222 |
223 |
224 | class Annulus(fn.Function):
225 | """Annulus"""
226 |
227 | def __init__(self, center, r1, r2):
228 | """Create an Annulus shape
229 |
230 | Parameters
231 | ----------
232 |
233 | center : center of the annulus
234 | r1 : Internal radius
235 | r2 : External radius
236 |
237 | Returns
238 | -------
239 |
240 | An UWGeodynamics Shape object
241 | """
242 | self.center = center
243 | self.r1 = r1
244 | self.r2 = r2
245 | self.bottom = center[1] - self.r2
246 | self.top = center[1] + self.r2
247 |
248 | center = tuple(nd(x) for x in list(self.center))
249 | r1 = nd(self.r1)
250 | r2 = nd(self.r2)
251 | coord = fn.input() - center
252 | self._fn = (fn.math.dot(coord, coord) < r2**2) & (fn.math.dot(coord, coord) > r1**2)
253 | super(Annulus, self).__init__(argument_fns=None)
254 | self._fncself = self._fn._fncself
255 |
--------------------------------------------------------------------------------
/UWGeodynamics/utilities/UWtoAscii.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | from __future__ import print_function, absolute_import
3 | import h5py
4 | import os
5 | import numpy as np
6 | import xml.etree.ElementTree as ET
7 | import argparse
8 |
9 | __author__ = "Romain Beucher"
10 |
11 |
12 | def convert_to_ascii(file_input, file_output=None):
13 |
14 | root_dir = os.path.dirname(file_input)
15 |
16 | with open(file_input, "r") as f:
17 | tree = ET.parse(f)
18 | root = tree.getroot()
19 |
20 | grid = root[0].find("Grid")
21 | geometry = grid.find("Geometry")
22 | attribute = grid.find("Attribute")
23 |
24 | if grid.get("Name") == "swarm":
25 |
26 | file_geometry = geometry[0].text
27 | f = h5py.File(os.path.join(root_dir, file_geometry.split(":")[0]), "r")
28 | geometry = f["/data"]
29 |
30 | elif grid.get("Name") == "FEM_Mesh_mesh":
31 |
32 | geometryFile = geometry[0][0][1].text
33 | f = h5py.File(os.path.join(root_dir, geometryFile.split(":")[0]), "r")
34 | geometry = f["/vertices"]
35 |
36 | attributesFile = attribute[0].text
37 | f = h5py.File(os.path.join(root_dir, attributesFile.split(":")[0]), "r")
38 | data = f["/data"]
39 |
40 | new = np.zeros((geometry.value.shape[0], geometry.value.shape[1] + 1))
41 | new[:, :-1] = geometry.value
42 | new[:, -1] = data.value.ravel()
43 |
44 | if file_output is None or file_output == "None":
45 | file_output = os.path.split(file_input)[-1].split(".")[0] + ".asc"
46 |
47 | np.savetxt(file_output, new)
48 |
49 |
50 | def main():
51 |
52 | description = """Convert UW .h5 file to ASCII
53 | for import into MOVE/PETREL"""
54 | parser = argparse.ArgumentParser(description=description)
55 | parser.add_argument('-i', '--input', help='input file', required=True)
56 | parser.add_argument('-o', '--output', help='output file', required=False)
57 | args = parser.parse_args()
58 |
59 | file_input = str(args.input)
60 | file_output = str(args.output)
61 |
62 | convert_to_ascii(file_input, file_output)
63 |
--------------------------------------------------------------------------------
/UWGeodynamics/utilities/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, absolute_import
2 | from .UWtoAscii import convert_to_ascii
3 | from .UWtoAscii import main
4 |
--------------------------------------------------------------------------------
/UWGeodynamics/uwgeo-data/uwgeodynamicsrc:
--------------------------------------------------------------------------------
1 | ### MATPLOTLIBRC FORMAT
2 |
3 | # This is a sample UWGeodynamics configuration file - you can find a copy
4 | # of it on your system in
5 | # site-packages/uwgeodynamics/uwgeo-data/uwgeodynamicsrc. If you edit it
6 | # there, please note that it will be overwritten in your next install.
7 | # If you want to keep a permanent local copy that will not be
8 | # overwritten, place it in the following location:
9 | # unix/linux:
10 | # $HOME/.config/uwgeodynamics/uwgeodynamicsrc or
11 | # $XDG_CONFIG_HOME/uwgeodynamics/uwgeodynamicsrc (if $XDG_CONFIG_HOME is set)
12 | # other platforms:
13 | # $HOME/.uwgeodynamics/uwgeodynamicsrc
14 |
15 | #### CONFIGURATION BEGINS HERE
16 |
17 | # Name of the model output directory
18 | #
19 | #output.directory : outputs
20 | #
21 | #
22 | # Gravitational acceleration
23 | #gravity : 9.81 meter / u.second**2
24 | #
25 | # Range of viscosities
26 | #minimum.viscosity : 1e19 pascal * u.second
27 | #maximum.viscosity : 1e25 pascal * second
28 | #
29 | # List of swarm variables
30 | #swarm.variables : materialField , plasticStrain , viscosityField , densityField
31 |
32 | # List of mesh variables
33 | #mesh.variables : velocityField , temperature , pressureField , strainRateField , projMaterialField , projViscosityField , projPlasticStrain , projDensityField
34 |
35 | # List of fields to output
36 | #default.outputs : materialField , temperature , pressureField , plasticStrain , velocityField
37 | #
38 | #
39 | # swarm-layout number of particle per cell
40 | #swarm.particles.per.cell : 50
41 | #
42 | # population control parameters
43 | #popcontrol.aggressive : True
44 | #popcontrol.split.threshold : 0.15
45 | #popcontrol.max.splits : 10
46 | #popcontrol.particles.per.cell : 50
47 | #
48 | # CFL condition
49 | # CFL : 0.1
50 | # Solver configuration
51 | #solver : mg
52 | #penalty : 0.0
53 | #nonlinear.tolerance : 1e-2
54 | #maximum.timestep : 200000
55 | #nonlinear.min.iterations : 3
56 | #nonlinear.max.iterations : 500
57 | #
58 | # Scaling coefficients
59 | #scaling.length : 1.0 meter
60 | #scaling.mass : 1.0 kilogram
61 | #scaling.time : 1.0 second
62 | #scaling.temperature : 1.0 u.degK
63 | #scaling.substance : 1.0 u.mole
64 | #
65 | # Common field units
66 | #velocity.units : centimeter / year
67 | #temperature.units : degK
68 | #pressure.units : pascal
69 | #strain.rate : 1.0 / second
70 | #viscosity.units : pascal * second
71 | #density.units : kilogram / meter**3
72 | #
73 | # Output field units
74 | #viscosityField : pascal * second
75 | #densityField : kilogram / metre**3
76 | #velocityField : centimeter / u.year
77 | #temperature : degK
78 | #pressureField : pascal
79 | #strainRateField : 1.0 / second
80 | #projViscosityField : pascal * second
81 | #projDensityField : kilogram / u.metre**3
82 |
--------------------------------------------------------------------------------
/UWGeodynamics/version.py:
--------------------------------------------------------------------------------
1 |
2 | # THIS FILE IS GENERATED FROM UWGeodynamics SETUP.PY
3 | #
4 | short_version = '2.13.0'
5 | version = '2.13.0'
6 | full_version = '2.13.0-dev-20ce35c(development)'
7 | git_revision = '20ce35c409a1194dec531d1b5270a76d4cec6ea8'
8 | release = False
9 |
10 | if not release:
11 | version = full_version
12 |
--------------------------------------------------------------------------------
/conda/meta.yaml:
--------------------------------------------------------------------------------
1 | {% set name = "UWGeodynamics" %}
2 | {% set version = "2.10.0b" %}
3 |
4 | package:
5 | name: {{ name|lower }}
6 | version: {{ version }}
7 |
8 | source:
9 | #url: https://github.com/underworldcode/UWGeodynamics/archive/v{{ version }}.tar.gz
10 | #sha256:
11 | git_url: https://github.com/underworldcode/UWGeodynamics.git
12 | git_tag: development
13 |
14 | build:
15 | skip: true # [win]
16 | number: 0
17 | script: {{ PYTHON }} -m pip install . -vv
18 |
19 | requirements:
20 | host:
21 | - python
22 | - underworld2>=2.10
23 |
24 | run:
25 | - python
26 | - underworld2>=2.10
27 |
28 |
29 | about:
30 | home: "https://github.com/underworldcode/UWGeodynamics"
31 | license: LGPL-3.0-only
32 | license_family: LGPL
33 | license_file: LICENSE.md
34 | summary: "Underworld Geodynamics Project"
35 | doc_url: https://uwgeodynamics.readthedocs.io/
36 | dev_url: https://github.com/underworldcode/UWGeodynamics/tree/development
37 |
38 | extra:
39 | recipe-maintainers:
40 | - rbeucher
41 | - jgiordani
42 |
--------------------------------------------------------------------------------
/docker-compose.yaml:
--------------------------------------------------------------------------------
1 |
2 | version: '3.7'
3 | services:
4 | underworld:
5 | container_name: UWGeodynamics-dev
6 | image: underworldcode/uwgeodynamics:dev
7 | build:
8 | context: $PWD
9 | dockerfile: Dockerfile
10 | hostname: "uw-container"
11 | command: "jupyter notebook --ip=0.0.0.0 --no-browser"
12 | ports:
13 | - "8888:8888"
14 | - "9999:9999"
15 | volumes:
16 | - "$PWD:/home/jovyan/workspace"
17 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/.gitignore
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # readthedocs
2 |
3 | Documentation sources published on [readthedocs](https://uwgeodynamics.readthedocs.io/en/latest/):
4 |
5 | # examples
6 |
7 | Contain examples of UWGeodynamics functionalities.
8 |
9 | # tutorials
10 |
11 | Complete work through examples.
12 |
13 | # nci_gadi
14 |
15 | Installation script for NCI gadi
16 |
--------------------------------------------------------------------------------
/docs/examples/1_11_StokesSinker3D.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Stokes Sinker\n",
8 | "\n",
9 | "Demonstration example for setting up particle swarms with different material properties. This system consists of a dense, high viscosity sphere falling through a background lower density and viscosity fluid. "
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": 1,
15 | "metadata": {},
16 | "outputs": [
17 | {
18 | "name": "stdout",
19 | "output_type": "stream",
20 | "text": [
21 | "loaded rc file /home/jovyan/workspace/codes/UWGeodynamics_use_with_docker/UWGeodynamics/uwgeo-data/uwgeodynamicsrc\n"
22 | ]
23 | }
24 | ],
25 | "source": [
26 | "import UWGeodynamics as GEO\n",
27 | "from UWGeodynamics import visualisation as vis"
28 | ]
29 | },
30 | {
31 | "cell_type": "code",
32 | "execution_count": 2,
33 | "metadata": {},
34 | "outputs": [],
35 | "source": [
36 | "u = GEO.UnitRegistry"
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "execution_count": 3,
42 | "metadata": {},
43 | "outputs": [],
44 | "source": [
45 | "velocity = 1.0 * u.centimeter / u.hour\n",
46 | "model_length = 2. * u.meter\n",
47 | "model_height = 1. * u.meter\n",
48 | "refViscosity = 1e6 * u.pascal * u.second\n",
49 | "bodyforce = 200 * u.kilogram / u.metre**3 * 9.81 * u.meter / u.second**2\n",
50 | "\n",
51 | "KL = model_height\n",
52 | "Kt = KL / velocity\n",
53 | "KM = bodyforce * KL**2 * Kt**2\n",
54 | "\n",
55 | "GEO.scaling_coefficients[\"[length]\"] = KL\n",
56 | "GEO.scaling_coefficients[\"[time]\"] = Kt\n",
57 | "GEO.scaling_coefficients[\"[mass]\"]= KM"
58 | ]
59 | },
60 | {
61 | "cell_type": "code",
62 | "execution_count": 4,
63 | "metadata": {},
64 | "outputs": [],
65 | "source": [
66 | "Model = GEO.Model(elementRes=(16, 16, 16), \n",
67 | " minCoord=(-1. * u.meter, -1. * u.meter, -50. * u.centimeter), \n",
68 | " maxCoord=(1. * u.meter, 1. * u.meter, 50. * u.centimeter),\n",
69 | " gravity =(0.0, 0.0, -9.81 * u.meter / u.second**2) )"
70 | ]
71 | },
72 | {
73 | "cell_type": "code",
74 | "execution_count": 5,
75 | "metadata": {},
76 | "outputs": [],
77 | "source": [
78 | "Model.outputDir = \"1_11_StokesSinker3D\""
79 | ]
80 | },
81 | {
82 | "cell_type": "code",
83 | "execution_count": 6,
84 | "metadata": {},
85 | "outputs": [],
86 | "source": [
87 | "lightMaterial = Model.add_material(name=\"Light\", shape=GEO.shapes.Layer3D(top=Model.top, bottom=Model.bottom))\n",
88 | "heavyMaterial = Model.add_material(name=\"Heavy\", shape=GEO.shapes.Sphere(center=(0., 0., 20.*u.centimetre), radius=20. * u.centimetre))"
89 | ]
90 | },
91 | {
92 | "cell_type": "code",
93 | "execution_count": 7,
94 | "metadata": {},
95 | "outputs": [],
96 | "source": [
97 | "lightMaterial.density = 10 * u.kilogram / u.metre**3\n",
98 | "heavyMaterial.density = 500 * u.kilogram / u.metre**3\n",
99 | "\n",
100 | "lightMaterial.viscosity = GEO.ConstantViscosity(1e6 * u.pascal * u.second)\n",
101 | "heavyMaterial.viscosity = GEO.ConstantViscosity(1e6 * u.pascal * u.second)"
102 | ]
103 | },
104 | {
105 | "cell_type": "code",
106 | "execution_count": 8,
107 | "metadata": {},
108 | "outputs": [
109 | {
110 | "data": {
111 | "text/plain": [
112 | ""
113 | ]
114 | },
115 | "execution_count": 8,
116 | "metadata": {},
117 | "output_type": "execute_result"
118 | }
119 | ],
120 | "source": [
121 | "Model.set_velocityBCs(left=[0, None, None],\n",
122 | " right=[0, None, None],\n",
123 | " top=[None, None, 0.],\n",
124 | " bottom=[None, None, 0], \n",
125 | " front=[None, 0., None],\n",
126 | " back=[None, 0., None])"
127 | ]
128 | },
129 | {
130 | "cell_type": "code",
131 | "execution_count": null,
132 | "metadata": {},
133 | "outputs": [],
134 | "source": [
135 | "Fig = vis.Figure(resolution=(1200,600))\n",
136 | "Fig.Surface(Model.mesh, Model.projMaterialField, cullface=False, opacity=0.5)\n",
137 | "Fig.window()"
138 | ]
139 | },
140 | {
141 | "cell_type": "code",
142 | "execution_count": 10,
143 | "metadata": {},
144 | "outputs": [],
145 | "source": [
146 | "Model.init_model()"
147 | ]
148 | },
149 | {
150 | "cell_type": "code",
151 | "execution_count": null,
152 | "metadata": {},
153 | "outputs": [],
154 | "source": [
155 | "Model.run_for(3.0 * u.hours, checkpoint_interval=0.1 * u.hours)"
156 | ]
157 | }
158 | ],
159 | "metadata": {
160 | "kernelspec": {
161 | "display_name": "Python 3",
162 | "language": "python",
163 | "name": "python3"
164 | },
165 | "language_info": {
166 | "codemirror_mode": {
167 | "name": "ipython",
168 | "version": 3
169 | },
170 | "file_extension": ".py",
171 | "mimetype": "text/x-python",
172 | "name": "python",
173 | "nbconvert_exporter": "python",
174 | "pygments_lexer": "ipython3",
175 | "version": "3.7.3"
176 | }
177 | },
178 | "nbformat": 4,
179 | "nbformat_minor": 2
180 | }
181 |
--------------------------------------------------------------------------------
/docs/examples/1_21_3D_ColumnsTractionBottom.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [
8 | {
9 | "name": "stdout",
10 | "output_type": "stream",
11 | "text": [
12 | "loaded rc file /home/jovyan/workspace/codes/UWGeodynamics_use_with_docker/UWGeodynamics/uwgeo-data/uwgeodynamicsrc\n"
13 | ]
14 | }
15 | ],
16 | "source": [
17 | "import UWGeodynamics as GEO\n",
18 | "from UWGeodynamics import visualisation as vis"
19 | ]
20 | },
21 | {
22 | "cell_type": "code",
23 | "execution_count": 2,
24 | "metadata": {},
25 | "outputs": [],
26 | "source": [
27 | "u = GEO.UnitRegistry"
28 | ]
29 | },
30 | {
31 | "cell_type": "code",
32 | "execution_count": 3,
33 | "metadata": {},
34 | "outputs": [],
35 | "source": [
36 | "# Characteristic values of the system\n",
37 | "half_rate = (1.8 * u.centimeter / u.year).to(u.meter / u.second)\n",
38 | "model_length = 60e3 * u.meter\n",
39 | "model_height = 60e3 * u.meter\n",
40 | "bodyforce = (3300 * u.kilogram / u.metre**3 * 9.81 * u.meter / u.second**2)\n",
41 | "\n",
42 | "KL = model_length\n",
43 | "Kt = KL / half_rate\n",
44 | "KM = bodyforce * KL**2 * Kt**2\n",
45 | "\n",
46 | "GEO.scaling_coefficients[\"[length]\"] = KL\n",
47 | "GEO.scaling_coefficients[\"[time]\"] = Kt\n",
48 | "GEO.scaling_coefficients[\"[mass]\"] = KM"
49 | ]
50 | },
51 | {
52 | "cell_type": "code",
53 | "execution_count": 4,
54 | "metadata": {},
55 | "outputs": [],
56 | "source": [
57 | "Model = GEO.Model(elementRes=(16,16,16), \n",
58 | " minCoord=(-30 * u.kilometer, -30. * u.kilometer, -20 * u.kilometer),\n",
59 | " maxCoord=( 30 * u.kilometer, 30. * u.kilometer, 10 * u.kilometer), \n",
60 | " gravity=(0., 0., -9.81 * u.meter / u.second**2))"
61 | ]
62 | },
63 | {
64 | "cell_type": "code",
65 | "execution_count": 5,
66 | "metadata": {},
67 | "outputs": [],
68 | "source": [
69 | "Model.outputDir = \"1_21_3D_ColumnsTractionBottom\""
70 | ]
71 | },
72 | {
73 | "cell_type": "code",
74 | "execution_count": 6,
75 | "metadata": {},
76 | "outputs": [],
77 | "source": [
78 | "air = Model.add_material(name=\"air\", shape=GEO.shapes.Layer3D(top=Model.top, bottom=0.0))\n",
79 | "background = Model.add_material(name=\"background\", shape=GEO.shapes.Layer3D(top=air.bottom, bottom=Model.bottom))\n",
80 | "heavyColumn = Model.add_material(name=\"Heavy Column\", shape=GEO.shapes.Box(minX=-10.*u.kilometer,\n",
81 | " maxX=10. * u.kilometer,\n",
82 | " minY=-10. * u.kilometer,\n",
83 | " maxY=10. * u.kilometer,\n",
84 | " top=0, bottom=Model.bottom))"
85 | ]
86 | },
87 | {
88 | "cell_type": "code",
89 | "execution_count": null,
90 | "metadata": {},
91 | "outputs": [],
92 | "source": [
93 | "Fig = vis.Figure(resolution=(1200,600))\n",
94 | "Fig.Surface(Model.mesh, Model.projMaterialField, cullface=False, opacity=0.5)\n",
95 | "Fig.window()"
96 | ]
97 | },
98 | {
99 | "cell_type": "code",
100 | "execution_count": 8,
101 | "metadata": {},
102 | "outputs": [],
103 | "source": [
104 | "air.density = 0. * u.kilogram / u.metre**3\n",
105 | "background.density = 2700. * u.kilogram / u.metre**3\n",
106 | "heavyColumn.density = 3300. * u.kilogram / u.metre**3"
107 | ]
108 | },
109 | {
110 | "cell_type": "code",
111 | "execution_count": 9,
112 | "metadata": {},
113 | "outputs": [],
114 | "source": [
115 | "import numpy as np\n",
116 | "x = GEO.nd(-30 * u.kilometer)\n",
117 | "y = GEO.nd(-30 * u.kilometer)\n",
118 | "z = GEO.nd(-20 * u.kilometer)\n",
119 | "P = Model.lithostatic_pressureField.evaluate(np.array([[x,y,z]]))\n",
120 | "bottomPress = GEO.dimensionalise(P, u.megapascal)"
121 | ]
122 | },
123 | {
124 | "cell_type": "code",
125 | "execution_count": 10,
126 | "metadata": {},
127 | "outputs": [],
128 | "source": [
129 | "air.viscosity = 1e19 * u.pascal * u.second\n",
130 | "background.viscosity = 1e25 * u.pascal * u.second\n",
131 | "heavyColumn.viscosity = 1e25 * u.pascal * u.second"
132 | ]
133 | },
134 | {
135 | "cell_type": "code",
136 | "execution_count": 11,
137 | "metadata": {},
138 | "outputs": [
139 | {
140 | "data": {
141 | "text/plain": [
142 | ""
143 | ]
144 | },
145 | "execution_count": 11,
146 | "metadata": {},
147 | "output_type": "execute_result"
148 | }
149 | ],
150 | "source": [
151 | "Model.set_velocityBCs(left=[0.,0.,0.],\n",
152 | " right=[0.,0.,0.],\n",
153 | " front=[0., 0., 0.],\n",
154 | " back=[0., 0., 0.])\n",
155 | "\n",
156 | "Model.set_stressBCs(bottom=[0.,0., bottomPress])"
157 | ]
158 | },
159 | {
160 | "cell_type": "code",
161 | "execution_count": 12,
162 | "metadata": {},
163 | "outputs": [
164 | {
165 | "name": "stdout",
166 | "output_type": "stream",
167 | "text": [
168 | "Running with UWGeodynamics version 2.10.0-dev-71e6210(2.10-pre_release)\n",
169 | "Options: -Q22_pc_type uw -ksp_type bsscr -pc_type none -ksp_k2_type NULL -rescale_equations False -remove_constant_pressure_null_space False -change_backsolve False -change_A11rhspresolve False -restore_K False -A11_ksp_type fgmres -A11_ksp_rtol 1e-06 -scr_ksp_type fgmres -scr_ksp_rtol 1e-05\n",
170 | "Step: 1 Model Time: 202.3 megayear dt: 202.3 megayear (2020-08-13 05:38:47)\n"
171 | ]
172 | },
173 | {
174 | "data": {
175 | "text/plain": [
176 | "1"
177 | ]
178 | },
179 | "execution_count": 12,
180 | "metadata": {},
181 | "output_type": "execute_result"
182 | }
183 | ],
184 | "source": [
185 | "Model.run_for(nstep=1)"
186 | ]
187 | }
188 | ],
189 | "metadata": {
190 | "kernelspec": {
191 | "display_name": "Python 3",
192 | "language": "python",
193 | "name": "python3"
194 | },
195 | "language_info": {
196 | "codemirror_mode": {
197 | "name": "ipython",
198 | "version": 3
199 | },
200 | "file_extension": ".py",
201 | "mimetype": "text/x-python",
202 | "name": "python",
203 | "nbconvert_exporter": "python",
204 | "pygments_lexer": "ipython3",
205 | "version": "3.7.3"
206 | }
207 | },
208 | "nbformat": 4,
209 | "nbformat_minor": 1
210 | }
211 |
--------------------------------------------------------------------------------
/docs/examples/images/3D_hafspaces.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/3D_hafspaces.png
--------------------------------------------------------------------------------
/docs/examples/images/3D_layer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/3D_layer.png
--------------------------------------------------------------------------------
/docs/examples/images/CompressionSetUp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/CompressionSetUp.png
--------------------------------------------------------------------------------
/docs/examples/images/Extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/Extension.png
--------------------------------------------------------------------------------
/docs/examples/images/ExtensionA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/ExtensionA.png
--------------------------------------------------------------------------------
/docs/examples/images/ExtensionB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/ExtensionB.png
--------------------------------------------------------------------------------
/docs/examples/images/HotCanonFig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/HotCanonFig.png
--------------------------------------------------------------------------------
/docs/examples/images/HypnicJerk.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/HypnicJerk.gif
--------------------------------------------------------------------------------
/docs/examples/images/MovingWall.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/MovingWall.gif
--------------------------------------------------------------------------------
/docs/examples/images/SlabDetachment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/SlabDetachment.png
--------------------------------------------------------------------------------
/docs/examples/images/Stokes2D.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/Stokes2D.gif
--------------------------------------------------------------------------------
/docs/examples/images/vanKekken.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/examples/images/vanKekken.gif
--------------------------------------------------------------------------------
/docs/readthedocs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | SPHINXPROJ = UWGeodynamics
8 | SOURCEDIR = src
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 Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/readthedocs/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 | set SPHINXPROJ=UWGeodynamics
13 |
14 | if "%1" == "" goto help
15 |
16 | %SPHINXBUILD% >NUL 2>NUL
17 | if errorlevel 9009 (
18 | echo.
19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
20 | echo.installed, then set the SPHINXBUILD environment variable to point
21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
22 | echo.may add the Sphinx directory to PATH.
23 | echo.
24 | echo.If you don't have Sphinx installed, grab it from
25 | echo.http://sphinx-doc.org/
26 | exit /b 1
27 | )
28 |
29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
30 | goto end
31 |
32 | :help
33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
34 |
35 | :end
36 | popd
37 |
--------------------------------------------------------------------------------
/docs/readthedocs/requirements.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/requirements.txt
--------------------------------------------------------------------------------
/docs/readthedocs/src/Benchmarks.rst:
--------------------------------------------------------------------------------
1 | Benchmarks
2 | ==========
3 |
4 | Viscous Benchmarks
5 | ------------------
6 |
7 | 1. `Slab Detachment`_
8 |
9 | Visco-Plastic Benchmarks
10 | ------------------------
11 |
12 | 1. `Indentor Benchmark`_
13 | 2. `Brick Benchmark in compression`_
14 | 3. `Brick Benchmark in extension`_
15 |
16 |
17 | Averaging Viscosity Method
18 | --------------------------
19 |
20 | 1. `Subduction Case 1`_
21 | 2. `Subduction Case 2`_
22 |
23 |
24 | .. _Indentor Benchmark: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/benchmarks/1_22_Indentor_Benchmark.ipynb
25 | .. _Brick Benchmark in compression: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/benchmarks/Kaus_BrickBenchmark-Compression.ipynb
26 | .. _Brick Benchmark in extension: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/benchmarks/Kaus_BrickBenchmark_Extension.ipynb
27 | .. _Subduction Case 1: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/benchmarks/2D_Self_Subduction_Case1.ipynb
28 | .. _Subduction Case 2: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/benchmarks/2D_Self_Subduction_Case2.ipynb
29 | .. _Slab Detachment: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/benchmarks/1_12_Slab_Detachment_Benchmark.ipynb
30 |
--------------------------------------------------------------------------------
/docs/readthedocs/src/Examples.rst:
--------------------------------------------------------------------------------
1 |
2 | Examples
3 | ========
4 |
5 | We provide a series of example to illustrate the functionalities
6 | available in **UWGeodynamics**.
7 |
8 | 1. `Steady State heat`_
9 | 2. `Convection`_
10 | 3. `Blankenbach Benchmark`_
11 | 4. `Rayleigh Taylor`_
12 | 5. `Stokes sinker`_
13 | 6. `Hypnic Jerk`_ (Periodic Boundary Conditions)
14 | 7. `Slab Subduction`_
15 | 8. `Pure Shear example`_
16 | 9. `Visco-elastic half space`_
17 | 10. `Visco-elasto-plasticity in simple shear`_
18 | 11. `3D Stokes Sinker`_
19 | 12. `2D Bottom Traction condition`_ (Stress condition)
20 | 13. `3D Bottom Traction condition`_ (Stress condition)
21 | 14. `Free surface simple example`_ (Free Surface)
22 | 15. `Hot Canon Ball`_ (Internal boundary condition)
23 |
24 |
25 | .. _Steady State heat: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_01_Steady_State_Heat.ipynb
26 | .. _Convection: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_02_Convection_Example.ipynb
27 | .. _Blankenbach Benchmark: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_03_BlankenbachBenchmark.ipynb
28 | .. _Stokes sinker: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_05_StokesSinker.ipynb
29 | .. _Hypnic Jerk: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_06_HypnicJerk.ipynb
30 | .. _Slab Subduction: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_07_SlabSubduction.ipynb
31 | .. _Pure Shear example: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/2_09_ShearBandsPureShear.ipynb
32 | .. _Visco-elastic half space: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_08_ViscoElasticHalfSpace.ipynb
33 | .. _Visco-elasto-plasticity in simple shear: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_10_Viscoelastoplasticity-in-simple-shear.ipynb
34 | .. _3D Stokes Sinker: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_11_StokesSinker3D.ipynb
35 | .. _2D Bottom Traction condition: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_20_ColumnsTractionBottom.ipynb
36 | .. _3D Bottom Traction condition: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_21_3D_ColumnsTractionBottom.ipynb
37 | .. _Free surface simple example: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_23_FreeSurface_Simple_Example.ipynb
38 | .. _Hot Canon Ball: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/1_25_Hot_Canon_Ball.ipynb
39 | .. _Rayleigh Taylor: http://nbviewer.jupyter.org/github/rbeucher/UWGeodynamics/blob/master/docs/examples/2_15_Rayleigh-Taylor_van_Keken_et_al_1997.ipynb
40 |
--------------------------------------------------------------------------------
/docs/readthedocs/src/Installation.rst:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 | Docker_ installation
5 | --------------------
6 |
7 | Docker containers provide and easy-way to set up and distribute
8 | applications. They also provide a safe and consistent environment which
9 | facilitate debugging and reproducibility of models. The image we provide
10 | contains all the dependencies and configuration files required to run
11 | Underworld models. Users can start developping model as soon as they
12 | have downloaded the image, independently of the operating system running
13 | on their machine.
14 |
15 | We strongly encourage users to run UWGeodynamics using the docker images
16 | we provide on `Docker Hub`_
17 |
18 | Different version of the `underworldcode/uwgeodynamics` image can be
19 | pulled using a tag:
20 |
21 | 1. The *latest* tag points to the github master branch and uses the latest
22 | *underworld* release.
23 | 2. The *dev* tag points to the github development and uses the development
24 | branch of *underworld*.
25 | 3. release tags such as *0.9.8* points to the specified version.
26 |
27 | Command line
28 | ~~~~~~~~~~~~
29 |
30 | Once you have installed docker on your system you can *pull* the
31 | *UWGeodynamics* official image as follow:
32 |
33 | .. code:: bash
34 |
35 | docker pull underworldcode/uwgeodynamics
36 |
37 | You can list all the images available on your system as follow:
38 |
39 | .. code:: bash
40 |
41 | docker images
42 |
43 | An image can be deleted as follow:
44 |
45 | .. code:: bash
46 |
47 | docker rmi underworldcode/uwgeodynamics
48 |
49 | You can then start a docker container. (An instance of
50 | an image).
51 |
52 | .. code:: bash
53 |
54 | docker run -d \
55 | --name my_container \
56 | -p 8888:8888 \
57 | --mount source=myvol,target=/workspace/user-data \
58 | underworldcode/uwgeodynamics
59 |
60 | You can access the container via your browser at the following
61 | address: http://localhost:8888
62 |
63 |
64 | It is also possible to ssh into the container as follow:
65 |
66 | .. code:: bash
67 |
68 | docker exec -it my_container /bin/bash
69 |
70 | You can list the containers currently existing on your machine by running:
71 |
72 | .. code:: bash
73 |
74 | docker ps -a
75 |
76 | The "a" means "all container". The :code:`docker ps` command only list
77 | running containers.
78 |
79 | Docker containers can be stop (so that they do not use CPU or RAM ressource):
80 |
81 | .. code:: bash
82 |
83 | docker stop my_container
84 |
85 | They can also be deleted:
86 |
87 | .. code:: bash
88 |
89 | docker rm my_container
90 |
91 | .. warning::
92 |
93 | It's a good idea to keep track of how many containers have been created as
94 | they can rapidly take a lot of space on your machine.
95 |
96 | Kitematic_
97 | ~~~~~~~~~~
98 |
99 | Kitematic_ is a program that provides a graphical user interface to
100 | the *docker* daemon and to Docker Hub.
101 | The software is available for Windows, MacOsx and Linux. Be aware that on
102 | linux the installation may differ depending on the distribution you
103 | are running.
104 |
105 | 1. Download and Install Kitematic_
106 | 2. Open Kitematic and search for the **uwgeodynamics** image.
107 | 3. Create a container by clicking on the create button.
108 |
109 | You should now have a container appearing on the left side of your
110 | kitematic window. The first thing to do now is to create a link between
111 | a local directory (A directory on your physical hard drive) and a volume
112 | directory inside the docker container. A volume is a special directory
113 | that can be accessed from outside the container. It is the location you
114 | will use to save your results.
115 |
116 | Local Installation
117 | ------------------
118 |
119 | This is not recommended and involves installing *Underworld* and all
120 | its dependencies. Docker is highly recommended!!!
121 |
122 | Requirements
123 | ~~~~~~~~~~~~
124 |
125 | - Python >= 2.7
126 | - A Working version of Underworld2 >=2.6.0 (Please refer to the
127 | Underworld documentation)
128 | - pint >= 0.8
129 |
130 | **Note on Python 3 compatibility**:
131 | The bleeding edge version of *Underworld* (development branch)
132 | is now python 3 compatible only.
133 | *UWGeodynamics* is python 3 ready and can thus be used with it.
134 |
135 | Install
136 | ~~~~~~~
137 |
138 | **from Pip**
139 |
140 | The UWGeodynamics module can be installed directly from the Python
141 | Package Index:
142 |
143 | .. code:: bash
144 |
145 | pip install UWGeodynamics
146 |
147 | **from sources**
148 |
149 | The module source files are available through github_
150 |
151 | .. code:: bash
152 |
153 | git clone https://github.com/underworldcode/UWGeodynamics.git
154 |
155 | It can then be installed globally on your system using
156 |
157 | .. code:: bash
158 |
159 | pip install UWGeodynamics/
160 |
161 |
162 | HPC Installation
163 | ----------------
164 |
165 | requirements
166 | ^^^^^^^^^^^^
167 |
168 | - python >= 3.6
169 | - openmpi >= 1.8
170 | - hdf5 >= 1.8
171 |
172 | NCI Gadi
173 | ~~~~~~~~~~
174 |
175 | We provide a `script `_ to install UWGeodynamics, Underworld and Badlands inside a virtual
176 | environment on Gadi.
177 | A minimal `PBS script `_ is also available.
178 |
179 | Pawsey MAGNUS
180 | -------------
181 |
182 | The recommended way to run Underworld / UWGeodynamics model is to use
183 | Singularity.
184 |
185 | You can have a look at the `Pawsey
186 | documentation `__
187 | if you want to know more about Singularity:
188 |
189 | Pre-requisites
190 | ~~~~~~~~~~~~~~
191 |
192 | .. code:: bash
193 |
194 | ssh username@magnus-1.pawsey.org.au
195 |
196 | Singularity module needs to be loaded:
197 |
198 | .. code:: bash
199 |
200 | module load singularity
201 |
202 |
203 | The following command will pull the latest version of the image:
204 |
205 | .. code:: bash
206 |
207 | singularity pull --dir $MYGROUP/singularity/UWGeodynamics docker://underworldcode/uwgeodynamics:latest
208 |
209 | NOTE: You might need to create the $MYGROUP/singularity/UWGeodynamics directory.
210 |
211 | You can list images that are already present in the cache using the following command:
212 |
213 | .. code:: bash
214 |
215 | singularity cache list
216 |
217 | Once you have finished, we recommend you clean the cache:
218 |
219 | .. code:: bash
220 |
221 | singularity cache clean -a
222 |
223 | Setting up a job
224 | ~~~~~~~~~~~~~~~~
225 |
226 | Here we assume that we have a copy of the UWGeodynamics Tutorial 1 model
227 | saved as a python file (*Tutorial_1_ThermoMechanical_Model.py*), inside
228 | a folder *UWGeo_Tutorial1* located in the
229 | /scratch/your-project-account/your-username folder:
230 |
231 | .. code:: bash
232 |
233 | rb5533@magnus-1:/scratch/q97/rb5533/UWGeo_Tutorial1> ls
234 | Tutorial_1_ThermoMechanical_Model.py
235 |
236 | SLURM file
237 | ^^^^^^^^^^
238 |
239 | Following is an example of a SLURM file (*job.slurm*) showing how to run
240 | Tutorial 1 on 1 node using 4 cores:
241 |
242 | .. code:: bash
243 |
244 | #!/bin/bash -l
245 | #SBATCH --nodes=1
246 | #SBATCH --time=00:10:00
247 | #SBATCH --account=q97
248 | #SBATCH --partition=workq
249 | #SBATCH --export=NONE
250 |
251 | echo "PRINTING ENVIRONMENT"
252 | env
253 |
254 | echo "PRINTING SLURM SCRIPT"
255 | scontrol show job ${SLURM_JOBID} -ddd
256 |
257 | module load singularity
258 |
259 | export myRepository=$MYGROUP/singularity/UWGeodynamics
260 | export containerImage=$myRepository/uwgeodynamics_latest.sif
261 |
262 | srun --export=ALL singularity exec -C -B $PWD:/home/jovyan $containerImage python Tutorial_1_ThermoMechanical_Model.py
263 |
264 | Running a job
265 | ~~~~~~~~~~~~~
266 |
267 | After the above we should have the following files in our
268 | *UWGeo_Tutorial1* folder:
269 |
270 | .. code:: bash
271 |
272 | rb5533@magnus-1:/scratch/q97/rb5533/UWGeo_Tutorial1> ls
273 | Tutorial_1_ThermoMechanical_Model.py job.slurm
274 |
275 | The job can now be submitted to the queue system using:
276 |
277 | .. code:: bash
278 |
279 | sbatch job.slurm
280 |
281 | That’s it!!!
282 |
283 | .. _Jupyter: http://jupyter.org/
284 | .. _Docker: https://www.docker.com
285 | .. _Docker Hub: https://hub.docker.com/r/underworldcode/uwgeodynamics
286 | .. _Kitematic: https://kitematic.com/
287 | .. _github: https://github.com/underworldcode/UWGeodynamics.git
288 | .. _Pint: https://pint.readthedocs.io/en/latest
289 |
290 |
--------------------------------------------------------------------------------
/docs/readthedocs/src/Troubleshoot.rst:
--------------------------------------------------------------------------------
1 | Troubleshoot
2 | ============
3 |
--------------------------------------------------------------------------------
/docs/readthedocs/src/Tutorials.rst:
--------------------------------------------------------------------------------
1 |
2 | Tutorials
3 | =========
4 |
5 | We provide a series of docs/tutorials as Jupyter notebook:
6 |
7 | 1. `Tutorial 1 Simple Rift`_
8 |
9 | .. image:: img/Tutorial1.gif
10 | :target: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_1_ThermoMechanical_Model.ipynb
11 |
12 | [Output Data](https://www.dropbox.com/s/3gy3boh9mf9s807/Tutorial1_BGH.zip?dl=0)
13 |
14 | 2. `Tutorial 2 Melt`_
15 |
16 | [Output Data](https://www.dropbox.com/s/x03vlj03zqvu6wa/Tutorial2_BGH.zip?dl=0)
17 |
18 | 3. `Tutorial 3 Sandbox Extension`_
19 |
20 | .. image:: img/underworld.png
21 | :target: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_3_SandboxExtension_static_mesh.ipynb
22 |
23 | [Output Data](https://www.dropbox.com/s/9j24v5ex1eanro2/Tutorial3_BGH.zip?dl=0)
24 |
25 | 4. `Tutorial 4 Sandbox Compression`_
26 |
27 | .. image:: img/Tutorial4.png
28 | :target: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_4_NumericalSandboxCompression.ipynb
29 |
30 | [Output Data](https://www.dropbox.com/s/4wlp3cociwysz3l/Tutorial4_BGH.zip?dl=0)
31 |
32 | 5. `Tutorial 5 Simple Compression`_
33 |
34 | 6. `Tutorial 6 Simple Surface Processes`_
35 |
36 | 6.1 `Tutorial 6.1 Surface Processes - Sedimentation & Erosion Rates`_
37 |
38 | 6.2 `Tutorial 6.2 Surface Processes - Diffusive Surface`_
39 |
40 | 7. `Tutorial 7 3D Rift`_
41 |
42 | 8. `Tutorial 8 ViscoElasticity`_
43 |
44 | 9. `Tutorial 9 Passive Margins`_
45 |
46 | .. image:: img/Tutorial_9.gif
47 | :target: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_9_passive_margins.ipynb
48 |
49 | [Output Data](https://www.dropbox.com/s/g1ocpse0mld4tiy/Tutorial9_BGH.zip?dl=0)
50 |
51 | 10. `Tutorial 10 Thrust Wedge`_
52 |
53 | [Output Data](https://www.dropbox.com/s/q9m37t1f09zi3xj/Tutorial10_BGH.zip?dl=0)
54 |
55 | 11. `Tutorial 11 Coupling with Badlands`_
56 |
57 | [Output Data](https://www.dropbox.com/s/qpzrxp9fcf35w38/Tutorial11_BGH.zip?dl=0)
58 |
59 | .. image:: img/Tutorial11.gif
60 | :target: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_11_Coupling_with_Badlands.ipynb
61 |
62 | .. _Tutorial 1 Simple Rift: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_1_ThermoMechanical_Model.ipynb
63 | .. _Tutorial 2 Melt: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_2_Melt.ipynb
64 | .. _Tutorial 3 Sandbox Extension: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_3_SandboxExtension_static_mesh.ipynb
65 | .. _Tutorial 4 Sandbox Compression: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_4_NumericalSandboxCompression.ipynb
66 | .. _Tutorial 5 Simple Compression: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_5_Convergence_Model.ipynb
67 | .. _Tutorial 6 Simple Surface Processes: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_6_Simple_Surface_Processes.ipynb
68 | .. _Tutorial 6.1 Surface Processes - Sedimentation & Erosion Rates: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_6.1_sedimentation&erosion_rates.ipynb
69 | .. _Tutorial 6.2 Surface Processes - Diffusive Surface: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_6.2_diffusive_surface.ipynb
70 | .. _Tutorial 7 3D Rift: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_7_3D_Lithospheric_Model.ipynb
71 | .. _Tutorial 8 ViscoElasticity: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_8_Subduction_ViscoElastic.ipynb
72 | .. _Tutorial 9 Passive Margins: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_9_passive_margins.ipynb
73 | .. _Tutorial 10 Thrust Wedge: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_10_Thrust_Wedges.ipynb
74 | .. _Tutorial 11 Coupling with Badlands: http://nbviewer.jupyter.org/github/underworldcode/UWGeodynamics/blob/master/docs/tutorials/Tutorial_11_Coupling_with_Badlands.ipynb
75 |
--------------------------------------------------------------------------------
/docs/readthedocs/src/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Configuration file for the Sphinx documentation builder.
4 | #
5 | # This file does only contain a selection of the most common options. For a
6 | # full list see the documentation:
7 | # http://www.sphinx-doc.org/en/master/config
8 |
9 | # -- Path setup --------------------------------------------------------------
10 |
11 | # If extensions (or modules to document with autodoc) are in another directory,
12 | # add these directories to sys.path here. If the directory is relative to the
13 | # documentation root, use os.path.abspath to make it absolute, like shown here.
14 | #
15 | # import os
16 | # import sys
17 | # sys.path.insert(0, os.path.abspath('.'))
18 |
19 |
20 | # -- Project information -----------------------------------------------------
21 |
22 | project = 'UWGeodynamics'
23 | copyright = '2020, Romain Beucher'
24 | author = 'Romain Beucher'
25 |
26 | # The short X.Y version
27 | version = ''
28 | # The full version, including alpha/beta/rc tags
29 | release = '2.7'
30 |
31 |
32 | # -- General configuration ---------------------------------------------------
33 |
34 | # If your documentation needs a minimal Sphinx version, state it here.
35 | #
36 | # needs_sphinx = '1.0'
37 |
38 | # Add any Sphinx extension module names here, as strings. They can be
39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
40 | # ones.
41 | extensions = [
42 | 'sphinx.ext.autodoc',
43 | 'sphinx.ext.doctest',
44 | 'sphinx.ext.intersphinx',
45 | 'sphinx.ext.todo',
46 | 'sphinx.ext.coverage',
47 | 'sphinx.ext.mathjax',
48 | 'sphinx.ext.ifconfig',
49 | 'sphinx.ext.viewcode',
50 | 'sphinx.ext.githubpages',
51 | ]
52 |
53 | # Add any paths that contain templates here, relative to this directory.
54 | templates_path = ['_templates']
55 |
56 | source_parsers = {
57 | '.md': 'recommonmark.parser.CommonMarkParser',
58 | }
59 |
60 | # The suffix(es) of source filenames.
61 | # You can specify multiple suffix as a list of string:
62 | #
63 | source_suffix = ['.rst', '.md']
64 | #source_suffix = '.rst'
65 |
66 | # The master toctree document.
67 | master_doc = 'index'
68 |
69 | # The language for content autogenerated by Sphinx. Refer to documentation
70 | # for a list of supported languages.
71 | #
72 | # This is also used if you do content translation via gettext catalogs.
73 | # Usually you set "language" from the command line for these cases.
74 | language = None
75 |
76 | # List of patterns, relative to source directory, that match files and
77 | # directories to ignore when looking for source files.
78 | # This pattern also affects html_static_path and html_extra_path .
79 | exclude_patterns = []
80 |
81 | # The name of the Pygments (syntax highlighting) style to use.
82 | pygments_style = 'sphinx'
83 |
84 |
85 | # -- Options for HTML output -------------------------------------------------
86 |
87 | # The theme to use for HTML and HTML Help pages. See the documentation for
88 | # a list of builtin themes.
89 | #
90 | import sphinx_rtd_theme
91 |
92 | html_theme = 'sphinx_rtd_theme'
93 |
94 | # Add any paths that contain custom themes here, relative to this directory.
95 | #html_theme_path = []
96 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
97 |
98 | # Theme options are theme-specific and customize the look and feel of a theme
99 | # further. For a list of options available for each theme, see the
100 | # documentation.
101 | #
102 | #html_theme_options = {
103 | # 'github_user': 'underworldcode',
104 | # 'github_repo': 'uwgeodynamics',
105 | #}
106 |
107 | # Add any paths that contain custom static files (such as style sheets) here,
108 | # relative to this directory. They are copied after the builtin static files,
109 | # so a file named "default.css" will overwrite the builtin "default.css".
110 | #html_static_path = ['_static']
111 |
112 | # Custom sidebar templates, must be a dictionary that maps document names
113 | # to template names.
114 | #
115 | # The default sidebars (for documents that don't match any pattern) are
116 | # defined by theme itself. Builtin themes are using these templates by
117 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
118 | # 'searchbox.html']``.
119 | #
120 | # html_sidebars = {}
121 | html_sidebars = {
122 | 'index': ['sidebarintro.html', 'sourcelink.html', 'searchbox.html'],
123 | '**': ['sidebarlogo.html', 'localtoc.html', 'relations.html',
124 | 'sourcelink.html', 'searchbox.html']
125 | }
126 |
127 |
128 | # -- Options for HTMLHelp output ---------------------------------------------
129 |
130 | # Output file base name for HTML help builder.
131 | htmlhelp_basename = 'UWGeodynamicsdoc'
132 |
133 |
134 | # -- Options for LaTeX output ------------------------------------------------
135 |
136 | latex_elements = {
137 | # The paper size ('letterpaper' or 'a4paper').
138 | #
139 | # 'papersize': 'letterpaper',
140 |
141 | # The font size ('10pt', '11pt' or '12pt').
142 | #
143 | # 'pointsize': '10pt',
144 |
145 | # Additional stuff for the LaTeX preamble.
146 | #
147 | # 'preamble': '',
148 |
149 | # Latex figure (float) alignment
150 | #
151 | # 'figure_align': 'htbp',
152 | }
153 |
154 | # Grouping the document tree into LaTeX files. List of tuples
155 | # (source start file, target name, title,
156 | # author, documentclass [howto, manual, or own class]).
157 | latex_documents = [
158 | (master_doc, 'UWGeodynamics.tex', 'UWGeodynamics Documentation',
159 | 'Romain Beucher', 'manual'),
160 | ]
161 |
162 |
163 | # -- Options for manual page output ------------------------------------------
164 |
165 | # One entry per manual page. List of tuples
166 | # (source start file, name, description, authors, manual section).
167 | man_pages = [
168 | (master_doc, 'uwgeodynamics', 'UWGeodynamics Documentation',
169 | [author], 1)
170 | ]
171 |
172 |
173 | # -- Options for Texinfo output ----------------------------------------------
174 |
175 | # Grouping the document tree into Texinfo files. List of tuples
176 | # (source start file, target name, title, author,
177 | # dir menu entry, description, category)
178 | texinfo_documents = [
179 | (master_doc, 'UWGeodynamics', 'UWGeodynamics Documentation',
180 | author, 'UWGeodynamics', 'One line description of project.',
181 | 'Miscellaneous'),
182 | ]
183 |
184 |
185 | # -- Options for Epub output -------------------------------------------------
186 |
187 | # Bibliographic Dublin Core info.
188 | epub_title = project
189 | epub_author = author
190 | epub_publisher = author
191 | epub_copyright = copyright
192 |
193 | # The unique identifier of the text. This can be a ISBN number
194 | # or the project homepage.
195 | #
196 | # epub_identifier = ''
197 |
198 | # A unique identification for the text.
199 | #
200 | # epub_uid = ''
201 |
202 | # A list of files that should not be packed into the epub file.
203 | epub_exclude_files = ['search.html']
204 |
205 |
206 | # -- Extension configuration -------------------------------------------------
207 |
208 | # -- Options for intersphinx extension ---------------------------------------
209 |
210 | # Example configuration for intersphinx: refer to the Python standard library.
211 | intersphinx_mapping = {'https://docs.python.org/': None}
212 |
213 | # -- Options for todo extension ----------------------------------------------
214 |
215 | # If true, `todo` and `todoList` produce output, else they produce nothing.
216 | todo_include_todos = True
217 |
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/2D_polygon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/2D_polygon.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/3D_halfspaces.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/3D_halfspaces.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/3D_halfspaces2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/3D_halfspaces2.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/3D_layer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/3D_layer.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/Material1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/Material1.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/MaterialRegistry.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/MaterialRegistry.gif
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/PlasticityRegistry.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/PlasticityRegistry.gif
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/SandboxCompression.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/SandboxCompression.gif
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/Tutorial1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/Tutorial1.gif
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/Tutorial11.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/Tutorial11.gif
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/Tutorial4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/Tutorial4.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/Tutorial_9.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/Tutorial_9.gif
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/ViscousCreepRegistry.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/ViscousCreepRegistry.gif
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/annulus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/annulus.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/box.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/collision_wedge.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/collision_wedge.gif
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/density.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/density.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/disk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/disk.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/gif1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/gif1.gif
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/kitematic.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/kitematic.gif
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/layers.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/logos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/logos.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/mechanicalBCs1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/mechanicalBCs1.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/mechanicalBCs2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/mechanicalBCs2.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/multiple_materials.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/multiple_materials.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/multishape-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/multishape-1.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/multishape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/multishape.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/polygon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/polygon.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/tabtab.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/tabtab.gif
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/thermalBCs1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/thermalBCs1.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/thermalBCs2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/thermalBCs2.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/img/underworld.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/readthedocs/src/img/underworld.png
--------------------------------------------------------------------------------
/docs/readthedocs/src/index.rst:
--------------------------------------------------------------------------------
1 | Welcome to UWGeodynamics's documentation!
2 | =========================================
3 |
4 | .. image:: ./img/Tutorial1.gif
5 |
6 | .. image:: ./img/collision_wedge.gif
7 |
8 | The UWGeodynamics module intents to facilitate rapid prototyping of geodynamics
9 | models using Underworld. It can be seen as a set of high-level functions within
10 | the Underworld ecosystem. It is a means to quickly get the user into Underworld
11 | modelling and assumes very little knowledge in coding. The module make some
12 | assumptions based on how the user defines the boundary conditions and the
13 | properties of the materials (rocks, phases). Its simplicity comes with a
14 | relatively more rigid workflow (compared to the classic Underworld functions).
15 | However, the user can easily break the high level objects and get back to core
16 | Underworld function at any step of model design.
17 |
18 | The UWGeodynamics is inspired by the Lithospheric Modelling Recipe (LMR)
19 | originally developed by Luke Mondy, Guillaume Duclaux and Patrice Rey
20 | for Underworld 1. Some of the naming conventions have been reused to facilitate
21 | the transition from LMR. The Rheological libraries are also taken from LMR.
22 |
23 | As we think the low-level interface is more flexible, and in so allows for more
24 | complex models, we strongly encourage users to explore and break
25 | the High Level functions.
26 |
27 | We hope that the user will naturally move to the low-level functionalities as
28 | he or her gets more confident, and by doing so will access the wide range
29 | of possibilities offered by Underworld.
30 |
31 | UWGeodynamics and Underworld
32 | ----------------------------
33 |
34 | *UWGeodynamics* uses the *Underworld_* Application Programming Interface (API).
35 | Both projects are supported by The Underworld development team led by Louis Moresi and based in Melbourne, Australia
36 | at the University of Melbourne and at Monash University.
37 |
38 | *Underworld* and *UWGeodynamics* both provide powerful tools to develop numerical geodynamic models.
39 | But their approaches are different: *UWGeodynamics* largely guides users into a way of doing things.
40 | The Underworld API provides a series of tools and components (Mesh, Mesh variables, system of equations, functions)
41 | and leaves the responsibility to arrange those components to the user. The main advantage of the Underworld API is its flexibility.
42 | The main inconvenient resides in a somewhat steeper learning curve. *UWGeodynamics* components are
43 | designed to be more natural to non-experimented numerical modellers or people with little knowledge in programming.
44 | It is a way to quickly get started and design numerical models. Developing complex models can also be facilitated
45 | by the *UWGeodynamics* high-level interface as it requires less time and less involvement
46 | with the details of the Underworld API.
47 |
48 | The two approaches are complementary and mixing the two approaches is possible and highly encouraged.
49 |
50 | Versioning
51 | ------------------
52 |
53 | Since version 1.0 The Underworld development team has decided to match the *UWGeodynamics* version number with
54 | the latest supported version of Underworld.
55 | UWGeodynamics v2.7 is then supporing Underworld up to version 2.7.
56 |
57 | The third number is used for *UWGeodynamics* only (v2.7.1, v2.7.2 etc.)
58 |
59 | The development branch is based on the current *Underworld* development branch.
60 |
61 | Quick Start / Testing
62 | ----------------------
63 |
64 | We provide a docker container via binder_.
65 | This is a quick solution to get you started and run the examples and tutorials
66 | without installing anything on your machine. That is a good way to see if the
67 | software can actually be useful to you.
68 | The ressource are however limited and you should not try to run model with high resolution.
69 | 3D models can not be run in the binder.
70 |
71 | .. image:: ./img/SandboxCompression.gif
72 |
73 | .. toctree::
74 | :maxdepth: 2
75 |
76 | Installation
77 | User Guide
78 | Troubleshoot
79 |
80 | Examples
81 | Benchmarks
82 | Tutorials
83 |
--------------------------------------------------------------------------------
/docs/tutorials/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/.gitignore
--------------------------------------------------------------------------------
/docs/tutorials/images/CompressionA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/CompressionA.png
--------------------------------------------------------------------------------
/docs/tutorials/images/CompressionB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/CompressionB.png
--------------------------------------------------------------------------------
/docs/tutorials/images/CompressionSetUp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/CompressionSetUp.png
--------------------------------------------------------------------------------
/docs/tutorials/images/Extension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/Extension.png
--------------------------------------------------------------------------------
/docs/tutorials/images/ExtensionA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/ExtensionA.png
--------------------------------------------------------------------------------
/docs/tutorials/images/ExtensionB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/ExtensionB.png
--------------------------------------------------------------------------------
/docs/tutorials/images/LAnson2018.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/LAnson2018.png
--------------------------------------------------------------------------------
/docs/tutorials/images/Rey_et_al2009.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/Rey_et_al2009.png
--------------------------------------------------------------------------------
/docs/tutorials/images/Tutorial1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/Tutorial1.gif
--------------------------------------------------------------------------------
/docs/tutorials/images/Tutorial11.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/Tutorial11.gif
--------------------------------------------------------------------------------
/docs/tutorials/images/Tutorial4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/Tutorial4.png
--------------------------------------------------------------------------------
/docs/tutorials/images/Tutorial_10.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/Tutorial_10.gif
--------------------------------------------------------------------------------
/docs/tutorials/images/Tutorial_10_bcs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/Tutorial_10_bcs.png
--------------------------------------------------------------------------------
/docs/tutorials/images/Tutorial_9.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/Tutorial_9.gif
--------------------------------------------------------------------------------
/docs/tutorials/images/underworld.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/docs/tutorials/images/underworld.png
--------------------------------------------------------------------------------
/docs/tutorials/ressources/badlands.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 | 1
10 |
11 | 1
12 |
13 |
14 |
15 |
16 | -200.
17 |
18 |
19 |
21 |
22 |
23 |
24 |
33 |
34 |
35 |
36 | 1
37 |
38 |
39 |
40 | 0.
41 |
42 | 3000000.
43 |
44 | 1.
45 |
46 |
47 |
52 |
53 |
58 | 0.5
59 | 1.0
60 |
63 | 8.e-6
64 | 10
65 | 0.05
66 |
67 |
68 | 5000.
69 | 10000.
70 |
71 |
74 |
75 |
76 | 0.5
77 |
78 | 1.0
79 | 10
80 |
81 |
82 | outbdls
83 |
84 |
--------------------------------------------------------------------------------
/docs/uwgeodynamicsrc.template:
--------------------------------------------------------------------------------
1 | ### MATPLOTLIBRC FORMAT
2 |
3 | # This is a sample UWGeodynamics configuration file - you can find a copy
4 | # of it on your system in
5 | # site-packages/uwgeodynamics/uwgeo-data/uwgeodynamicsrc. If you edit it
6 | # there, please note that it will be overwritten in your next install.
7 | # If you want to keep a permanent local copy that will not be
8 | # overwritten, place it in the following location:
9 | # unix/linux:
10 | # $HOME/.config/uwgeodynamics/uwgeodynamicsrc or
11 | # $XDG_CONFIG_HOME/uwgeodynamics/uwgeodynamicsrc (if $XDG_CONFIG_HOME is set)
12 | # other platforms:
13 | # $HOME/.uwgeodynamics/uwgeodynamicsrc
14 |
15 | #### CONFIGURATION BEGINS HERE
16 |
17 | # Name of the model output directory
18 | #
19 | #output.directory : outputs
20 | #
21 | #
22 | # Gravitational acceleration
23 | #gravity : 9.81 meter / u.second**2
24 | #
25 | # Range of viscosities
26 | #minimum.viscosity : 1e19 pascal * u.second
27 | #maximum.viscosity : 1e25 pascal * second
28 | #
29 | # List of swarm variables
30 | #swarm.variables : materialField , plasticStrain , viscosityField , densityField
31 |
32 | # List of mesh variables
33 | #mesh.variables : velocityField , temperature , pressureField , strainRateField , projMaterialField , projViscosityField , projPlasticStrain , projDensityField
34 |
35 | # List of fields to output
36 | #default.outputs : materialField , temperature , pressureField , plasticStrain , velocityField
37 | #
38 | #
39 | # swarm-layout number of particle per cell
40 | #swarm.particles.per.cell : 50
41 | #
42 | # population control parameters
43 | #popcontrol.aggressive : True
44 | #popcontrol.split.threshold : 0.15
45 | #popcontrol.max.splits : 10
46 | #popcontrol.particles.per.cell : 50
47 | #
48 | # CFL condition
49 | # CFL : 0.1
50 | # Solver configuration
51 | #solver : mg
52 | #penalty : 0.0
53 | #nonlinear.tolerance : 1e-2
54 | #maximum.timestep : 200000
55 | #nonlinear.min.iterations : 3
56 | #nonlinear.max.iterations : 500
57 | #
58 | # Scaling coefficients
59 | #scaling.length : 1.0 meter
60 | #scaling.mass : 1.0 kilogram
61 | #scaling.time : 1.0 second
62 | #scaling.temperature : 1.0 u.degK
63 | #scaling.substance : 1.0 u.mole
64 | #
65 | # Common field units
66 | #velocity.units : centimeter / year
67 | #temperature.units : degK
68 | #pressure.units : pascal
69 | #strain.rate : 1.0 / second
70 | #viscosity.units : pascal * second
71 | #density.units : kilogram / meter**3
72 | #
73 | # Output field units
74 | #viscosityField : pascal * second
75 | #densityField : kilogram / metre**3
76 | #velocityField : centimeter / u.year
77 | #temperature : degK
78 | #pressureField : pascal
79 | #strainRateField : 1.0 / second
80 | #projViscosityField : pascal * second
81 | #projDensityField : kilogram / u.metre**3
82 |
--------------------------------------------------------------------------------
/joss/codemeta.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": "https://raw.githubusercontent.com/codemeta/codemeta/master/codemeta.jsonld",
3 | "@type": "Code",
4 | "author": [
5 |
6 | ],
7 | "identifier": "DOI: 10.5281/zenodo.2008639",
8 | "codeRepository": "https://github.com/underworldcode/UWGeodynamics",
9 | "datePublished": "2018-12-07",
10 | "dateModified": "2018-12-07",
11 | "dateCreated": "2018-12-07",
12 | "description": "Python package for geodynamic numerical modelling",
13 | "keywords": "geodynamics, geophysics, geology, earth-science, tectonics, rift, subduction, basin evolution, orogenic collision, sandbox experiment, stokes",
14 | "license": "GPL v3.0",
15 | "title": "UWGeodynamics",
16 | "version": "v1.0.0"
17 | }
18 |
--------------------------------------------------------------------------------
/joss/paper.bib:
--------------------------------------------------------------------------------
1 | @article{Moresi2002,
2 | author = {Moresi, L. and Dufour, F. and M{\"{u}}hlhaus, H.-B.},
3 | doi = {10.1007/s00024-002-8738-3},
4 | issn = {0033-4553},
5 | journal = {Pure and Applied Geophysics},
6 | month = {aug},
7 | number = {10},
8 | pages = {2335--2356},
9 | title = {{Mantle Convection Modeling with Viscoelastic/Brittle Lithosphere: Numerical Methodology and Plate Tectonic Modeling}},
10 | url = {http://link.springer.com/10.1007/s00024-002-8738-3},
11 | volume = {159},
12 | year = {2002}
13 | }
14 |
15 | @article{Moresi2007,
16 | author = {Moresi, L. and Quenette, S. and Lemiale, V. and M{\'{e}}riaux, C. and Appelbe, B. and M{\"{u}}hlhaus, H.-B.},
17 | doi = {10.1016/j.pepi.2007.06.009},
18 | issn = {00319201},
19 | journal = {Physics of the Earth and Planetary Interiors},
20 | month = {aug},
21 | number = {1-4},
22 | pages = {69--82},
23 | title = {{Computational approaches to studying non-linear dynamics of the crust and mantle}},
24 | url = {http://linkinghub.elsevier.com/retrieve/pii/S0031920107001446},
25 | volume = {163},
26 | year = {2007}
27 | }
28 |
29 | @article{Moresi2003,
30 | author = {Moresi, L. and Dufour, F. and M{\"{u}}hlhaus, H.-B.},
31 | doi = {10.1016/S0021-9991(02)00031-1},
32 | issn = {00219991},
33 | journal = {Journal of Computational Physics},
34 | month = {jan},
35 | number = {2},
36 | pages = {476--497},
37 | title = {{A Lagrangian integration point finite element method for large deformation modeling of viscoelastic geomaterials}},
38 | url = {http://linkinghub.elsevier.com/retrieve/pii/S0021999102000311},
39 | volume = {184},
40 | year = {2003}
41 | }
42 |
43 | @article{Salles2018,
44 | title = {pyBadlands: A framework to simulate sediment transport, landscape dynamics and basin stratigraphic evolution through space and time},
45 | author = {Salles, Tristan and Ding, Xuesong and Brocard, Gilles},
46 | journal = {PLOS ONE},
47 | year = {2018},
48 | volume = {13},
49 | number = {4},
50 | pages = {1--24},
51 | doi = {10.1371/journal.pone.0195557},
52 | }
53 |
--------------------------------------------------------------------------------
/joss/paper.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'UWGeodynamics: A teaching an research tool for numerical geodynamic modelling'
3 | tags:
4 | - Python
5 | - geodynamics
6 | - geophysics
7 | - geology
8 | - earth science
9 | - tectonics
10 | - rift
11 | - subduction
12 | - basin evolution
13 | - orogenic collision
14 | - subduction
15 | - sandbox experiment
16 | - stokes
17 | authors:
18 | - name: Romain Beucher
19 | orcid: 0000-0003-3891-5444
20 | affiliation: "1"
21 | - name: Louis Moresi
22 | orcid: 0000-0003-3685-174X
23 | affiliation: "1"
24 | - name: Julian Giordani
25 | orcid: 0000-0003-4515-9296
26 | affiliation: "1"
27 | - name: John Mansour
28 | orcid: 0000-0001-5865-1664
29 | affiliation: "2"
30 | - name: Dan Sandiford
31 | orcid: 0000-0002-2207-6837
32 | affiliation: "1"
33 | - name: Rebecca Farrington
34 | orcid: 0000-0002-2594-6965
35 | affiliatioin: "1"
36 | - name: Luke Mondy
37 | orcid: 0000-0001-7779-509X
38 | affiliation: "3"
39 | - name: Claire Mallard
40 | orcid: 0000-0003-2595-2414
41 | affiliation: "3"
42 | - name: Patrice Rey
43 | orcid: 0000-0002-1767-8593
44 | affiliation: "3"
45 | - name: Guillaume Duclaux
46 | orcid: 0000-0002-9512-7252
47 | affiliation: "4"
48 | - name: Owen Kaluza
49 | orcid: 0000-0001-6303-5671
50 | affiliation: "2"
51 | - name: Arijit Laik
52 | orcid: 0000-0002-3484-7985
53 | affiliation: "5"
54 | - name: Sara Morón
55 | orcid: 0000-0002-1270-4377
56 | affiliation: "1"
57 |
58 | affiliations:
59 | - name: School of Earth Science, The University of Melbourne, Melbourne, Australia
60 | index: 1
61 | - name: Monash eResearch Centre, Monash University, Clayton, Australia
62 | index: 2
63 | - name: School of Geosciences, Earthbyte Research Group, The University of Sydney, Australia
64 | index: 3
65 | - name: Laboratoire Géoazur, Université Nice Sophia Antipolis, Nice, France
66 | index: 4
67 | - name: Department of Earth Science, Faculty of Science, Vrije Universiteit, Amsterdam
68 | index: 5
69 |
70 | date: 05 October 2018
71 | bibliography: paper.bib
72 | ---
73 |
74 | # Summary
75 |
76 | The UWGeodynamics module facilitates development of 2D and 3D thermo-mechanical
77 | geodynamic models (Subduction, Rift, Passive Margins, Orogenic systems etc.).
78 | It is designed to be used for research and teaching, and combined the flexibility
79 | of the Underworld Application Programming Interface,
80 | [@Moresi2002, @Moresi2003, @Moresi2007] with a structured workflow.
81 |
82 | Designing geodynamic numerical models can be a daunting task which
83 | often requires good understanding of the numerical code.
84 | UWGeodynamics provides a simple interface with examples to get you started
85 | with development of numerical models. Users can start designing their models without any
86 | pre-existing knowledge of programming. Expert users can easily modify the
87 | framework and adapt it to more specific needs. The code can be run in parallel
88 | on multiple CPUs on personal computers and/or High Performance Computing systems.
89 |
90 | Although UWGeodynamics has been primarily designed to address geodynamic
91 | problems, it can also be used to teach fluid dynamics and material mechanics.
92 |
93 | UWGeodynamics uses the flexibility of the python language and the Jupyter
94 | notebook environment which allows leveraging the wide range of scientific
95 | libraries available from the python community.
96 | It also facilitates the coupling with existing scientific python modules such
97 | as Badlands [@Salles2018].
98 |
99 | The functionalities include:
100 |
101 | - Dimensional input values, using user's choice of physical units.
102 | - Automated and transparent scaling of dimensional values.
103 | - Sets of predefined geometries that can be combined to define the
104 | initial geometry of a model.
105 | - Handles Newtonian and non-Newtonian rheologies (Viscous, Visco-plastic and
106 | Visco-elasto-plastic).
107 | - Database of common rheologies used in geodynamics, which can be
108 | personalised / extended by users.
109 | - Simple definition of kinematic, stress, and thermal boundary conditions.
110 | - Lithostatic pressure calculation.
111 | - Thermal equilibrium (steady-state) calculation.
112 | - Pseudo Isostasy using a range of kinematic or stress boundary conditions.
113 | - Partial melt calculation and associated change in viscosity / heat production.
114 | - Simple definition of passive tracers and grid of tracers.
115 | - Simple Phase changes
116 | - 2 way coupling with the surface processes model pyBadlands [@Salles2018].
117 |
118 | UWGeo comes with a series of examples, benchmarks and tutorials setups that can
119 | be used as cookbook recipes. They also provide a wide range of teaching materials
120 | useful to introduce numerical geodynamic modeling to students.
121 |
122 | New functionalities are constantly added to the code and contributions are more than
123 | welcomed. You can access the full documentation online at https://uwgeodynamics.readthedocs.io
124 |
125 | # Audience
126 |
127 | The module is directed towards a large audience, including earth-science
128 | students, structural geologists, expert numerical geodynamicists and
129 | industry research and development teams. It is used as a research and teaching
130 | tool at the University of Melbourne and the University of Sydney.
131 |
132 | # Acknowledgments
133 |
134 | Development of Underworld / UWGeodynamics is financially supported by AuScope as
135 | part of the Simulation Analysis Modelling platform (SAM).
136 | UWGeodynamics has been developed to assist researchers and students of the
137 | Basin Genesis Hub and their industry partners.
138 |
139 |
140 | # References
141 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy>=1.21
2 | scipy
3 | mpi4py
4 | h5py
5 | pandas
6 | pint
7 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | # This includes the license file(s) in the wheel.
3 | # https://wheel.readthedocs.io/en/stable/user_guide.html#including-license-files-in-the-generated-wheel-file
4 | license_files = LICENSE.md
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 | # To use a consistent encoding
3 | from codecs import open
4 | import os
5 | import subprocess
6 | from os import path
7 | import re
8 |
9 | MAJOR = 2
10 |
11 | MINOR = 12
12 | MICRO = 5
13 |
14 | ISRELEASED = True
15 | VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
16 |
17 | here = path.abspath(path.dirname(__file__))
18 |
19 | # Get the long description from the README file
20 | with open(path.join(here, 'README.md'), encoding='utf-8') as f:
21 | long_description = f.read()
22 |
23 | long_description = re.sub(r"\[image\]\(", "[image](https://raw.githubusercontent.com/underworldcode/UWGeodynamics/master/", long_description)
24 |
25 | # Write the default uwgeodynamics file
26 | with open('docs/uwgeodynamicsrc.template') as fd:
27 | template = fd.read()
28 |
29 | with open('UWGeodynamics/uwgeo-data/uwgeodynamicsrc', 'w') as fd:
30 | fd.write(template)
31 |
32 |
33 | # Return the git revision as a string
34 | def git_version():
35 | def _minimal_ext_cmd(cmd):
36 | # construct minimal environment
37 | env = {}
38 | for k in ['SYSTEMROOT', 'PATH']:
39 | v = os.environ.get(k)
40 | if v is not None:
41 | env[k] = v
42 | # LANGUAGE is used on win32
43 | env['LANGUAGE'] = 'C'
44 | env['LANG'] = 'C'
45 | env['LC_ALL'] = 'C'
46 | out = subprocess.Popen(cmd, stdout = subprocess.PIPE, env=env).communicate()[0]
47 | return out
48 |
49 | try:
50 | out = _minimal_ext_cmd(['git', 'rev-parse', 'HEAD'])
51 | GIT_REVISION = out.strip().decode('ascii')
52 | except OSError:
53 | GIT_REVISION = "Unknown"
54 |
55 | try:
56 | out = _minimal_ext_cmd(['git', 'rev-parse','--abbrev-ref', 'HEAD'])
57 | GIT_BRANCH = out.strip().decode('ascii')
58 | except OSError:
59 | GIT_BRANCH = "Unknown"
60 |
61 | return GIT_REVISION, GIT_BRANCH
62 |
63 | def get_version_info():
64 | # Adding the git rev number needs to be done inside write_version_py(),
65 | # otherwise the import of numpy.version messes up the build under Python 3.
66 | FULLVERSION = VERSION
67 | if os.path.exists('.git'):
68 | GIT_REVISION, GIT_BRANCH = git_version()
69 | elif os.path.exists('UWGeodynamics/version.py'):
70 | # must be a source distribution, use existing version file
71 | try:
72 | from UWGeodynamics.version import git_revision as GIT_REVISION
73 | except ImportError:
74 | raise ImportError("Unable to import git_revision. Try removing " \
75 | "UWGeodynamics/version.py and the build directory " \
76 | "before building.")
77 | try:
78 | from UWGeodynamics.version import git_branch as GIT_BRANCH
79 | except ImportError:
80 | raise ImportError("Unable to import git_branch. Try removing " \
81 | "UWGeodynamics/version.py and the build directory " \
82 | "before building.")
83 | else:
84 | GIT_REVISION = "Unknown"
85 | GIT_BRANCH = "Unknown"
86 |
87 | if not ISRELEASED:
88 | FULLVERSION += "-dev-" + GIT_REVISION[:7] + "(" + GIT_BRANCH + ")"
89 |
90 | return FULLVERSION, GIT_REVISION
91 |
92 | def write_version_py(filename='UWGeodynamics/version.py'):
93 | cnt = """
94 | # THIS FILE IS GENERATED FROM UWGeodynamics SETUP.PY
95 | #
96 | short_version = '%(version)s'
97 | version = '%(version)s'
98 | full_version = '%(full_version)s'
99 | git_revision = '%(git_revision)s'
100 | release = %(isrelease)s
101 |
102 | if not release:
103 | version = full_version
104 | """
105 | FULLVERSION, GIT_REVISION = get_version_info()
106 |
107 | try:
108 | a = open(filename, 'w')
109 | a.write(cnt % {'version': VERSION,
110 | 'full_version': FULLVERSION,
111 | 'git_revision': GIT_REVISION,
112 | 'isrelease': str(ISRELEASED)})
113 | finally:
114 | a.close()
115 |
116 | write_version_py()
117 |
118 | # Arguments marked as "Required" below must be included for upload to PyPI.
119 | # Fields marked as "Optional" may be commented out.
120 |
121 | setup(
122 | # This is the name of your project. The first time you publish this
123 | # package, this name will be registered for you. It will determine how
124 | # users can install this project, e.g.:
125 | #
126 | # $ pip install sampleproject
127 | #
128 | # And where it will live on PyPI: https://pypi.org/project/sampleproject/
129 | #
130 | # There are some restrictions on what makes a valid project name
131 | # specification here:
132 | # https://packaging.python.org/specifications/core-metadata/#name
133 | name='UWGeodynamics', # Required
134 |
135 | # Versions should comply with PEP 440:
136 | # https://www.python.org/dev/peps/pep-0440/
137 | #
138 | # For a discussion on single-sourcing the version across setup.py and the
139 | # project code, see
140 | # https://packaging.python.org/en/latest/single_source_version.html
141 | version=VERSION, # Required
142 |
143 | # This is a one-line description or tagline of what your project does. This
144 | # corresponds to the "Summary" metadata field:
145 | # https://packaging.python.org/specifications/core-metadata/#summary
146 | description='Underworld Geodynamics wrapper', # Required
147 |
148 | # This is an optional longer description of your project that represents
149 | # the body of text which users will see when they visit PyPI.
150 | #
151 | # Often, this is the same as your README, so you can just read it in from
152 | # that file directly (as we have already done above)
153 | #
154 | # This field corresponds to the "Description" metadata field:
155 | # https://packaging.python.org/specifications/core-metadata/#description-optional
156 | long_description=long_description, # Optional
157 | long_description_content_type="text/markdown",
158 |
159 | # This should be a valid link to your project's main homepage.
160 | #
161 | # This field corresponds to the "Home-Page" metadata field:
162 | # https://packaging.python.org/specifications/core-metadata/#home-page-optional
163 | url='https://github.com/rbeucher/UWGeodynamics.git', # Optional
164 |
165 | # This should be your name or the name of the organization which owns the
166 | # project.
167 | author='Romain Beucher', # Optional
168 |
169 | # This should be a valid email address corresponding to the author listed
170 | # above.
171 | author_email='romain.beucher@anu.edu.au', # Optional
172 |
173 | # Classifiers help users find your project by categorizing it.
174 | #
175 | # For a list of valid classifiers, see
176 | # https://pypi.python.org/pypi?%3Aaction=list_classifiers
177 | classifiers=[ # Optional
178 | # How mature is this project? Common values are
179 | # 3 - Alpha
180 | # 4 - Beta
181 | # 5 - Production/Stable
182 | 'Development Status :: 5 - Production/Stable',
183 |
184 | # Indicate who your project is intended for
185 | 'Intended Audience :: Developers',
186 | 'Topic :: Software Development :: Build Tools',
187 |
188 | # Pick your license as you wish (should match "license" above)
189 | 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
190 |
191 | # Specify the Python versions you support here. In particular, ensure
192 | # that you indicate whether you support Python 2, Python 3 or both.
193 | 'Programming Language :: Python :: 3.3',
194 | 'Programming Language :: Python :: 3.4',
195 | 'Programming Language :: Python :: 3.5',
196 | 'Programming Language :: Python :: 3.6',
197 | 'Programming Language :: Python :: 3.7',
198 | 'Programming Language :: Python :: 3.8',
199 | 'Programming Language :: Python :: 3.9',
200 | ],
201 |
202 | # This field adds keywords for your project which will appear on the
203 | # project page. What does your project relate to?
204 | #
205 | # Note that this is a string of words separated by whitespace, not a list.
206 | keywords='geodynamics Underworld geophysics geology', # Optional
207 |
208 | # You can just specify package directories manually here if your project is
209 | # simple. Or you can use find_packages().
210 | #
211 | # Alternatively, if you just want to distribute a single Python file, use
212 | # the `py_modules` argument instead as follows, which will expect a file
213 | # called `my_module.py` to exist:
214 | #
215 | # py_modules=["my_module"],
216 | #
217 | packages=find_packages(exclude=['contrib', 'docs', 'tests']), # Required
218 |
219 | # This field lists other packages that your project depends on to run.
220 | # Any package you put here will be installed by pip when your project is
221 | # installed, so they must be valid existing projects.
222 | #
223 | # For an analysis of "install_requires" vs pip's requirements files see:
224 | # https://packaging.python.org/en/latest/requirements.html
225 | install_requires=['pint', 'numpy', 'scipy'], # Optional
226 |
227 | # List additional groups of dependencies here (e.g. development
228 | # dependencies). Users will be able to install these using the "extras"
229 | # syntax, for example:
230 | #
231 | # $ pip install sampleproject[dev]
232 | #
233 | # Similar to `install_requires` above, these must be valid existing
234 | # projects.
235 | #extras_require={ # Optional
236 | # 'dev': ['check-manifest'],
237 | # 'test': ['coverage'],
238 | #},
239 |
240 | # If there are data files included in your packages that need to be
241 | # installed, specify them here.
242 | #
243 | # If using Python 2.6 or earlier, then these have to be included in
244 | # MANIFEST.in as well.
245 | package_data={
246 | 'UWGeodynamics': ['ressources/*', 'uwgeo-data/*'],
247 | },
248 |
249 | # Although 'package_data' is the preferred approach, in some case you may
250 | # need to place data files outside of your packages. See:
251 | # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files
252 | #
253 | # In this case, 'data_file' will be installed into '/my_data'
254 | # data_files=[('examples', ['./examples/*']),
255 | # ('tutorials', ['./tutorials/*']),
256 | # ('manual', ['./manual/*'])], # Optional
257 |
258 | include_package_data=True,
259 | # To provide executable scripts, use entry points in preference to the
260 | # "scripts" keyword. Entry points provide cross-platform support and allow
261 | # `pip` to create the appropriate form of executable for the target
262 | # platform.
263 | #
264 | # For example, the following would provide a command called `sample` which
265 | # executes the function `main` from this package when invoked:
266 | entry_points={ # Optional
267 | 'console_scripts': [
268 | 'UW_to_ASCII=UWGeodynamics.utilities:main',
269 | ],
270 | },
271 | )
272 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # the inclusion of the tests module is not meant to offer best practices for
2 | # testing in general, but rather to support the `find_packages` example in
3 | # setup.py that excludes installing the "tests" package
4 |
--------------------------------------------------------------------------------
/tests/doctests.py:
--------------------------------------------------------------------------------
1 | import UWGeodynamics as GEO
2 | import pkgutil, doctest, sys
3 | import os
4 | # lets disable metrics for tests
5 | os.environ["UW_NO_USAGE_METRICS"] = "1"
6 | os.environ["DOCTEST"] = "1"
7 |
8 | test_vis = True
9 | try:
10 | import lavavu
11 | except ImportError:
12 | test_vis = False
13 |
14 | for module in [GEO,]:
15 | modIter = pkgutil.walk_packages(path=module.__path__, prefix=module.__name__+'.')
16 |
17 | for itthing, modName, bs in modIter:
18 | mod=sys.modules.get(modName)
19 | if modName.startswith("underworld.visualisation"):
20 | print("Not testing `{}` as `lavavu` not found.".format(modName))
21 | continue
22 | print("Testing "+modName)
23 | res = doctest.testmod(mod)
24 | if res.failed > 0:
25 | raise RuntimeError("Doctest failed")
26 |
--------------------------------------------------------------------------------
/tests/image_tests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import imp
4 | path = os.path.abspath('./image_tests/')
5 |
6 | #Check if the viewer is working
7 | import glucifer
8 | if not glucifer.lavavu:
9 | print("Image tests skipped, Viewer disabled")
10 | exit()
11 |
12 | for d in os.listdir(path):
13 | testd = os.path.join(path,d)
14 | if not os.path.isdir(testd): continue
15 | if str(d)[0] == '.': continue
16 | modfile = os.path.join(path, str(d) + '/runtest.py')
17 | if not os.path.isfile(modfile): continue;
18 | os.chdir(testd)
19 | print("Running tests in " + os.getcwd())
20 | print("===================================================")
21 | #print modfile
22 | testmod = imp.load_source('runtest', modfile)
23 | os.chdir(path)
24 | print("===================================================")
25 |
26 |
--------------------------------------------------------------------------------
/tests/image_tests/examples/1_01_Steady_State_Heat/expected/Figure_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/tests/image_tests/examples/1_01_Steady_State_Heat/expected/Figure_1.png
--------------------------------------------------------------------------------
/tests/image_tests/examples/1_01_Steady_State_Heat/expected/Figure_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/tests/image_tests/examples/1_01_Steady_State_Heat/expected/Figure_2.png
--------------------------------------------------------------------------------
/tests/image_tests/examples/1_02_Convection_Example/expected/Figure_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/tests/image_tests/examples/1_02_Convection_Example/expected/Figure_1.png
--------------------------------------------------------------------------------
/tests/image_tests/examples/1_02_Convection_Example/expected/Figure_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/tests/image_tests/examples/1_02_Convection_Example/expected/Figure_2.png
--------------------------------------------------------------------------------
/tests/image_tests/examples/1_02_Convection_Example/expected/Figure_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/tests/image_tests/examples/1_02_Convection_Example/expected/Figure_3.png
--------------------------------------------------------------------------------
/tests/image_tests/examples/1_25_Hot_Canon_Ball/expected/Figure_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/tests/image_tests/examples/1_25_Hot_Canon_Ball/expected/Figure_1.png
--------------------------------------------------------------------------------
/tests/image_tests/examples/1_25_Hot_Canon_Ball/expected/Figure_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/tests/image_tests/examples/1_25_Hot_Canon_Ball/expected/Figure_2.png
--------------------------------------------------------------------------------
/tests/image_tests/examples/runtest.py:
--------------------------------------------------------------------------------
1 | # This test runs notebooks that produce image output and checks the images against expected output
2 | # coding: utf-8
3 | import underworld as uw
4 | import glucifer
5 | import os
6 | import glob
7 | import subprocess
8 | import shutil
9 |
10 | # Viewer instance for running image tests
11 | lv = glucifer.lavavu.Viewer(quality=1)
12 |
13 | nbdir = "../../../examples/"
14 | files = ['1_01_Steady_State_Heat.ipynb',
15 | '1_02_Convection_Example.ipynb']
16 |
17 | # Save working dir
18 | wd = os.getcwd()
19 |
20 | # Process list of notebooks
21 | for f in files:
22 | fname = os.path.join(nbdir, f)
23 | # Get filename without path and extension
24 | notebook = os.path.splitext(os.path.basename(fname))[0]
25 | print("Testing Notebook: " + notebook)
26 | # Check if the test dir exists, if not create
27 | dirfound = os.path.exists(notebook)
28 | if not dirfound:
29 | print("Creating dirs: " + notebook + '/expected')
30 | os.makedirs(os.path.join(notebook, 'expected'))
31 | # Create log file
32 | outName = notebook + "/convert.out"
33 | with open(outName, "w") as outFile:
34 | # Notebooks must be converted to py before running or images will be generated inline and not saved to disk
35 | subprocess.check_call(['jupyter', 'nbconvert', '--to', 'script', fname, '--output', os.path.join(wd,notebook, notebook)],
36 | stdout=outFile, stderr=outFile )
37 | # Change to working dir for test
38 | os.chdir(notebook)
39 | # Execute converted script
40 | subprocess.check_call(['python', notebook+".py"], stdout=outFile, stderr=outFile )
41 |
42 | # Use output of the initial run as expected data
43 | if not dirfound:
44 | print("Using files created by initial run as expected output for tests")
45 | images = glob.glob("*.png")
46 | for f in images:
47 | shutil.move(f, os.path.join('expected', f))
48 | else:
49 | # Check the image results
50 | if uw.rank() == 0:
51 | lv.testimages(tolerance=1e-3)
52 |
53 | # Restore working dir
54 | os.chdir(wd)
55 |
56 |
--------------------------------------------------------------------------------
/tests/test_benchmarks.py:
--------------------------------------------------------------------------------
1 | # test_benchmark.py
2 |
3 | from .utils import _notebook_run
4 | import pytest
5 | import glob
6 | import ntpath
7 |
8 | scripts = [pytest.param(path, id=ntpath.basename(path)) for path in sorted(glob.glob("docs/benchmarks/*.ipynb"))]
9 |
10 | @pytest.mark.parametrize('script', scripts)
11 | def test_script_execution(script):
12 | _notebook_run(script)
13 |
--------------------------------------------------------------------------------
/tests/test_examples.py:
--------------------------------------------------------------------------------
1 | # test_examples.py
2 |
3 | from .utils import _notebook_run
4 | import pytest
5 | import glob
6 | import ntpath
7 |
8 | scripts = [pytest.param(path, id=ntpath.basename(path)) for path in sorted(glob.glob("docs/examples/*.ipynb"))]
9 |
10 | @pytest.mark.parametrize('script', scripts)
11 | def test_script_execution(script):
12 | _notebook_run(script)
13 |
--------------------------------------------------------------------------------
/tests/test_results/benchmarks/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/tests/test_results/benchmarks/.gitignore
--------------------------------------------------------------------------------
/tests/test_results/examples/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/tests/test_results/examples/.gitignore
--------------------------------------------------------------------------------
/tests/test_results/tutorials/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/underworldcode/UWGeodynamics/20af15e771a69edd301f4d16b8530f21a3b9fe7b/tests/test_results/tutorials/.gitignore
--------------------------------------------------------------------------------
/tests/test_simple.py:
--------------------------------------------------------------------------------
1 | import UWGeodynamics as GEO
2 | import underworld as uw
3 |
4 | u = GEO.u
5 |
6 | Model = GEO.Model()
7 | Model3D = GEO.Model(elementRes=(10, 10, 10),
8 | gravity=(0.,0.,-9.81*u.m/u.s**2),
9 | minCoord=(0. * u.kilometer,
10 | 0. * u.kilometer,
11 | 0. * u.kilometer),
12 | maxCoord=(10. * u.kilometer,
13 | 10. * u.kilometer,
14 | 10. * u.kilometer))
15 |
16 | def test_scaling():
17 |
18 | velocity = 1.0 * u.centimeter / u.hour
19 | model_height = 1. * u.meter
20 | bodyforce = 200 * u.kilogram / u.metre**3 * 9.81 * u.meter / u.second**2
21 | temperature = 1200 * u.degK
22 |
23 | KL = model_height
24 | Kt = KL / velocity
25 | KM = bodyforce * KL**2 * Kt**2
26 | KT = temperature
27 |
28 | GEO.scaling_coefficients["[length]"] = KL
29 | GEO.scaling_coefficients["[time]"] = Kt
30 | GEO.scaling_coefficients["[mass]"] = KM
31 | GEO.scaling_coefficients["[temperature]"] = KT
32 |
33 | def test_adding_materials():
34 | air = Model.add_material(
35 | name="Air",
36 | shape=GEO.shapes.Layer(top=Model.top,
37 | bottom=Model.bottom)
38 | )
39 | assert(isinstance(air, GEO.Material))
40 |
41 | def test_material_attributes():
42 | Material = GEO.Material(name="Material")
43 | Material.density = 3000. * u.kilogram / u.metre**3
44 | Material.viscosity = 1e19 * u.pascal * u.second
45 | Material.diffusivity = 1e-6 * u.metre**2 / u.second
46 | Material.capacity = 1000. * u.joule / (u.kelvin * u.kilogram)
47 | Material.radiogenicHeatProd = 0.7 * u.microwatt / u.metre**3
48 |
49 | def test_viscous_registry():
50 | rh = GEO.ViscousCreepRegistry()
51 | Material = GEO.Material(name="Material")
52 | for name, rheology in rh.__dict__["_dir"].items():
53 | Material.viscosity = rheology
54 |
55 | def test_shapes():
56 |
57 | layer = GEO.shapes.Layer2D(top=30.*u.kilometer, bottom=0.*u.kilometer)
58 | polygon = GEO.shapes.Polygon(vertices=[(10.* u.kilometer, 10.*u.kilometer),
59 | (20.* u.kilometer, 35.*u.kilometer),
60 | (35.* u.kilometer, 5.*u.kilometer)])
61 | box = GEO.shapes.Box(top=10.* u.kilometer, bottom=5*u.kilometer,
62 | minX=10.*u.kilometer, maxX=15*u.kilometer)
63 | disk = GEO.shapes.Disk(center=(32. * u.kilometer, 32. * u.kilometer), radius=10.*u.kilometer)
64 |
65 | annulus = GEO.shapes.Annulus(center=(35.*u.kilometer, 50.*u.kilometer),
66 | r1=5.*u.kilometer,
67 | r2=10.*u.kilometer)
68 |
69 | disk1 = GEO.shapes.Disk(center=(10. * u.kilometer, 10. * u.kilometer), radius=10.*u.kilometer)
70 | disk2 = GEO.shapes.Disk(center=(20. * u.kilometer, 20. * u.kilometer), radius=5.*u.kilometer)
71 |
72 | shape = disk1 | disk2
73 | shape2 = layer | polygon | box | disk | annulus
74 |
75 | material = Model.add_material(name="Material", shape=layer)
76 | material = Model.add_material(name="Material", shape=polygon)
77 | material = Model.add_material(name="Material", shape=box)
78 | material = Model.add_material(name="Material", shape=disk)
79 | material = Model.add_material(name="Material", shape=annulus)
80 | material = Model.add_material(name="Material", shape=shape)
81 | material = Model.add_material(name="Material", shape=shape2)
82 |
83 | def test_plastic_registry():
84 | pl = GEO.PlasticityRegistry()
85 | Material = GEO.Material(name="Material")
86 | for name, rheology in pl.__dict__["_dir"].items():
87 | Material.plasticity = rheology
88 |
89 | def test_set_velocity_boundary_conditions():
90 | velocityBCs = Model.set_velocityBCs(
91 | left=[1.0 * u.centimetre / u.year, None],
92 | right=[-1.0 * u.centimetre / u.year, None],
93 | bottom=[None, 0.],
94 | top=[None, 0.])
95 | assert(isinstance(velocityBCs, uw.conditions.DirichletCondition))
96 |
97 | def test_user_defined_viscous_creep():
98 | viscosity = GEO.ViscousCreep(preExponentialFactor=1.0,
99 | stressExponent=1.0,
100 | activationVolume=0.,
101 | activationEnergy=200 * u.kilojoules,
102 | waterFugacity=0.0,
103 | grainSize=0.0,
104 | meltFraction=0.,
105 | grainSizeExponent=0.,
106 | waterFugacityExponent=0.,
107 | meltFractionFactor=0.0,
108 | f=1.0)
109 | assert(isinstance(viscosity, GEO.ViscousCreep))
110 |
111 | def test_user_defined_drucker_prager():
112 | plasticity = GEO.DruckerPrager(cohesion=10. * u.megapascal,
113 | cohesionAfterSoftening=10. * u.megapascal,
114 | frictionCoefficient = 0.3,
115 | frictionAfterSoftening = 0.2,
116 | epsilon1=0.5,
117 | epsilon2=1.5)
118 | assert(isinstance(plasticity, GEO.DruckerPrager))
119 |
120 | def test_temperature_boundary_condition():
121 | Model.set_temperatureBCs(top=500. * u.degK,
122 | bottom=1000. * u.degK)
123 | Model.capacity = 1000. * u.joule / (u.kelvin * u.kilogram)
124 | Model.density = 1000. * u.kilogram / u.metre**3
125 | Model.set_temperatureBCs(top=500. * u.degK,
126 | bottom=1200. * u.degK)
127 |
128 | def test_passive_tracers():
129 | import numpy as np
130 | npoints = 1000
131 | coords = np.ndarray((1000, 2))
132 | coords[:, 0] = np.linspace(GEO.nd(Model.minCoord[0]), GEO.nd(Model.maxCoord[0]), npoints)
133 | coords[:, 1] = GEO.nd(32. * u.kilometer)
134 | Model.add_passive_tracers(name="Tracers", vertices=coords)
135 |
136 | def test_set_velocity_boundary_conditions_in_3D():
137 | velocityBCs = Model3D.set_velocityBCs(
138 | left=[1.0 * u.centimetre / u.year, None, 0.],
139 | right=[-1.0 * u.centimetre / u.year, None, 0.],
140 | bottom=[None, None, 0.],
141 | top=[None, None, 0.],
142 | front=[None, 0., None],
143 | back=[None, 0., None])
144 | assert(isinstance(velocityBCs, uw.conditions.DirichletCondition))
145 |
--------------------------------------------------------------------------------
/tests/test_tutorials.py:
--------------------------------------------------------------------------------
1 | # test_tutorials.py
2 |
3 | from .utils import _notebook_run
4 | import pytest
5 | import glob
6 | import ntpath
7 |
8 | scripts = [pytest.param(path, id=ntpath.basename(path)) for path in sorted(glob.glob("docs/tutorials/*.ipynb")) if "Badlands" not in path]
9 |
10 | @pytest.mark.parametrize('script', scripts)
11 | def test_script_execution(script):
12 | _notebook_run(script)
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tests/utils.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 | from shutil import copyfile
3 | import os
4 | import json
5 |
6 |
7 | def _check_setup_only(nb):
8 | # Remove all cells after and including "run_for"
9 | val = None
10 | data = json.load(open(nb, "r"))
11 | for index, cell in enumerate(data["cells"]):
12 | for line in cell["source"]:
13 | if "Model.run_for" in line:
14 | val = index
15 | if val:
16 | data["cells"] = data["cells"][:val]
17 | with open(nb, "w") as f:
18 | json.dump(data, f)
19 |
20 | def _notebook_run(script, check_setup_only=True):
21 |
22 | outpath = script.replace(".ipynb", "_out.ipynb" )
23 | copyfile(script, outpath)
24 |
25 | if check_setup_only:
26 | _check_setup_only(outpath)
27 |
28 | args = ["jupyter", "nbconvert",
29 | "--to", "python", outpath]
30 | subprocess.check_call(args)
31 |
32 | pyfile = outpath.split(".")[0] + ".py"
33 | os.remove(outpath)
34 | args = ["python", pyfile]
35 | subprocess.check_call(args)
36 | os.remove(pyfile)
37 |
38 |
39 |
--------------------------------------------------------------------------------