initialize new template with Groningen reservoir model as example

master
GMG Contributors 2024-07-29 18:39:03 +00:00
commit e814b8ff9f
11 changed files with 1631 additions and 0 deletions

190
.gitignore vendored Normal file
View File

@ -0,0 +1,190 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

438
environment.yml Normal file
View File

@ -0,0 +1,438 @@
name: flow2quake
channels:
- conda-forge
- defaults
dependencies:
- _libgcc_mutex=0.1=conda_forge
- _openmp_mutex=4.5=2_kmp_llvm
- _sysroot_linux-64_curr_repodata_hack=3=h69a702a_16
- aiohttp=3.9.5=py310h2372a71_0
- aiosignal=1.3.1=pyhd8ed1ab_0
- alsa-lib=1.2.12=h4ab18f5_0
- anyio=4.4.0=pyhd8ed1ab_0
- aom=3.6.1=h59595ed_0
- argon2-cffi=23.1.0=pyhd8ed1ab_0
- argon2-cffi-bindings=21.2.0=py310h2372a71_4
- arrow=1.3.0=pyhd8ed1ab_0
- arviz=0.12.1=pyhd8ed1ab_1
- astropy=6.1.0=py310h8a78493_0
- astropy-iers-data=0.2024.7.22.0.34.13=pyhd8ed1ab_0
- asttokens=2.4.1=pyhd8ed1ab_0
- async-lru=2.0.4=pyhd8ed1ab_0
- async-timeout=4.0.3=pyhd8ed1ab_0
- attr=2.5.1=h166bdaf_1
- attrs=23.2.0=pyh71513ae_0
- babel=2.14.0=pyhd8ed1ab_0
- beautifulsoup4=4.12.3=pyha770c72_0
- binutils=2.39=hdd6e379_1
- binutils_impl_linux-64=2.39=he00db2b_1
- binutils_linux-64=2.39=h5fc0e48_13
- black=24.4.2=py310hff52083_0
- bleach=6.1.0=pyhd8ed1ab_0
- blosc=1.21.5=hc2324a3_1
- boost-cpp=1.78.0=h2c5509c_4
- brotli=1.1.0=hd590300_1
- brotli-bin=1.1.0=hd590300_1
- brotli-python=1.1.0=py310hc6cd4ac_1
- bzip2=1.0.8=h4bc722e_7
- c-ares=1.32.3=h4bc722e_0
- c-compiler=1.5.1=h166bdaf_0
- ca-certificates=2024.7.4=hbcca054_0
- cached-property=1.5.2=hd8ed1ab_1
- cached_property=1.5.2=pyha770c72_1
- cachetools=5.4.0=pyhd8ed1ab_0
- cairo=1.18.0=h3faef2a_0
- certifi=2024.7.4=pyhd8ed1ab_0
- cffi=1.16.0=py310h2fee648_0
- cftime=1.6.4=py310h261611a_0
- charset-normalizer=3.3.2=pyhd8ed1ab_0
- click=8.1.7=unix_pyh707e725_0
- cmake=3.29.4=h91dbaaa_0
- colorama=0.4.6=pyhd8ed1ab_0
- comm=0.2.2=pyhd8ed1ab_0
- contourpy=1.2.1=py310hd41b1e2_0
- coolprop=6.4.1=py310hd8f1fbe_7
- curl=8.8.0=he654da7_1
- cxx-compiler=1.5.1=h924138e_0
- cycler=0.12.1=pyhd8ed1ab_0
- dav1d=1.2.1=hd590300_0
- dbus=1.13.6=h5008d03_3
- debugpy=1.8.2=py310h76e45a6_0
- decorator=5.1.1=pyhd8ed1ab_0
- defusedxml=0.7.1=pyhd8ed1ab_0
- dill=0.3.8=pyhd8ed1ab_0
- double-conversion=3.2.0=h27087fc_1
- eigen=3.4.0=h00ab1b0_0
- entrypoints=0.4=pyhd8ed1ab_0
- exceptiongroup=1.2.2=pyhd8ed1ab_0
- executing=2.0.1=pyhd8ed1ab_0
- expat=2.6.2=h59595ed_0
- fastprogress=1.0.3=pyhd8ed1ab_0
- fenics-dijitso=2019.1.0=pyhd8ed1ab_39
- fenics-dolfin=2019.1.0=py310h17b16a0_34
- fenics-ffc=2019.1.0=pyhd8ed1ab_39
- fenics-fiat=2019.1.0=pyhd8ed1ab_39
- fenics-libdolfin=2019.1.0=h0f808bc_34
- fenics-ufl=2019.1.0=py310hff52083_38
- ffmpeg=5.1.2=gpl_hf01f75b_112
- fftw=3.3.10=mpi_mpich_h5537406_7
- filelock=3.15.4=pyhd8ed1ab_0
- font-ttf-dejavu-sans-mono=2.37=hab24e00_0
- font-ttf-inconsolata=3.000=h77eed37_0
- font-ttf-source-code-pro=2.038=h77eed37_0
- font-ttf-ubuntu=0.83=h77eed37_2
- fontconfig=2.14.2=h14ed4e7_0
- fonts-conda-ecosystem=1=0
- fonts-conda-forge=1=0
- fonttools=4.53.1=py310h5b4e0ec_0
- fqdn=1.5.1=pyhd8ed1ab_0
- freetype=2.12.1=h267a509_2
- fribidi=1.0.10=h36c2ea0_0
- frozenlist=1.4.1=py310h2372a71_0
- fsspec=2024.6.1=pyhff2d567_0
- gcc=10.4.0=hb92f740_13
- gcc_impl_linux-64=10.4.0=h5231bdf_19
- gcc_linux-64=10.4.0=h9215b83_13
- geos=3.12.2=he02047a_1
- gettext=0.22.5=h59595ed_2
- gettext-tools=0.22.5=h59595ed_2
- gl2ps=1.4.2=h0708190_0
- glew=2.1.0=h9c3ff4c_2
- glib=2.80.2=hf974151_0
- glib-tools=2.80.2=hb6ce0ca_0
- gmp=6.3.0=hac33072_2
- gmpy2=2.1.5=py310hc7909c9_1
- gnutls=3.7.9=hb077bed_0
- graphite2=1.3.13=h59595ed_1003
- gst-plugins-base=1.22.9=hfa15dee_1
- gstreamer=1.22.9=h98fc4e7_1
- gxx=10.4.0=hb92f740_13
- gxx_impl_linux-64=10.4.0=h5231bdf_19
- gxx_linux-64=10.4.0=h6e491c6_13
- h11=0.14.0=pyhd8ed1ab_0
- h2=4.1.0=pyhd8ed1ab_0
- harfbuzz=8.5.0=hfac3d4d_0
- hdf4=4.2.15=h501b40f_6
- hdf5=1.12.2=mpi_mpich_h5d83325_1
- hpack=4.0.0=pyh9f0ad1d_0
- httpcore=1.0.5=pyhd8ed1ab_0
- httpx=0.27.0=pyhd8ed1ab_0
- hyperframe=6.0.1=pyhd8ed1ab_0
- hypre=2.25.0=mpi_mpich_hed3a557_0
- icu=73.2=h59595ed_0
- idna=3.7=pyhd8ed1ab_0
- importlib-metadata=8.2.0=pyha770c72_0
- importlib_metadata=8.2.0=hd8ed1ab_0
- importlib_resources=6.4.0=pyhd8ed1ab_0
- intel-openmp=2022.0.1=h06a4308_3633
- ipykernel=6.29.5=pyh3099207_0
- ipython=8.26.0=pyh707e725_0
- ipywidgets=8.1.3=pyhd8ed1ab_0
- isoduration=20.11.0=pyhd8ed1ab_0
- jedi=0.19.1=pyhd8ed1ab_0
- jinja2=3.1.4=pyhd8ed1ab_0
- json5=0.9.25=pyhd8ed1ab_0
- jsoncpp=1.9.5=h4bd325d_1
- jsonpointer=3.0.0=py310hff52083_0
- jsonschema=4.23.0=pyhd8ed1ab_0
- jsonschema-specifications=2023.12.1=pyhd8ed1ab_0
- jsonschema-with-format-nongpl=4.23.0=hd8ed1ab_0
- jupyter=1.0.0=pyhd8ed1ab_10
- jupyter-lsp=2.2.5=pyhd8ed1ab_0
- jupyter_client=8.6.2=pyhd8ed1ab_0
- jupyter_console=6.6.3=pyhd8ed1ab_0
- jupyter_core=5.7.2=py310hff52083_0
- jupyter_events=0.10.0=pyhd8ed1ab_0
- jupyter_server=2.14.2=pyhd8ed1ab_0
- jupyter_server_terminals=0.5.3=pyhd8ed1ab_0
- jupyterlab=4.2.4=pyhd8ed1ab_0
- jupyterlab_pygments=0.3.0=pyhd8ed1ab_1
- jupyterlab_server=2.27.3=pyhd8ed1ab_0
- jupyterlab_widgets=3.0.11=pyhd8ed1ab_0
- kernel-headers_linux-64=3.10.0=h4a8ded7_16
- keyutils=1.6.1=h166bdaf_0
- kiwisolver=1.4.5=py310hd41b1e2_1
- krb5=1.21.3=h659f571_0
- lame=3.100=h166bdaf_1003
- lcms2=2.15=haa2dc70_1
- ld_impl_linux-64=2.39=hcc3a1bd_1
- lerc=4.0.0=h27087fc_0
- libabseil=20240116.2=cxx17_he02047a_1
- libaec=1.1.3=h59595ed_0
- libasprintf=0.22.5=h661eb56_2
- libasprintf-devel=0.22.5=h661eb56_2
- libass=0.17.1=h8fe9dca_1
- libblas=3.9.0=20_linux64_openblas
- libbrotlicommon=1.1.0=hd590300_1
- libbrotlidec=1.1.0=hd590300_1
- libbrotlienc=1.1.0=hd590300_1
- libcap=2.69=h0f662aa_0
- libcblas=3.9.0=20_linux64_openblas
- libclang=15.0.7=default_h127d8a8_5
- libclang-cpp15=15.0.7=default_h127d8a8_5
- libclang13=15.0.7=default_h5d6823c_5
- libcups=2.3.3=h4637d8d_4
- libcurl=8.8.0=hca28451_1
- libdeflate=1.18=h0b41bf4_0
- libdrm=2.4.122=h4ab18f5_0
- libedit=3.1.20191231=he28a2e2_2
- libev=4.33=hd590300_2
- libevent=2.1.12=hf998b51_1
- libexpat=2.6.2=h59595ed_0
- libffi=3.4.2=h7f98852_5
- libflac=1.4.3=h59595ed_0
- libgcc-devel_linux-64=10.4.0=hd38fd1e_19
- libgcc-ng=14.1.0=h77fa898_0
- libgcrypt=1.11.0=h4ab18f5_1
- libgettextpo=0.22.5=h59595ed_2
- libgettextpo-devel=0.22.5=h59595ed_2
- libgfortran-ng=14.1.0=h69a702a_0
- libgfortran5=14.1.0=hc5f4f2c_0
- libglib=2.80.2=hf974151_0
- libglu=9.0.0=hac7e632_1003
- libgomp=14.1.0=h77fa898_0
- libgpg-error=1.50=h4f305b6_0
- libgpuarray=0.7.6=h7f98852_1003
- libhwloc=2.11.1=default_hecaa2ac_1000
- libiconv=1.17=hd590300_2
- libidn2=2.3.7=hd590300_0
- libjpeg-turbo=2.1.5.1=hd590300_1
- liblapack=3.9.0=20_linux64_openblas
- libllvm15=15.0.7=hb3ce162_4
- libllvm18=18.1.7=hb77312f_0
- libnetcdf=4.9.1=mpi_mpich_h5eb6f38_2
- libnghttp2=1.58.0=h47da74e_1
- libnsl=2.0.1=hd590300_0
- libogg=1.3.5=h4ab18f5_0
- libopenblas=0.3.25=pthreads_h413a1c8_0
- libopus=1.3.1=h7f98852_1
- libpciaccess=0.18=hd590300_0
- libpng=1.6.43=h2797004_0
- libpq=15.7=h088ca5b_0
- libprotobuf=4.25.3=h08a7969_0
- libsanitizer=10.4.0=h5246dfb_19
- libsndfile=1.2.2=hc60ed4a_1
- libsodium=1.0.18=h36c2ea0_1
- libsqlite=3.46.0=hde9e2c9_0
- libssh2=1.11.0=h0841786_0
- libstdcxx-devel_linux-64=10.4.0=hd38fd1e_19
- libstdcxx-ng=14.1.0=hc0a3c3a_0
- libsystemd0=255=h3516f8a_1
- libtasn1=4.19.0=h166bdaf_0
- libtheora=1.1.1=h4ab18f5_1006
- libtiff=4.5.1=h8b53f26_1
- libtorch=2.3.1=cpu_mkl_h0bb0d08_100
- libunistring=0.9.10=h7f98852_0
- libuuid=2.38.1=h0b41bf4_0
- libuv=1.48.0=hd590300_0
- libva=2.21.0=h4ab18f5_2
- libvorbis=1.3.7=h9c3ff4c_0
- libvpx=1.13.1=h59595ed_0
- libwebp-base=1.4.0=hd590300_0
- libxcb=1.15=h0b41bf4_0
- libxkbcommon=1.7.0=h662e7e4_0
- libxml2=2.12.7=hc051c1a_1
- libzip=1.10.1=h2629f0a_3
- libzlib=1.2.13=h4ab18f5_6
- llvm-openmp=18.1.7=ha31de31_0
- loguru=0.7.2=py310hff52083_1
- lz4-c=1.9.4=hcb278e6_0
- mako=1.3.5=pyhd8ed1ab_0
- markupsafe=2.1.5=py310h2372a71_0
- matplotlib=3.8.4=py310hff52083_2
- matplotlib-base=3.8.4=py310hef631a5_2
- matplotlib-inline=0.1.7=pyhd8ed1ab_0
- metis=5.1.0=h59595ed_1007
- mistune=3.0.2=pyhd8ed1ab_0
- mkl=2023.2.0=h84fe81f_50496
- mkl-service=2.4.1=py310hc72dfd8_0
- mpc=1.3.1=hfe3b2da_0
- mpfr=4.2.1=h9458935_1
- mpg123=1.32.6=h59595ed_0
- mpi=1.0=mpich
- mpi4py=3.1.4=py310h37cc914_0
- mpich=4.0.3=h846660c_100
- mpmath=1.3.0=pyhd8ed1ab_0
- msgpack-python=1.0.8=py310h25c7140_0
- mshr=2019.1.0=py310ha64120c_7
- multidict=6.0.5=py310h2372a71_0
- mumps-include=5.2.1=ha770c72_11
- mumps-mpi=5.2.1=h7ee95aa_11
- munkres=1.1.4=pyh9f0ad1d_0
- mypy_extensions=1.0.0=pyha770c72_0
- mysql-common=8.0.33=hf1915f5_6
- mysql-libs=8.0.33=hca2cd23_6
- nbclient=0.10.0=pyhd8ed1ab_0
- nbconvert=7.16.4=hd8ed1ab_1
- nbconvert-core=7.16.4=pyhd8ed1ab_1
- nbconvert-pandoc=7.16.4=hd8ed1ab_1
- nbformat=5.10.4=pyhd8ed1ab_0
- ncurses=6.5=h59595ed_0
- nest-asyncio=1.6.0=pyhd8ed1ab_0
- netcdf4=1.6.3=nompi_py310h0feb132_100
- nettle=3.9.1=h7ab15ed_0
- networkx=3.2=pyhd8ed1ab_0
- nlohmann_json=3.11.3=h59595ed_0
- notebook=7.2.1=pyhd8ed1ab_0
- notebook-shim=0.2.4=pyhd8ed1ab_0
- nspr=4.35=h27087fc_0
- nss=3.100=hca3bf56_0
- numpy=1.22.4=py310h4ef5377_0
- openh264=2.3.1=hcb278e6_2
- openjpeg=2.5.0=hfec8fc6_2
- openssl=3.3.1=h4bc722e_2
- overrides=7.7.0=pyhd8ed1ab_0
- p11-kit=0.24.1=hc5aa10d_0
- packaging=24.1=pyhd8ed1ab_0
- pandas=2.2.2=py310hf9f9076_1
- pandoc=3.2.1=ha770c72_0
- pandocfilters=1.5.0=pyhd8ed1ab_0
- parmetis=4.0.3=h2a9763c_1005
- parso=0.8.4=pyhd8ed1ab_0
- pathspec=0.12.1=pyhd8ed1ab_0
- patsy=0.5.6=pyhd8ed1ab_0
- pcre2=10.43=hcad00b1_0
- petsc=3.17.4=real_h15390b8_101
- petsc4py=3.17.4=real_hce8fbc3_101
- pexpect=4.9.0=pyhd8ed1ab_0
- pickleshare=0.7.5=py_1003
- pillow=10.0.0=py310h582fbeb_0
- pip=24.0=pyhd8ed1ab_0
- pixman=0.43.2=h59595ed_0
- pkg-config=0.29.2=h4bc722e_1009
- pkgconfig=1.5.5=pyhd8ed1ab_4
- pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1
- platformdirs=4.2.2=pyhd8ed1ab_0
- ply=3.11=pyhd8ed1ab_2
- proj=9.1.1=h8ffa02c_2
- prometheus_client=0.20.0=pyhd8ed1ab_0
- prompt-toolkit=3.0.47=pyha770c72_0
- prompt_toolkit=3.0.47=hd8ed1ab_0
- psutil=6.0.0=py310hc51659f_0
- pthread-stubs=0.4=h36c2ea0_1001
- ptscotch=6.0.9=hb499603_2
- ptyprocess=0.7.0=pyhd3deb0d_0
- pugixml=1.11.4=h59595ed_1
- pulseaudio-client=16.1=hb77b528_5
- pure_eval=0.2.3=pyhd8ed1ab_0
- pybind11=2.10.1=py310hbf28c38_0
- pybind11-global=2.10.1=py310hbf28c38_0
- pycparser=2.22=pyhd8ed1ab_0
- pyerfa=2.0.1.4=py310h261611a_1
- pygments=2.18.0=pyhd8ed1ab_0
- pygpu=0.7.6=py310h96516ba_1003
- pymc3=3.11.2=pyh4f5629e_2
- pyparsing=3.1.2=pyhd8ed1ab_0
- pyqt=5.15.9=py310h04931ad_5
- pyqt5-sip=12.12.2=py310hc6cd4ac_5
- pysocks=1.7.1=pyha2e5f31_6
- python=3.10.0=h543edf9_3_cpython
- python-dateutil=2.9.0=pyhd8ed1ab_0
- python-fastjsonschema=2.20.0=pyhd8ed1ab_0
- python-json-logger=2.0.7=pyhd8ed1ab_0
- python-tzdata=2024.1=pyhd8ed1ab_0
- python_abi=3.10=4_cp310
- pytorch=2.3.1=cpu_mkl_py310h75865b9_100
- pytz=2024.1=pyhd8ed1ab_0
- pyyaml=6.0.1=py310h2372a71_1
- pyzmq=26.0.3=py310h6883aea_0
- qhull=2020.2=h434a139_5
- qt-main=5.15.8=hc47bfe8_16
- qtconsole-base=5.5.2=pyha770c72_0
- qtpy=2.4.1=pyhd8ed1ab_0
- readline=8.2=h8228510_1
- referencing=0.35.1=pyhd8ed1ab_0
- requests=2.32.3=pyhd8ed1ab_0
- rfc3339-validator=0.1.4=pyhd8ed1ab_0
- rfc3986-validator=0.1.1=pyh9f0ad1d_0
- rhash=1.4.4=hd590300_0
- rpds-py=0.19.1=py310h42e942d_0
- scalapack=2.2.0=hd931219_1
- scipy=1.7.3=py310hdfbd76f_1
- scotch=6.0.9=hb2e6521_2
- seaborn=0.13.2=hd8ed1ab_2
- seaborn-base=0.13.2=pyhd8ed1ab_2
- semver=3.0.2=pyhd8ed1ab_0
- send2trash=1.8.3=pyh0d859eb_0
- setuptools=71.0.4=pyhd8ed1ab_0
- shapely=2.0.5=py310h019a838_0
- sip=6.7.12=py310hc6cd4ac_0
- six=1.16.0=pyh6c4a22f_0
- sleef=3.6.1=h3400bea_1
- slepc=3.17.2=real_hb19a63e_100
- slepc4py=3.17.2=real_h45d0737_101
- snappy=1.2.1=ha2e4443_0
- sniffio=1.3.1=pyhd8ed1ab_0
- soupsieve=2.5=pyhd8ed1ab_1
- sqlite=3.46.0=h6d4b2fc_0
- stack_data=0.6.2=pyhd8ed1ab_0
- statsmodels=0.14.1=py310h1f7b6fc_0
- suitesparse=5.10.1=h5a4f163_3
- superlu=5.2.2=h00795ac_0
- superlu_dist=7.2.0=h25dcc4a_0
- svt-av1=1.4.1=hcb278e6_0
- sympy=1.13.0=pypyh2585a3b_103
- sysroot_linux-64=2.17=h4a8ded7_16
- tbb=2021.12.0=h434a139_3
- tbb-devel=2021.12.0=hfcbfbdb_3
- terminado=0.18.1=pyh0d859eb_0
- theano=1.0.5=py310hd8f1fbe_3
- theano-pymc=1.1.2=py310h00e6091_0
- tinycss2=1.3.0=pyhd8ed1ab_0
- tk=8.6.13=noxft_h4845f30_101
- toml=0.10.2=pyhd8ed1ab_0
- tomli=2.0.1=pyhd8ed1ab_0
- tornado=6.4.1=py310hc51659f_0
- tqdm=4.66.4=pyhd8ed1ab_0
- traitlets=5.14.3=pyhd8ed1ab_0
- types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0
- typing-extensions=4.12.2=hd8ed1ab_0
- typing_extensions=4.12.2=pyha770c72_0
- typing_utils=0.1.0=pyhd8ed1ab_0
- tzdata=2024a=h0c530f3_0
- unicodedata2=15.1.0=py310h2372a71_0
- uri-template=1.3.0=pyhd8ed1ab_0
- urllib3=2.2.2=pyhd8ed1ab_1
- utfcpp=4.0.5=ha770c72_0
- vtk=9.2.6=qt_py310h2e23b3e_201
- wcwidth=0.2.13=pyhd8ed1ab_0
- webcolors=24.6.0=pyhd8ed1ab_0
- webencodings=0.5.1=pyhd8ed1ab_2
- websocket-client=1.8.0=pyhd8ed1ab_0
- wheel=0.43.0=pyhd8ed1ab_1
- widgetsnbextension=4.0.11=pyhd8ed1ab_0
- wslink=2.1.1=pyhd8ed1ab_0
- x264=1!164.3095=h166bdaf_2
- x265=3.5=h924138e_3
- xarray=2023.7.0=pyhd8ed1ab_0
- xarray-einstats=0.6.0=pyhd8ed1ab_0
- xcb-util=0.4.0=hd590300_1
- xcb-util-image=0.4.0=h8ee46fc_1
- xcb-util-keysyms=0.4.0=h8ee46fc_1
- xcb-util-renderutil=0.3.9=hd590300_1
- xcb-util-wm=0.4.1=h8ee46fc_1
- xkeyboard-config=2.42=h4ab18f5_0
- xorg-fixesproto=5.0=h7f98852_1002
- xorg-kbproto=1.0.7=h7f98852_1002
- xorg-libice=1.1.1=hd590300_0
- xorg-libsm=1.2.4=h7391055_0
- xorg-libx11=1.8.9=h8ee46fc_0
- xorg-libxau=1.0.11=hd590300_0
- xorg-libxdmcp=1.1.3=h7f98852_0
- xorg-libxext=1.3.4=h0b41bf4_2
- xorg-libxfixes=5.0.3=h7f98852_1004
- xorg-libxrender=0.9.11=hd590300_0
- xorg-libxt=1.3.0=hd590300_1
- xorg-renderproto=0.11.1=h7f98852_1002
- xorg-xextproto=7.3.0=h0b41bf4_1003
- xorg-xf86vidmodeproto=2.3.1=h7f98852_1002
- xorg-xproto=7.0.31=h7f98852_1007
- xz=5.2.6=h166bdaf_0
- yaml=0.2.5=h7f98852_2
- yarl=1.9.4=py310h2372a71_0
- zeromq=4.3.5=h75354e8_4
- zipp=3.19.2=pyhd8ed1ab_0
- zlib=1.2.13=h4ab18f5_6
- zstandard=0.23.0=py310h64cae3c_0
- zstd=1.5.6=ha6fb4c9_0
prefix: /home/michael/miniconda3/envs/flow2quake

0
flow2quake/__init__.py Normal file
View File

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,78 @@
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
def UpdateGasExtractionData(
GasData_file="./Data/WellInformation.npy",
winter="ColdWinter",
Excel_file="../../Workshop2021/UpdatedData/Gaswinning-maandelijks_2010_2022.xlsx",
Extrapolate_increase=False,
plot_YN=False):
"""
Updates gas extraction data from an Excel file and optionally extrapolates values.
Args:
GasData_file (str): Path to the existing gas data file.
winter (str): Specifies the winter type to use ('ColdWinter', 'AverageWinter', or 'HotWinter').
Excel_file (str): Path to the Excel file containing updated data.
Extrapolate_increase (bool): If True, extrapolates data beyond the last available date.
plot_YN (bool): If True, generates a plot to visualize the updated data.
Returns:
pd.DataFrame: Updated gas extraction data.
"""
# Load updated data from Excel file
# For this to work, the second column of the file Gaswinning-maandelijks needs to contain the updated well clusters acronyms
a = pd.read_excel(Excel_file)
names1 = a[a.columns[0]][:-2]
names2 = a[a.columns[1]][:-2]
data = a[a.columns[2:-1]][:-2].T
data.columns = names2
idx = [type(data.index[ii]) != str for ii in range(len(data.index))]
data = data[idx]
# Load existing gas data
GasData = np.load(GasData_file, allow_pickle=True).item()
# Find matching indices for data alignment
idx0 = np.argmin(abs(GasData["Date"] - data.index[0]))
idx1 = np.argmin(abs(GasData["Date"] - data.index[-1]))
# Update gas extraction data
df1 = GasData[winter].copy()
df1.iloc[idx0:idx1 + 1] = 0 # Clear existing data in the specified range
for col in data.columns:
df1[col].iloc[idx0:idx1 + 1] = data[col] # Insert updated data
# Extrapolate data if requested
if Extrapolate_increase:
df1.iloc[idx1 + 1 :] = df1.iloc[500 : 500 + len(df1.iloc[idx1 + 1 :])]
# Generate plot to check consistency (if requested)
if plot_YN:
fig, ax = plt.subplots(1, 1, figsize=(15, 10))
for scenario in ["HotWinter", "AverageWinter", "ColdWinter"]:
GasData[scenario].sum(axis=1).plot(
x=GasData["Date"], ax=ax, ls="--", label=scenario
)
df1.sum(axis=1).plot(x=GasData["Date"], ax=ax, label="Corrected data")
ax.axvline(x=idx1 + 1, c="r", ls="-.", label="End of data")
ax.legend()
ax.set_xlabel("Month since 1956")
ax.set_ylabel("Total gas extraction")
return df1
import os
def file_exists(file_path):
"""
Checks if a file exists at the specified path.
Args:
file_path (str): The path to the file to check.
Returns:
bool: True if the file exists, False otherwise.
"""
# Use the os.path.isfile function to determine if the file exists
return os.path.isfile(file_path)

View File

@ -0,0 +1,284 @@
import numpy as np
import pandas as pd
from fenics import *
from scipy import signal
from mshr import *
class DiffusionModel:
"""A class that computes the pressure depletion inside a reservoir given
its physical properties (boundaries,thickness,permeability,porosity,
temperature,initial pressure), the gas compositon (or Molar Weight)
and the spatial and temporal parameters (grid,timestep and
extracted volume)"""
def __init__(self,
x: np.ndarray,
y: np.ndarray,
thickness: np.ndarray,
temperature: int,
initial_pressure: float,
gas_molecular_weight: float,
num_steps: int,
time_step: float,
extraction_data: pd.DataFrame,
wells: np.ndarray,
outline: pd.DataFrame,
p_new_init: np.ndarray = None,
begin: int = 0,
name: str = 'DiffusionModel'):
"""
Initializes the reservoir model with invariant parameters.
"""
# Model name and settings:
self.name = name
self.begin = begin
# Input data:
self.x_meshgrid = x
self.y_meshgrid = y
self.outline = outline
self.reservoir_temperature = temperature # In Kelvin
self.gas_molecular_weight = gas_molecular_weight # In kg/mol
self.pressure_new_init = p_new_init
self.extraction_data = extraction_data
self.wells = wells
# Mesh dimensions:
self.dim_x = self.x_meshgrid.shape[0] - 1
self.dim_y = self.x_meshgrid.shape[1] - 1
# Time parameters:
self.step_number = num_steps # Number of time steps in months
self.d_t = time_step # Duration of a time step in seconds
# Derived constants:
self.d_rho = (self.gas_molecular_weight / (8.314 * self.reservoir_temperature)) * 1e6 / 3600**2 # dρ/dp
self.rho_std_condition = self.rho(101325 * 1e-6, 293.25) # Density in kg/m³
# Create rectangular mesh for thickness:
self.mesh = RectangleMesh(Point(self.x_meshgrid[0, 0], self.y_meshgrid[0, 0]),
Point(self.x_meshgrid[-1, 0], self.y_meshgrid[0, -1]),
self.dim_x, self.dim_y)
self.w = FunctionSpace(self.mesh, 'CG', 1)
self.coordinates = self.mesh.coordinates()
self.intermediate_thickness = self.array_2d_to_fenics(thickness, 1e-6)
# Create triangle mesh for flexibility:
mesh_x = signal.resample(self.outline[2], 500)[::-1]
mesh_y = signal.resample(self.outline[3], 500)[::-1]
structure = [Point(x, y) for x, y in zip(mesh_x, mesh_y)]
domain = Polygon(structure)
self.mesh2 = generate_mesh(domain, 40)
self.v = FunctionSpace(self.mesh2, 'CG', 1)
self.coordinates2_ = self.mesh2.coordinates()
# Interpolate thickness onto triangle mesh:
self.thickness = Function(self.v)
self.thickness.interpolate(self.intermediate_thickness)
# Define initial pressure on the mesh:
self.initial_pressure = interpolate(Constant(initial_pressure), self.v)
def array_2d_to_fenics(self, numpy_2d_array: np.ndarray, error_avoir_number: float = None) -> Function:
"""
Converts a 2D NumPy array to a Fenics array, handling potential errors and adjusting for mesh layout.
Args:
numpy_2d_array: The 2D NumPy array to convert.
error_avoir_number: An optional value to add to all elements of the array for error mitigation.
Returns:
The converted Fenics array.
"""
# Handle potential errors:
numpy_2d_array = np.nan_to_num(numpy_2d_array) # Replace NaNs with numerical values
# Transpose the array to match Fenics mesh layout:
numpy_2d_array = numpy_2d_array.T
# Flatten the array for assignment to Fenics function:
numpy_array = numpy_2d_array.reshape((self.dim_x + 1) * (self.dim_y + 1))
# Add error mitigation value if specified:
if error_avoir_number is not None:
numpy_array = numpy_array + np.ones_like(numpy_array) * error_avoir_number
# Create the Fenics function and assign values:
fenics_array = Function(self.w)
fenics_array.vector()[:] = numpy_array[dof_to_vertex_map(self.w)]
return fenics_array
def array_1d_to_fenics(self, numpy_1d_array: np.ndarray, error_avoid_number: float = None) -> Function:
"""
Converts a 1D NumPy array to a Fenics array, optionally adding a value to all elements for error mitigation.
Args:
numpy_1d_array: The 1D NumPy array to convert.
error_avoid_number: An optional value to add to all elements of the array for error mitigation.
Returns:
The converted Fenics array.
"""
# Add error mitigation value if specified:
if error_avoid_number is not None:
numpy_1d_array = numpy_1d_array + np.ones_like(numpy_1d_array) * error_avoid_number
# Create the Fenics function and assign values:
fenics_array = Function(self.v)
fenics_array.vector()[:] = numpy_1d_array[dof_to_vertex_map(self.v)]
return fenics_array
def rho(self,
p,
temperature: float = None):
"""Function that computes the density of a gas given the molecular
weight of the gas, its pressure, and its temperature
If no temperature is given, Temperature of Reservoir is by default
Pressure given in MPa, result in kg.km-3"""
if temperature is None:
return p*1e6 * self.gas_molecular_weight / \
(8.314 * self.reservoir_temperature) *1e9#dim change change2
return p*1e6 * self.gas_molecular_weight / (8.314 * temperature) *1e9 #dim change change2
def viscosity(self, p):
"""Compute the viscosity of a gas given its density.
Empirical Formula from LeeGonzalez Semiempirical Method (1966)
!!!!!!!Constants are set for Groningen parameters, they need
to be changed if another case study!!!!!!!!"""
vertex_values = p.compute_vertex_values(self.mesh2)
rho_vertex = self.rho(vertex_values) / 1000 / 1e9 #pressure change : *(1e9*3600**2), change2
viscosity = 137.071e-4 * np.exp(5.094 * rho_vertex **1.314) / 1000 * 1000*3600 #dim change 1e9 et 1000*3600
fenics_viscosity = self.array_1d_to_fenics(viscosity)
return fenics_viscosity
def distance(self, array: np.ndarray, x: float, y: float):
"""
Determines the index, distance, and coordinates of the point in the given array that is closest to a target point.
Args:
array: A 2D NumPy array of coordinates, where each row represents a point.
x: The x-coordinate of the target point.
y: The y-coordinate of the target point.
Returns:
- The index of the closest point in the array.
- The distance between the target point and the closest point.
- The x-coordinate of the closest point.
- The y-coordinate of the closest point.
"""
closest_index = None
closest_distance = float('inf') # Initialize with positive infinity
closest_x = None
closest_y = None
for i, (point_x, point_y) in enumerate(array):
distance_to_point = np.sqrt((x - point_x)**2 + (y - point_y)**2)
if distance_to_point < closest_distance:
closest_index = i
closest_distance = distance_to_point
closest_x = point_x
closest_y = point_y
return closest_index, closest_distance, closest_x, closest_y
def well_pressure_difference(self,
measurements_data: pd.DataFrame):
"""
Calculates the total absolute difference between measured well pressures and calculated pressures
at the closest points on the grid, as well as the number of valid measurements used.
Args:
measurements_data: A pandas DataFrame containing well pressure measurements.
Returns:
A tuple containing:
- The total absolute well pressure difference.
- The number of valid measurements used in the calculation.
"""
# Find the indices of the closest grid points to each well:
location = np.zeros(self.wells.shape[0])
for k in range(self.wells.shape[0]):
location[k] = self.distance(self.coordinates2_, int(Well[k][1]), int(Well[k][2]))[0]
# Initialize variables for calculating the difference:
well_difference = 0
well_nb_measurements = 0
# Determine the maximum number of time steps to consider:
IHM = min(self.step_number, len(measurements_data))
# Iterate through time steps and wells:
for T in range(self.begin, IHM):
for i in range(self.wells.shape[0]):
# Check if the measurement is valid:
if np.isfinite(measurements_data[self.wells[i][0]][T]):
# Calculate the absolute difference between measured and calculated pressures:
difference = abs(
measurements_data[self.wells[i][0]][T] - self.PArray_[int(location[i]), T]
)
well_difference += difference
well_nb_measurements += 1
return well_difference, well_nb_measurements
def diffusion_process_for_control(self,
permeability: float,
porosity: float,
gassat: float,
instantaneous_pressure: np.ndarray,
instantaneous_extraction_data: np.ndarray):
"""
Computes the diffusion model for a single iteration, given specific parameters
and instantaneous pressure and extraction data. Returns the pressure field at time t+1.
"""
# Initialize pressure array:
self.PArray_ = np.zeros((self.coordinates2_.shape[0], self.step_number))
# Set parameters and trial/test functions:
permeability_fenics = Constant(permeability)
self.permeability_ = interpolate(permeability_fenics, self.v)
p = TrialFunction(self.v)
p0i = self.array_1d_to_fenics(instantaneous_pressure)
p0 = interpolate(p0i, self.v)
v = TestFunction(self.v)
# Define variational problem for pressure:
a = ((porosity * self.d_rho * self.thickness) * p * (1e9 * 3600**2) * v * dx
+ (self.d_t * self.thickness * self.permeability_
/ self.viscosity(p0)) * dot(self.rho(p0) * grad(p * (1e9 * 3600**2)), grad(v)) * dx)
L = ((porosity * self.d_rho * self.thickness) * p0 * (1e9 * 3600**2) * v * dx)
# Define point sources for extraction:
point_sources = []
for i in range(self.wells.shape[0]):
extraction_rate = -instantaneous_extraction_data[self.wells[i][0]] # Convert to positive
point_sources.append((Point(float(self.wells[i][1]), float(self.wells[i][2])),
extraction_rate * self.d_t * self.rho_std_condition / gassat * 1e-9))
ps = PointSource(self.v, point_sources)
# Assemble and solve the system:
b = assemble(L)
A = assemble(a)
ps.apply(b)
self.p1_ = Function(self.v)
self.p1_.assign(p0)
solver = KrylovSolver('minres', 'hypre_euclid')
solver.parameters["maximum_iterations"] = 1000
solver.parameters["error_on_nonconvergence"] = False # Set to True for debugging
solver.solve(A, self.p1_.vector(), b)
# Extract vertex values and return:
self.vertex_values_P_ = self.p1_.compute_vertex_values(self.mesh2)
return self.vertex_values_P_

View File

@ -0,0 +1,53 @@
import numpy as np
import pandas as pd
def create_well_configuration(well_configuration, Well, GasData):
"""
Creates well configuration data based on the specified configuration type.
Args:
well_configuration (int): The type of well configuration to create.
Well (np.ndarray): Array containing well data for Groningen real wells.
GasData (pd.DataFrame): DataFrame containing gas data for Groningen wells.
Returns:
tuple: (wells_names, wells_locations, Well, initial_extraction_data)
"""
wells_list = [] # List to store well information
if well_configuration == 1: # Unique well
wells_names = ['Unique well']
wells_locations = np.array([[252.500, 587.500]])
initial_extraction_rate = [4e8 / (30.4375 * 24)] # m3/hour
elif well_configuration == 2: # Two wells (north and south)
wells_names = ['Extraction well', 'Injection well']
wells_locations = np.array([[260.000, 575.000], [245.000, 600.000]])
initial_extraction_rate = [4e8 / (30.4375 * 24), -4e8 / (30.4375 * 24)]
elif well_configuration == 5: # Five wells (central and surrounding)
wells_names = ['Constant well', 'Variable well up_right', 'Variable well up_left',
'Variable well down_left', 'Variable well down_right']
wells_locations = np.array([[252.500, 587.500],
[257.500, 592.500], [247.500, 592.500],
[247.500, 582.500], [257.500, 582.500]])
initial_extraction_rate = [8e8 / (30.4375 * 24)] * 5
elif well_configuration == 29: # Groningen real wells
wells_names = [Well[i, 0] for i in range(Well.shape[0])]
wells_locations = np.array([[float(Well[i, 1]) / 1000, float(Well[i, 2]) / 1000]
for i in range(Well.shape[0])])
historic_extraction = np.nan_to_num(GasData['AverageWinter'].fillna(0).rolling(1).mean().to_numpy()) / (30.4375 * 24)
initial_extraction_rate = historic_extraction[300, :].tolist() # Extraction rate of a random month
else:
print('Wrong well_configuration')
return None
# Create the Well array directly using list comprehension
Well = np.array([[name, str(loc[0]), str(loc[1])] for name, loc in zip(wells_names, wells_locations)])
initial_extraction_data = pd.Series(data=initial_extraction_rate, index=wells_names)
return wells_names, wells_locations, Well, initial_extraction_data

View File

View File

@ -0,0 +1,3 @@
"""
Geomechanical deformation functions
"""

View File

View File