diff --git a/.github/.devcontainer/DOCKERFILE_GHCS b/.github/.devcontainer/DOCKERFILE_GHCS index 058f0a32..10bd9d74 100644 --- a/.github/.devcontainer/DOCKERFILE_GHCS +++ b/.github/.devcontainer/DOCKERFILE_GHCS @@ -4,8 +4,8 @@ RUN conda install -n base -c conda-forge mamba # Here we can install all the dependencies using mamba (as we do in the test scripts) -COPY .devcontainer/uw_environment.yml /tmp/conda-tmp/ -RUN mamba env update -n base --file /tmp/conda-tmp/uw_environment.yml +COPY .devcontainer/uw_environment.yaml /tmp/conda-tmp/ +RUN mamba env update -n base --file /tmp/conda-tmp/uw_environment.yaml # Add other dependencies that can't be installed correctly. diff --git a/.github/.devcontainer/uw_environment.yaml b/.github/.devcontainer/uw_environment.yaml new file mode 120000 index 00000000..8dc54858 --- /dev/null +++ b/.github/.devcontainer/uw_environment.yaml @@ -0,0 +1 @@ +../../environment.yaml \ No newline at end of file diff --git a/.github/.devcontainer/uw_environment.yml b/.github/.devcontainer/uw_environment.yml deleted file mode 120000 index 70c7a446..00000000 --- a/.github/.devcontainer/uw_environment.yml +++ /dev/null @@ -1 +0,0 @@ -../../environment.yml \ No newline at end of file diff --git a/.github/workflows/build_deploy_pdoc.yml b/.github/workflows/build_deploy_pdoc.yaml similarity index 97% rename from .github/workflows/build_deploy_pdoc.yml rename to .github/workflows/build_deploy_pdoc.yaml index db2ea076..6641fadd 100644 --- a/.github/workflows/build_deploy_pdoc.yml +++ b/.github/workflows/build_deploy_pdoc.yaml @@ -21,7 +21,7 @@ jobs: - name: Install Conda environment with Micromamba uses: mamba-org/setup-micromamba@v2 with: - environment-file: ./environment.yml + environment-file: ./environment.yaml cache-downloads: true cache-environment: true diff --git a/.github/workflows/build_uw3_and_test.yml b/.github/workflows/build_uw3_and_test.yaml similarity index 95% rename from .github/workflows/build_uw3_and_test.yml rename to .github/workflows/build_uw3_and_test.yaml index 8c0ba18d..775461a2 100644 --- a/.github/workflows/build_uw3_and_test.yml +++ b/.github/workflows/build_uw3_and_test.yaml @@ -23,7 +23,7 @@ jobs: - name: Install Conda environment with Micromamba uses: mamba-org/setup-micromamba@v2 with: - environment-file: ./environment.yml + environment-file: ./environment.yaml cache-downloads: true cache-environment: true diff --git a/.github/workflows/deploy_to_gh_pages.yml.disabled b/.github/workflows/deploy_to_gh_pages.yml.disabled index e9ed4222..f1ec801a 100644 --- a/.github/workflows/deploy_to_gh_pages.yml.disabled +++ b/.github/workflows/deploy_to_gh_pages.yml.disabled @@ -34,7 +34,7 @@ jobs: - name: Cache book files uses: actions/cache@v1 env: - # Increase this value to reset cache if etc/example-environment.yml has not changed + # Increase this value to reset cache if etc/example-environment.yaml has not changed CACHE_NUMBER: 0 with: path: | diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yaml similarity index 100% rename from .github/workflows/docker-image.yml rename to .github/workflows/docker-image.yaml diff --git a/.github/workflows/draft-pdf.yml b/.github/workflows/draft-pdf.yaml similarity index 100% rename from .github/workflows/draft-pdf.yml rename to .github/workflows/draft-pdf.yaml diff --git a/.github/workflows/envs/build_jb.yml b/.github/workflows/envs/build_jb.yaml similarity index 100% rename from .github/workflows/envs/build_jb.yml rename to .github/workflows/envs/build_jb.yaml diff --git a/.github/workflows/envs/build_quickstart.yml b/.github/workflows/envs/build_quickstart.yaml similarity index 100% rename from .github/workflows/envs/build_quickstart.yml rename to .github/workflows/envs/build_quickstart.yaml diff --git a/.github/workflows/envs/build_uw_docs.yaml b/.github/workflows/envs/build_uw_docs.yaml new file mode 120000 index 00000000..0f9ae9cc --- /dev/null +++ b/.github/workflows/envs/build_uw_docs.yaml @@ -0,0 +1 @@ +../../../environment.yaml \ No newline at end of file diff --git a/.github/workflows/envs/build_uw_docs.yml b/.github/workflows/envs/build_uw_docs.yml deleted file mode 120000 index 7ed7a3b7..00000000 --- a/.github/workflows/envs/build_uw_docs.yml +++ /dev/null @@ -1 +0,0 @@ -../../../environment.yml \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yaml similarity index 96% rename from .github/workflows/publish.yml rename to .github/workflows/publish.yaml index be260e01..e53126a3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yaml @@ -22,8 +22,8 @@ jobs: uses: mamba-org/setup-micromamba@v2 with: #micromamba-version: "1.5.6-0" # any version from https://github.com/mamba-org/micromamba-releases - #environment-file: .github/workflows/envs/build_quickstart.yml - environment-file: ./environment.yml + #environment-file: .github/workflows/envs/build_quickstart.yaml + environment-file: ./environment.yaml init-shell: bash cache-environment: true post-cleanup: "all" diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index b0032458..00000000 --- a/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -# syntax=docker/dockerfile:1.7-labs - -### how to build docker image - -# (1) run from the underworld3 top directory -# podman build . \ -# --rm \ -# -f ./.github/Dockerfile \ -# --format docker \ -# -t underworldcode/underworld3:0.99 - -### needs the --format tag to run on podman - -FROM docker.io/mambaorg/micromamba:2.3.0 - -USER $MAMBA_USER -ENV NB_HOME=/home/$MAMBA_USER - -# create the env -COPY --chown=$MAMBA_USER:$MAMBA_USER environment.yml /tmp/env.yaml -RUN micromamba install -y -n base -f /tmp/env.yaml && \ - micromamba clean --all --yes - -# activate mamba env during `docker build` -ARG MAMBA_DOCKERFILE_ACTIVATE=1 - -# install UW3 -WORKDIR /tmp -COPY --exclude=**/.git \ - --chown=$MAMBA_USER:$MAMBA_USER \ - . /tmp/underworld3 -WORKDIR /tmp/underworld3 - -RUN pip install --no-build-isolation --no-cache-dir . - -# copy files across -RUN mkdir -p $NB_HOME/workspace - -COPY --chown=$MAMBA_USER:$MAMBA_USER ./tests $NB_HOME/Underworld/tests - -EXPOSE 8888 -WORKDIR $NB_HOME -USER $MAMBA_USER - -# Declare a volume space -VOLUME $NB_HOME/workspace - -CMD ["jupyter-lab", "--no-browser", "--ip=0.0.0.0"] diff --git a/README.md b/README.md index 600a681a..2fa74f61 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,13 @@ The quickest option is **not to install** anything but try the binder demo above If do you want to install the code on your own machine, we recommend using `miniconda` and `mamba`. Create a separate virtual environment and install the code from source. More details on how to do that are in the [Installation Instructions](https://underworldcode.github.io/underworld3/development/_quickstart/Installation.html) -## References +## References and Archives The canonical releases of the code can be found at [zenodo.org](https://doi.org/10.5281/zenodo.16810746). [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.16810747.svg)](https://doi.org/10.5281/zenodo.16810746) +There is a [publication in the Journal of Open Source Software](https://joss.theoj.org/papers/4f7a1ed76bde560968c246fa8eff778d) +([doi:10.21105/joss.07831](https://doi.org/10.21105/joss.07831)) that can be cited when using the software. + +[![status](https://joss.theoj.org/papers/4f7a1ed76bde560968c246fa8eff778d/status.svg)](https://joss.theoj.org/papers/4f7a1ed76bde560968c246fa8eff778d) diff --git a/docs/developer/container/Containerfile b/docs/developer/container/Containerfile new file mode 100644 index 00000000..3e4b1816 --- /dev/null +++ b/docs/developer/container/Containerfile @@ -0,0 +1,59 @@ +# syntax=docker/dockerfile:1.7-labs + +### how to build Underworld3 image +### MUST run from the underworld3 top directory +# podman build . --rm \ +# --format docker \ +# -f ./docs/developer/container/Containerfile \ +# -t underworldcode/underworld3: +# +### requires the '--format docker' to run on podman, but no under docker. +# +# +### Example usage (taken from - https://jupyter-docker-stacks.readthedocs.io/en/latest/using/running.html#using-the-podman-cli ) +# uid=57439 +# gid=57439 + +# subuidSize=$(( $(podman info --format "{{ range .Host.IDMappings.UIDMap }}+{{.Size }}{{end }}" ) - 1 )) +# subgidSize=$(( $(podman info --format "{{ range .Host.IDMappings.GIDMap }}+{{.Size }}{{end }}" ) - 1 )) +# podman run -it --rm -p 10000:8888 -v "${HOME}/uw_space":/home/mambauser/host --uidmap $uid:0:1 --uidmap 0:1:$uid --uidmap $(($uid+1)):$(($uid+1)):$(($subuidSize-$uid)) --gidmap $gid:0:1 --gidmap 0:1:$gid --gidmap $(($gid+1)):$(($gid+1)):$(($subgidSize-$gid)) underworldcode/underworld3: + +FROM docker.io/mambaorg/micromamba:2.3.0 + +# install os requirements for headless pyvista +USER root +RUN apt-get update && apt-get install -y --no-install-recommends \ + xvfb \ + libgl1-mesa-dev \ + && rm -rf /var/lib/apt/lists/* +USER $MAMBA_USER + +# create the conda environment with all dependencies +# see https://micromamba-docker.readthedocs.io/en/latest/quick_start.html#quick-start +COPY --chown=$MAMBA_USER:$MAMBA_USER environment.yaml /tmp/env.yaml +RUN micromamba install -y -v -n base -f /tmp/env.yaml && \ + micromamba clean --all --yes + +# activate mamba env during podman build +ARG MAMBA_DOCKERFILE_ACTIVATE=1 + +# pyvista - taken from pyvista docker files +# see https://github.com/pyvista/pyvista/tree/main/docker +RUN pip install --no-cache-dir --extra-index-url https://wheels.vtk.org vtk-osmesa + +# install UW3 +COPY --chown=$MAMBA_USER:$MAMBA_USER \ + --exclude=**/.git \ + . /home/$MAMBA_USER/underworld3 +WORKDIR /home/$MAMBA_USER/underworld3 +RUN pip install --no-build-isolation --no-cache-dir . + +# allow jupyterlab for ipyvtk +ENV PYVISTA_OFF_SCREEN=true +ENV JUPYTER_ENABLE_LAB=yes +ENV PYVISTA_TRAME_SERVER_PROXY_PREFIX='/proxy/' + +WORKDIR /home/$MAMBA_USER/ + +EXPOSE 8888 +CMD ["jupyter-lab", "--no-browser", "--ip=0.0.0.0"] diff --git a/docs/developer/container/README.md b/docs/developer/container/README.md new file mode 100644 index 00000000..6d7a7788 --- /dev/null +++ b/docs/developer/container/README.md @@ -0,0 +1,22 @@ +The `Containerfile` is used to build the container and can be used with docker or podman. +At present only amd64 architecture is built, because vtk-osmesa isn't available for arm by default. This may change in future, or we could build vtk-osmesa from source (see https://docs.pyvista.org/extras/building_vtk.html) + +Example use, must be run from repository root. +```bash + podman build . --rm \ + --format docker \ + -f ./docs/developer/container/Containerfile \ + -t underworldcode/underworld3:foobar +``` + +The `launch-container.sh` is a script for launching the container using `podman` only. Podman is the preferred container runner because of `rootless` support. +Expect the script to take a minute or so to load as permissions are updated. +Host port 10000 will run the container's default jupyter server. See script for details. + +Useful links: +- Container stacks with podman - https://jupyter-docker-stacks.readthedocs.io/en/latest/using/running.html#using-the-podman-cli +- Micromamba images - https://micromamba-docker.readthedocs.io/en/latest/quick_start.html#quick-start +- Pyvista containers: + - https://github.com/pyvista/pyvista/tree/main/docker + - https://dev.pyvista.org/getting-started/installation#running-on-mybinder + diff --git a/docs/developer/container/launch-container.sh b/docs/developer/container/launch-container.sh new file mode 100755 index 00000000..3d2015a4 --- /dev/null +++ b/docs/developer/container/launch-container.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +### Used for running the underworld3 container. +# This requires 'podman', not docker. Install podman from +# https://podman.io/docs/installation +# +# Once podman is installed and available on the command line, run with +# ./launch-container.sh +# +# this will launch a container with a jupyter server running on +# http://localhost:10000 +# Also, the machine (host) directory +# $HOME/uw_space +# will be mapped into the container under /home/mambauser/host. +# for transfering data to/from the container. +# +## + +set -x + +# check to see if $HOME/uw_space exists, if not create it +mkdir -p $HOME/uw_space + +# Set 'mambauser' uid/gid from base image, 'mambaorg/micromamba' +uid=57439 +gid=57439 + +subuidSize=$(( $(podman info --format "{{ range .Host.IDMappings.UIDMap }}+{{.Size }}{{end }}" ) - 1 )) +subgidSize=$(( $(podman info --format "{{ range .Host.IDMappings.GIDMap }}+{{.Size }}{{end }}" ) - 1 )) + +# This will set an jupyter server on HOST port 10000 +# the uidmap / gidmap make the container UID compatible with the host system. +# DO NOT run the following command with root, this is explain further below. +podman run -it --rm \ + -p 10000:8888 \ + --uidmap $uid:0:1 \ + --uidmap 0:1:$uid \ + --uidmap $(($uid+1)):$(($uid+1)):$(($subuidSize-$uid)) \ + --gidmap $gid:0:1 \ + --gidmap 0:1:$gid \ + --gidmap $(($gid+1)):$(($gid+1)):$((subgidSize-$gid)) \ + -v "${HOME}/uw_space":/home/mambauser/host \ + docker.io/underworldcode/underworld3:development + +## Description of rootless podman and uidmap/gidmap. +# Rootless podman allows a non-root user to run a container without elevated permissions. +# DO NOT use `sudo` to execute the above `podman run` command +# This is unlike rootful podman, or docker, thus it's more secure but has some complexity in the for of permission namespaces +# the host and container permissions are elegantly 'namespaced' to two id mappings. +# 1. host ids -> intermediate (/etc/subuid) +# 2. intermediate -> container ids (uidmaps arguments) +# +# In the above `podman run` we set uidmaps to allow for straight forward container / host directory bindmounts +# container UID 57439 -> host UID 0 (if podman rootless this is host UID) +# container UID 0-57438 -> host UID 1-57439 +# container UID 57440-delta -> host UID 57440-delta +# as the container would have root accesson the host. +# The $uid -> host UID 0 assumes podman "rootless" access, i.e. the host UID executing the container. +# All other UIDs in the container are mapped to something different. +# +# This **MUST** be run without sudo, otherwise the host UID would be root. diff --git a/docs/developer/docker/underworld3.dockerfile b/docs/developer/docker/underworld3.dockerfile deleted file mode 100644 index 8209e23d..00000000 --- a/docs/developer/docker/underworld3.dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -### how to build docker image - -# (1) run from the underworld3 top directory -# podman build . \ -# --rm \ -# -f ./docs/developer/docker/underworld3.dockerfile \ -# --format docker \ -# -t underworldcode/underworld3:0.9.9 - -### needs the --format tag to run on podman - -FROM docker.io/mambaorg/micromamba:debian11-slim - - -USER $MAMBA_USER -ENV NB_HOME=/home/$MAMBA_USER - -### create the env -COPY --chown=$MAMBA_USER:$MAMBA_USER environment.yml /tmp/env.yaml -RUN micromamba install -y -n base -f /tmp/env.yaml && \ - micromamba clean --all --yes - -# ### activate env and install -ARG MAMBA_DOCKERFILE_ACTIVATE=1 - - -# ### install UW3 -WORKDIR /tmp -COPY --chown=$MAMBA_USER:$MAMBA_USER . /tmp/underworld3 -WORKDIR /tmp/underworld3 - -### install uw3 using pip -RUN pip install --no-build-isolation . - -#### copy files across -RUN mkdir -p $NB_HOME/workspace - -COPY --chown=$MAMBA_USER:$MAMBA_USER ./tests $NB_HOME/Underworld/tests - -EXPOSE 8888 -WORKDIR $NB_HOME -USER $MAMBA_USER - -# Declare a volume space -VOLUME $NB_HOME/workspace - -CMD ["jupyter-lab", "--no-browser", "--ip='0.0.0.0'"] diff --git a/docs/user/Installation.qmd b/docs/user/Installation.qmd index a66fa443..f9e34afa 100644 --- a/docs/user/Installation.qmd +++ b/docs/user/Installation.qmd @@ -17,7 +17,7 @@ The `underworld3` build / run-time dependencies can be installed using ```bash (base) % git clone -b development --single-branch https://github.com/underworldcode/underworld3 /path/to/underworld3 (base) % cd /path/to/underworld3 - (base) % mamba env create -n uw3 -f environment.yml + (base) % mamba env create -n uw3 -f environment.yaml (base) % mamba activate uw3 (uw3) % compile.sh @@ -32,7 +32,7 @@ installed `PETSc` and `petsc4py`. ```bash (base) % git clone -b development --single-branch https://github.com/underworldcode/underworld3 /path/to/underworld3 (base) % cd /path/to/underworld3 - (base) % mamba env create -n uw3p -f environment.yml + (base) % mamba env create -n uw3p -f environment.yaml (base) % mamba activate uw3p (uw3p) % mamba remove petsc4py diff --git a/docs/user/_quarto.yml b/docs/user/_quarto.yaml similarity index 100% rename from docs/user/_quarto.yml rename to docs/user/_quarto.yaml diff --git a/environment.yml b/environment.yaml similarity index 64% rename from environment.yml rename to environment.yaml index 68e641dc..ea6b02b8 100644 --- a/environment.yml +++ b/environment.yaml @@ -2,7 +2,7 @@ name: uw3 channels: - conda-forge dependencies: - - python=3.11 + - python <= 3.11 - compilers - mpich - petsc=3.21.5 @@ -19,21 +19,25 @@ dependencies: - ipython - mpi4py - h5py=*=mpi* - - trame - - ipywidgets - gmsh - python-gmsh - python-xxhash - - jupyterlab - jupytext - - trame-vtk - - trame-vuetify - pygments - pint + - cmocean + - colorcet + - imageio + - imageio-ffmpeg + - ipywidgets<9.0.0 + - jupyter-server-proxy + - jupyterlab<5.0.0 + - trame>=2.5.2 + - trame-vtk>=2.5.8 + - trame-vuetify>=2.3.1 + - trimesh - typeguard - pip - pip: - rich<14 - meshio - - pygmsh - # - gmsh-api # is this used still in UW? diff --git a/src/underworld3/ckdtree.pyx b/src/underworld3/ckdtree.pyx index 34adb24e..cb3252f9 100644 --- a/src/underworld3/ckdtree.pyx +++ b/src/underworld3/ckdtree.pyx @@ -215,9 +215,9 @@ cdef class KDTree: i = i.reshape(-1) if sqr_dists: - return numpy.sqrt(d), i - else: return d, i + else: + return numpy.sqrt(d), i ## A general point-to-point rbf interpolator here diff --git a/src/underworld3/cython/petsc_generic_snes_solvers.pyx b/src/underworld3/cython/petsc_generic_snes_solvers.pyx index a2070f00..b42b1668 100644 --- a/src/underworld3/cython/petsc_generic_snes_solvers.pyx +++ b/src/underworld3/cython/petsc_generic_snes_solvers.pyx @@ -700,7 +700,7 @@ class SNES_Scalar(SolverBaseClass): print(" - field: {}".format(bc.f_id)) print(" - components: {}".format(bc.components)) print(" - boundary: {}".format(bc.boundary)) - print(" - fn: {} ".format(bc.fn)) + print(" - fn: {} ".format(bc.fn_f)) boundary = bc.boundary value = mesh.boundaries[bc.boundary].value @@ -846,38 +846,39 @@ class SNES_Scalar(SolverBaseClass): # continue if bc.fn_f is not None: - + bd_F0 = sympy.Array(bc.fn_f) - self._bd_f0 = sympy.ImmutableDenseMatrix(bd_F0) - - G0 = sympy.derive_by_array(self._bd_f0, U) - G1 = sympy.derive_by_array(self._bd_f0, self.Unknowns.L) + bc.fns["u_f0"] = sympy.ImmutableDenseMatrix(bd_F0) + + G0 = sympy.derive_by_array(bd_F0, U) + G1 = sympy.derive_by_array(bd_F0, L) - self._bd_G0 = sympy.ImmutableMatrix(G0) # sympy.ImmutableMatrix(sympy.permutedims(G0, permutation).reshape(dim,dim)) - self._bd_G1 = sympy.ImmutableMatrix(G1.reshape(dim)) # sympy.ImmutableMatrix(sympy.permutedims(G1, permutation).reshape(dim,dim*dim)) + bc.fns["uu_G0"] = sympy.ImmutableMatrix(G0.reshape(1, 1)) + bc.fns["uu_G1"] = sympy.ImmutableMatrix(G1.reshape(dim, 1)) - fns_bd_residual += [self._bd_f0] - fns_bd_jacobian += [self._bd_G0, self._bd_G1] + fns_bd_residual += [bc.fns["u_f0"]] + fns_bd_jacobian += [bc.fns["uu_G0"], bc.fns["uu_G1"]] + # Similar to SNES_Vector, will leave these out for now, perhaps a different user-interface altogether is required for flux-like bcs - if bc.fn_F is not None: + # if bc.fn_F is not None: - bd_F1 = sympy.Array(bc.fn_F).reshape(dim) - self._bd_f1 = sympy.ImmutableDenseMatrix(bd_F1) + # bd_F1 = sympy.Array(bc.fn_F).reshape(dim) + # self._bd_f1 = sympy.ImmutableDenseMatrix(bd_F1) - G2 = sympy.derive_by_array(self._bd_f1, U) - G3 = sympy.derive_by_array(self._bd_f1, self.Unknowns.L) + # G2 = sympy.derive_by_array(self._bd_f1, U) + # G3 = sympy.derive_by_array(self._bd_f1, self.Unknowns.L) - self._bd_uu_G2 = sympy.ImmutableMatrix(G2.reshape(dim)) # sympy.ImmutableMatrix(sympy.permutedims(G2, permutation).reshape(dim*dim,dim)) - self._bd_uu_G3 = sympy.ImmutableMatrix(G3.reshape(dim,dim)) # sympy.ImmutableMatrix(sympy.permutedims(G3, permutation).reshape(dim*dim,dim*dim)) + # self._bd_uu_G2 = sympy.ImmutableMatrix(G2.reshape(dim)) # sympy.ImmutableMatrix(sympy.permutedims(G2, permutation).reshape(dim*dim,dim)) + # self._bd_uu_G3 = sympy.ImmutableMatrix(G3.reshape(dim,dim)) # sympy.ImmutableMatrix(sympy.permutedims(G3, permutation).reshape(dim*dim,dim*dim)) - fns_bd_residual += [self._bd_f1] - fns_bd_jacobian += [self._bd_G2, self._bd_G3] + # fns_bd_residual += [self._bd_f1] + # fns_bd_jacobian += [self._bd_G2, self._bd_G3] self._fns_bd_residual = fns_bd_residual self._fns_bd_jacobian = fns_bd_jacobian - + # generate JIT code. # first, we must specify the primary fields. # these are fields for which the corresponding sympy functions @@ -1284,7 +1285,7 @@ class SNES_Vector(SolverBaseClass): print(" - field: {}".format(bc.f_id)) print(" - component: {}".format(bc.components)) print(" - boundary: {}".format(bc.boundary)) - print(" - fn: {} ".format(bc.fn)) + print(" - fn: {} ".format(bc.fn_f)) boundary = bc.boundary value = mesh.boundaries[bc.boundary].value diff --git a/tests/test_1000_poissonNaturalBC.py b/tests/test_1000_poissonNaturalBC.py new file mode 100644 index 00000000..a3bb7e9c --- /dev/null +++ b/tests/test_1000_poissonNaturalBC.py @@ -0,0 +1,77 @@ +import pytest +import underworld3 as uw +import sympy +import numpy as np + +''' +Unit test for Natural BCs in a Poisson (scalar) problem. +''' + +res = 16 + +width = 1 +height = 1 + +minX, maxX = 0, width +minY, maxY = 0, height + +mesh_simp_reg = uw.meshing.UnstructuredSimplexBox( minCoords = (minX, minY), + maxCoords = (maxX, maxY), + cellSize = 1 / res, + qdegree = 3, + regular = True) +mesh_simp_irreg = uw.meshing.UnstructuredSimplexBox(minCoords = (minX, minY), + maxCoords =(maxX, maxY), + cellSize = 1 / res, + regular = False) +mesh_quad = uw.meshing.StructuredQuadBox(minCoords = (minX, minY), + maxCoords = (maxX, maxY), + elementRes = (res, res)) + +@pytest.mark.parametrize("mesh", + [mesh_simp_reg, + mesh_simp_irreg, + mesh_quad] +) + +def test_poisson_natural_bc(mesh): + + T_soln = uw.discretisation.MeshVariable("T", mesh, 1, degree = 2) + + poisson = uw.systems.Poisson(mesh = mesh, + u_Field = T_soln, + degree = 2, + verbose = False, + ) + + poisson.constitutive_model = uw.constitutive_models.DiffusionModel + poisson.constitutive_model.Parameters.diffusivity = 1.0 + poisson.petsc_options.delValue("ksp_monitor") + + # set the source based on analytical solution + x, y = mesh.N.x, mesh.N.y + ana_soln = (x**2) * y + + #poisson.tolerance = 1e-6 # increase tolerance to decrease atol in allclose + poisson.f = -2 * y + + poisson.add_natural_bc(0.0, "Left") + poisson.add_natural_bc([2*y], "Right") + poisson.add_natural_bc([x**2], "Bottom") + poisson.add_natural_bc([x**2], "Top") + + poisson.add_dirichlet_bc(0.0, "Left") + poisson.add_dirichlet_bc([y], "Right") + poisson.add_dirichlet_bc(0.0, "Bottom") + poisson.add_dirichlet_bc([x**2], "Top") + + poisson.solve() + + with mesh.access(): + num = T_soln.data[:].squeeze() + ana = uw.function.evaluate(ana_soln, T_soln.coords) + + assert np.allclose(ana, num, atol = 1e-4), "Numerical and analytical solutions differ!" + + del poisson + del mesh \ No newline at end of file