diff --git a/.github/workflows/open_in_cloud.yml b/.github/workflows/open_in_cloud.yml new file mode 100644 index 00000000..3bb244fe --- /dev/null +++ b/.github/workflows/open_in_cloud.yml @@ -0,0 +1,130 @@ +name: "Update notebooks for cloud environments" + +on: + push: + branches: + - "**" + - "!gh-pages" + - "!open-in-colab" + - "!open-in-kaggle" + pull_request: + branches: + - main + schedule: + - cron: "0 4 * * MON" + workflow_dispatch: + inputs: + branch: + description: "Branch on viskex repository" + type: string + +jobs: + open_in_colab: + strategy: + matrix: + include: + - backend: dolfinx + fem_on_colab_packages: | + gmsh@current%dolfinx.io + fenicsx==real@current$dolfinx + notebook_pattern: | + "**/tutorial_*_dolfinx.ipynb" + - backend: firedrake + fem_on_colab_packages: | + firedrake==real@current + notebook_pattern: | + "**/tutorial_*_firedrake.ipynb" + fail-fast: false + uses: fem-on-colab/open-in-colab-workflow/.github/workflows/workflow_call.yml@main + with: + work_directory: open_in_colab + notebook_pattern: ${{ matrix.notebook_pattern }} + notebook_preparation: | + python3 -m pip install --no-dependencies git+https://github.com/multiphenics/nbvalx.git + git clone https://github.com/viskex/viskex.git + cd viskex + if [ -n "${{ (inputs || github.event.inputs).branch }}" ]; then + git checkout "${{ (inputs || github.event.inputs).branch }}" + fi + NO_TESTS_COLLECTED=5 + python3 -m pytest --ipynb-action=create-notebooks --tag-collapse --work-dir=.ipynb_colab tutorials || (($?==$NO_TESTS_COLLECTED)) + find tutorials -type d -name .ipynb_colab -exec rsync -avz --remove-source-files --include="*.ipynb" --exclude="*" {}/ {}/.. \; + NOTEBOOKS_TO_INCLUDE="" + while read -r PATTERN; do + NOTEBOOKS_TO_INCLUDE="${NOTEBOOKS_TO_INCLUDE} --include=$(echo ${PATTERN} | sed 's|\"||g')" + done <<< $(printf "%s" "${{ matrix.notebook_pattern }}") + rsync -avz --delete --include "*/" ${NOTEBOOKS_TO_INCLUDE} --exclude="*" tutorials ../open_in_colab/ + fem_on_colab_packages: ${{ matrix.fem_on_colab_packages }} + pip_packages: | + viskex@https://github.com/viskex/viskex.git@current + test_script: | + apt install -y -qq libgl1-mesa-glx xvfb + export DISPLAY=":99" + Xvfb $DISPLAY -screen 0 1024x768x24 > /dev/null 2>&1 & + NOTEBOOKS_TO_TEST="" + while read -r PATTERN; do + NOTEBOOKS_TO_TEST="${NOTEBOOKS_TO_TEST} $(find open_in_colab -wholename $(echo ${PATTERN} | sed 's|\"||g'))" + done <<< $(printf "%s" "${{ matrix.notebook_pattern }}") + python3 -m pytest --nbval ${NOTEBOOKS_TO_TEST} + publish_on: github@viskex/viskex.github.io@open-in-colab + publish_if_repository: viskex/viskex.github.io + + open_in_kaggle: + strategy: + matrix: + include: + - backend: dolfinx + fem_on_kaggle_packages: | + gmsh@current%dolfinx.io + fenicsx==real@current$dolfinx + notebook_pattern: | + "**/tutorial_*_dolfinx.ipynb" + - backend: firedrake + fem_on_kaggle_packages: | + firedrake==real@current + notebook_pattern: | + "**/tutorial_*_firedrake.ipynb" + fail-fast: false + uses: fem-on-kaggle/open-in-kaggle-workflow/.github/workflows/workflow_call.yml@main + with: + work_directory: open_in_kaggle + notebook_pattern: ${{ matrix.notebook_pattern }} + notebook_preparation: | + python3 -m pip install --no-dependencies git+https://github.com/multiphenics/nbvalx.git + git clone https://github.com/viskex/viskex.git + cd viskex + if [ -n "${{ (inputs || github.event.inputs).branch }}" ]; then + git checkout "${{ (inputs || github.event.inputs).branch }}" + fi + NO_TESTS_COLLECTED=5 + python3 -m pytest --ipynb-action=create-notebooks --tag-collapse --work-dir=.ipynb_kaggle tutorials || (($?==$NO_TESTS_COLLECTED)) + find tutorials -type d -name .ipynb_kaggle -exec rsync -avz --remove-source-files --include="*.ipynb" --exclude="*" {}/ {}/.. \; + NOTEBOOKS_TO_INCLUDE="" + while read -r PATTERN; do + NOTEBOOKS_TO_INCLUDE="${NOTEBOOKS_TO_INCLUDE} --include=$(echo ${PATTERN} | sed 's|\"||g')" + done <<< $(printf "%s" "${{ matrix.notebook_pattern }}") + rsync -avz --delete --include "*/" ${NOTEBOOKS_TO_INCLUDE} --exclude="*" tutorials ../open_in_kaggle/ + fem_on_kaggle_packages: ${{ matrix.fem_on_kaggle_packages }} + pip_packages: | + viskex@https://github.com/viskex/viskex.git@current + test_script: | + apt install -y -qq libgl1-mesa-glx xvfb + export DISPLAY=":99" + Xvfb $DISPLAY -screen 0 1024x768x24 > /dev/null 2>&1 & + NOTEBOOKS_TO_TEST="" + while read -r PATTERN; do + NOTEBOOKS_TO_TEST="${NOTEBOOKS_TO_TEST} $(find open_in_kaggle -wholename $(echo ${PATTERN} | sed 's|\"||g'))" + done <<< $(printf "%s" "${{ matrix.notebook_pattern }}") + python3 -m pytest --nbval ${NOTEBOOKS_TO_TEST} + publish_on: github@viskex/viskex.github.io@open-in-kaggle + publish_if_repository: viskex/viskex.github.io + + warn: + runs-on: ubuntu-latest + if: github.repository == 'viskex/viskex.github.io' && github.ref == 'refs/heads/main' && github.event_name == 'schedule' + steps: + - name: Warn if scheduled workflow is about to be disabled + uses: fem-on-colab/warn-workflow-about-to-be-disabled-action@main + with: + workflow-filename: open_in_cloud.yml + days-elapsed: 50 diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml new file mode 100644 index 00000000..2700f57c --- /dev/null +++ b/.github/workflows/website.yml @@ -0,0 +1,215 @@ +name: "Website update" + +on: + push: + branches: + - "**" + - "!gh-pages" + pull_request: + branches: + - main + schedule: + - cron: "0 3 * * MON" + workflow_dispatch: + inputs: + branch: + description: "Branch on viskex repository" + type: string + reset_github_pages: + description: "Reset the gh-pages branch (yes or no; default: no). Remember to set the gh-pages branch back in Settings -> Pages!" + type: string + +jobs: + convert_notebooks: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - backend: dolfinx + container: dolfinx/dolfinx:nightly + setup_container: | + export DEBIAN_FRONTEND="noninteractive" + apt -y -qq update + apt install -y -qq libgl1-mesa-glx xvfb + notebook_pattern: | + "**/tutorial_*_dolfinx.ipynb" + - backend: firedrake + container: firedrakeproject/firedrake + setup_container: | + export DEBIAN_FRONTEND="noninteractive" + apt -y -qq update + apt install -y -qq libgl1-mesa-glx xorg xvfb + echo "/home/firedrake/firedrake/bin" >> $GITHUB_PATH + notebook_pattern: | + "**/tutorial_*_firedrake.ipynb" + fail-fast: false + container: + image: ${{ matrix.container }} + options: --user root + steps: + - name: Determine which branch to checkout when cloning source repository + id: source_branch + run: | + if [ -n "${{ (inputs || github.event.inputs).branch }}" ]; then + echo "branch=${{ (inputs || github.event.inputs).branch }}" >> ${GITHUB_OUTPUT} + else + echo "branch=main" >> ${GITHUB_OUTPUT} + fi + shell: bash + - name: Clone source repository on the previously computed branch + uses: actions/checkout@v3 + with: + repository: viskex/viskex + ref: ${{ steps.source_branch.outputs.branch }} + fetch-depth: 0 + - name: Clone website repository on current branch + uses: actions/checkout@v3 + with: + fetch-depth: 0 + path: _website + - name: Setup container + run: | + ${{ matrix.setup_container }} + python3 -m pip -q install nbconvert + - name: Install viskex + run: python3 -m pip install .[tutorials] + - name: Install nbconvert + run: python3 -m pip -q install nbconvert + - name: Copy jupyter template from website repository + run: | + jupyter --paths --json > /tmp/jupyter-paths + JUPYTER_SHARE=$(python3 -c 'import json; data = json.loads(open("/tmp/jupyter-paths", "r").read()); print(data["data"][-1])') + mkdir -p ${JUPYTER_SHARE}/nbconvert/templates + cp -rf _website/share/jupyter/nbconvert/templates/html/viskex ${JUPYTER_SHARE}/nbconvert/templates/ + rm /tmp/jupyter-paths + - name: Convert notebooks to html + run: | + NOTEBOOKS_TO_RUN=() + while read -r PATTERN; do + NOTEBOOKS_TO_RUN+=($(find tutorials -wholename $(echo ${PATTERN} | sed 's|\"||g'))) + done <<< $(printf "%s" "${{ matrix.notebook_pattern }}") + mkdir -p _build/html + export DISPLAY=":99" + Xvfb $DISPLAY -screen 0 1024x768x24 > /dev/null 2>&1 & + for NOTEBOOK in "${NOTEBOOKS_TO_RUN[@]}"; do + NOTEBOOK_DIRNAME=$(dirname "${NOTEBOOK}") + NOTEBOOK_OUTPUT_DIRNAME=${GITHUB_WORKSPACE}/_build/html/${NOTEBOOK_DIRNAME} + NOTEBOOK_BASENAME=$(basename "${NOTEBOOK}") + NOTEBOOK_OUTPUT_BASENAME=${NOTEBOOK_BASENAME/.ipynb/.html} + pushd ${NOTEBOOK_DIRNAME} + VISKEX_PYVISTA_BACKEND="panel" jupyter nbconvert --to html --template viskex --execute --output-dir ${NOTEBOOK_OUTPUT_DIRNAME} ${NOTEBOOK_BASENAME} + popd + pushd ${NOTEBOOK_OUTPUT_DIRNAME} + sed -i "s|\"https://colab.research.google.com\"|\"https://colab.research.google.com/github/viskex/viskex.github.io/blob/open-in-colab/${NOTEBOOK_DIRNAME}/${NOTEBOOK_BASENAME}\"|g" ${NOTEBOOK_OUTPUT_BASENAME} + sed -i "s|\"https://kaggle.com\"|\"https://kaggle.com/kernels/welcome?src=https://github.com/viskex/viskex.github.io/blob/open-in-kaggle/${NOTEBOOK_DIRNAME}/${NOTEBOOK_BASENAME}\"|g" ${NOTEBOOK_OUTPUT_BASENAME} + popd + done + shell: bash + - name: Store converted notebooks as artifacts + uses: actions/upload-artifact@v3 + with: + name: converted-notebooks-${{ matrix.backend }} + path: _build/html + retention-days: 1 + + publish_notebooks: + runs-on: ubuntu-latest + needs: [convert_notebooks] + steps: + - name: Clone website repository on current branch + uses: actions/checkout@v3 + - name: Clone website repository on gh-pages branch + uses: actions/checkout@v3 + with: + ref: gh-pages + fetch-depth: 0 + path: _build/html + - name: Download converted notebooks from artifacts + uses: actions/download-artifact@v3 + with: + path: _build/html + - name: Flatten the artifacts hierarchy + run: | + rsync -avh --remove-source-files _build/html/converted-notebooks-*/ _build/html/ + find _build/html/ -type d -empty -delete + - name: Upload release file to website + if: github.repository == 'viskex/viskex.github.io' && github.ref == 'refs/heads/main' + run: | + SHA_SHORT=$(git rev-parse --short HEAD) + pushd _build/html + git config user.name "GitHub Actions" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add . + git pull origin gh-pages + [ -n "$(git status --porcelain=v1 2>/dev/null)" ] && git commit -m "deploy notebooks: ${SHA_SHORT}" + git push origin gh-pages + popd + shell: bash + + website: + runs-on: ubuntu-latest + needs: [publish_notebooks] + steps: + - name: Clone website repository on current branch + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Clone website repository on gh-pages branch + uses: actions/checkout@v3 + with: + ref: gh-pages + fetch-depth: 0 + path: _build/html + - name: Install dependencies + run: | + pip3 -q install sphinx-material + - name: Generate sphinx website + run: | + rm -rf _build/html/* && make html + - name: Fix permissions + run: | + sudo chown $USER _build -R + - name: Clean up old Github pages branch + if: github.repository == 'viskex/viskex.github.io' && github.event.inputs.reset_github_pages == 'yes' + run: | + if git ls-remote origin | grep -sw gh-pages 2>&1 >/dev/null; then git push origin --delete gh-pages; fi + - name: Check that no tutorials have been deleted + run: | + pushd _build/html + if [[ $(git ls-files --deleted tutorials | wc -l) -gt 0 ]]; then + echo "The following tutorials have been deleted:" + git ls-files --deleted tutorials + exit 1 + fi + popd + - name: Deploy to GitHub pages + if: github.repository == 'viskex/viskex.github.io' && github.ref == 'refs/heads/main' + run: | + SHA_SHORT=$(git rev-parse --short HEAD) + pushd _build/html + git config user.name "GitHub Actions" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add . + git pull origin gh-pages + [ -n "$(git status --porcelain=v1 2>/dev/null)" ] && git commit -m "deploy website: ${SHA_SHORT}" + git push origin gh-pages + popd + shell: bash + - name: Deploy to GitHub artifacts + if: github.repository == 'viskex/viskex.github.io' && github.ref != 'refs/heads/main' + uses: actions/upload-artifact@v3 + with: + name: website + path: _build/html + retention-days: 1 + + warn: + runs-on: ubuntu-latest + if: github.repository == 'viskex/viskex.github.io' && github.ref == 'refs/heads/main' && github.event_name == 'schedule' + steps: + - uses: actions/checkout@v3 + - name: Warn if scheduled workflow is about to be disabled + uses: fem-on-colab/warn-workflow-about-to-be-disabled-action@main + with: + workflow-filename: website.yml + days-elapsed: 50 diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/_ext/ext.py b/_ext/ext.py new file mode 100644 index 00000000..9bdff070 --- /dev/null +++ b/_ext/ext.py @@ -0,0 +1,191 @@ +import os +import subprocess +from docutils import nodes +from docutils.parsers.rst import Directive +from tutorials import tutorials +import sphinx_material + +class Tutorials(Directive): + + def run(self): + output = list() + # General text + intro = f""" +

+viskex is accompanied by a few tutorials, that can be run on JupyterLab through a local installation of the library, or on cloud computing platforms such as Google Colab and Kaggle. +

+""" + output.append(nodes.raw(text=intro, format="html")) + # Tutorials + for num in tutorials.keys(): + data = tutorials[num] + steps = data["steps"] + buttons = "" + for step_description in steps: + step_files = steps[step_description] + if len(step_files) == 1: + buttons += self._button(step_description, step_files) + else: + buttons += self._dropdown(step_description, step_files) + + card_num = self._card( + num=num, + title=data["title"], + description=data["description"], + buttons=buttons + ) + output.append(nodes.raw(text=card_num, format="html")) + return output + + @staticmethod + def _card(num, title, description, buttons): + return f""" +
+
+ {num} +
+
+

+ {title} +

+
+

{description}

+
+
+ {buttons} +
+
+
+""" + + @classmethod + def _dropdown(cls, step_description, libraries_urls): + dropdown = f""" +
+ +
+
{step_description}
+""" + cls._dropdown_id += 1 + return dropdown + + _dropdown_id = 1 + + @classmethod + def _button(cls, step_description, libraries_urls): + assert len(libraries_urls) == 1 + library = list(libraries_urls.keys())[0] + url = libraries_urls[library] + return f""" +
{cls._library_image(library)} {step_description}
+""" + + @staticmethod + def _library_image(library): + if library == "dolfinx": + logo = "_static/images/dolfinx-logo.png" + elif library == "firedrake": + logo = "_static/images/firedrake-logo.png" + else: + raise RuntimeError("Invalid type") + return f'' + +def on_build_finished(app, exc): + if exc is None and app.builder.format == "html": + # Unescape at symbol + subprocess.run( + "find " + app.outdir + " -type f -not -path '*/\.git/*' -exec sed -i 's/%40/@/g' {} +", + shell=True) + # Mark current page as active + subprocess.run( + "find " + app.outdir + " -type f -not -path '*/\.git/*' -exec sed -i 's/" + + '
  • ' + + "/" + + '
  • ' + + "/g' {} +", + shell=True) + # Disable going to submenus on mobile + subprocess.run( + "find " + app.outdir + " -type f -not -path '*/\.git/*' -exec sed -i 's/" + + 'id="__toc"' + + "/" + + 'id="__toc_disabled"' + + "/g' {} +", + shell=True) + # Add further SEO tags + seo_head = """ + + + + + + + + +""" + index = os.path.join(app.outdir, "index.html") + with open(index, "r") as f: + index_content = f.read() + index_content = index_content.replace("", "\n" + seo_head) + with open(index, "w") as f: + f.write(index_content) + # Get tutorial nbconvert html files from git + for num in tutorials.keys(): + for step_files in tutorials[num]["steps"].values(): + for url in step_files.values(): + html_generated = subprocess.run( + "mkdir -p " + os.path.dirname(os.path.join(app.outdir, url)) + " && " + + "git show origin/gh-pages:" + url + "> " + os.path.join(app.outdir, url), + shell=True, capture_output=True) + if html_generated.returncode != 0: + raise RuntimeError( + "HTML generation of " + url + " not found\n" + + "stdout contains " + html_generated.stdout.decode() + "\n" + + "stderr contains " + html_generated.stderr.decode() + "\n") + + +create_sitemap_bak = sphinx_material.create_sitemap +def create_sitemap(app, exc): + create_sitemap_bak(app, exc) + if exc is None and app.builder.format == "html": + # Add version and encoding to the top of sitemap.xml + subprocess.run( + "sed -i '1s/^//' " + os.path.join(app.outdir, "sitemap.xml"), + shell=True) + # Remove trailing index.html from sitemap.xml + subprocess.run( + "sed -i 's|/index.html||g' " + os.path.join(app.outdir, "sitemap.xml"), + shell=True) +sphinx_material.create_sitemap = create_sitemap + + +def setup(app): + app.add_directive("tutorials", Tutorials) + app.connect("build-finished", on_build_finished) + + return { + "version": "0.1", + "parallel_read_safe": True, + "parallel_write_safe": False, + } diff --git a/_ext/tutorials.py b/_ext/tutorials.py new file mode 100644 index 00000000..e8e69b17 --- /dev/null +++ b/_ext/tutorials.py @@ -0,0 +1,22 @@ +tutorials = { + "01": { + "title": "Introduction", + "description": "Introduction on simple 1D, 2D and 3D meshes", + "steps": { + "Select the finite element backend": { + "dolfinx": "tutorials/01_introduction/tutorial_introduction_dolfinx.html", + "firedrake": "tutorials/01_introduction/tutorial_introduction_firedrake.html" + }, + }, + }, + "02": { + "title": "Application to Lake Garda", + "description": "Interactive visualization of meshes and simulations for Lake Garda", + "steps": { + "Select the finite element backend": { + "dolfinx": "tutorials/02_garda/tutorial_garda_dolfinx.html", + "firedrake": "tutorials/02_garda/tutorial_garda_firedrake.html" + }, + }, + }, +} diff --git a/_static/bib/publications.bib b/_static/bib/publications.bib new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/_static/bib/publications.bib @@ -0,0 +1,2 @@ + + diff --git a/_static/css/custom.css b/_static/css/custom.css new file mode 100644 index 00000000..18acbf0c --- /dev/null +++ b/_static/css/custom.css @@ -0,0 +1,226 @@ +/* Customize palette */ +button[data-md-color-primary=unicatt] { + background-color: #00325c +} + +[data-md-color-primary=unicatt] .md-typeset a { + color: #00325c +} + +[data-md-color-primary=unicatt] .md-header, +[data-md-color-primary=unicatt] .md-hero { + background-color: #00325c +} + +[data-md-color-primary=unicatt] .md-nav__link--active, +[data-md-color-primary=unicatt] .md-nav__link:active { + color: #00325c +} + +[data-md-color-primary=unicatt] .md-nav__item--nested>.md-nav__link { + color: inherit +} + +button[data-md-color-accent=unicatt] { + background-color: #c23e46 +} + +[data-md-color-accent=unicatt] .md-typeset a:active, +[data-md-color-accent=unicatt] .md-typeset a:hover { + color: #c23e46 +} + +[data-md-color-accent=unicatt] .md-typeset .codehilite pre::-webkit-scrollbar-thumb:hover, +[data-md-color-accent=unicatt] .md-typeset pre code::-webkit-scrollbar-thumb:hover { + background-color: #c23e46 +} + +[data-md-color-accent=unicatt] .md-nav__link:focus, +[data-md-color-accent=unicatt] .md-nav__link:hover, +[data-md-color-accent=unicatt] .md-typeset .footnote li:hover .footnote-backref:hover, +[data-md-color-accent=unicatt] .md-typeset .footnote li:target .footnote-backref, +[data-md-color-accent=unicatt] .md-typeset .md-clipboard:active:before, +[data-md-color-accent=unicatt] .md-typeset .md-clipboard:hover:before, +[data-md-color-accent=unicatt] .md-typeset [id] .headerlink:focus, +[data-md-color-accent=unicatt] .md-typeset [id]:hover .headerlink:hover, +[data-md-color-accent=unicatt] .md-typeset [id]:target .headerlink { + color: #c23e46 +} + +[data-md-color-accent=unicatt] .md-search__scrollwrap::-webkit-scrollbar-thumb:hover { + background-color: #c23e46 +} + +[data-md-color-accent=unicatt] .md-search-result__link:hover, +[data-md-color-accent=unicatt] .md-search-result__link[data-md-state=active] { + background-color: rgba(255, 23, 68, .1) +} + +[data-md-color-accent=unicatt] .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover { + background-color: #c23e46 +} + +[data-md-color-accent=unicatt] .md-source-file:hover:before { + background-color: #c23e46 +} + +@media only screen and (max-width:59.9375em) { + [data-md-color-primary=unicatt] .md-nav__source { + background-color: #c23e46 + } +} + +@media only screen and (max-width:76.1875em) { + html [data-md-color-primary=unicatt] .md-nav--primary .md-nav__title--site { + background-color: #00325c + } +} + +@media only screen and (min-width:76.25em) { + [data-md-color-primary=unicatt] .md-tabs { + background-color: #00325c + } +} + +/* Hide undesired items */ +.md-sidebar--secondary, .md-footer { + display: None +} + +@media only screen and (min-width: 76.25em) { + .md-content { + margin-left: 1.0rem; + } +} +@media only screen and (min-width: 60em) { + .md-content { + margin-right: 1.0rem; + } +} + +@media only screen and (min-width: 76.25em) { + .md-sidebar--primary { + display: None + } +} + +/* Logo alignment on home page */ +.align-right { + float: right; + margin: 0 0 24px 24px; +} + +/* Links in header */ +.md-tabs__item { + display: inline-block; + height: 2.4rem; + padding-right: .6rem; + padding-left: .6rem; + background-color: #00325c; + font-weight: bold; +} + +.md-tabs__item:hover { + background-color: white; + color: #c23e46; +} + +.md-tabs__item_current { + background-color: #c23e46; + color: #00325c; +} + +.md-nav__link[for=__toc]:after { + display: none !important; +} + +/* Table in the home page */ +.md-typeset .md-typeset__table table { + font-size: .8rem; +} + +/* Tutorials buttons + https://labs.abeautifulsite.net/jquery-dropdown/ */ +.tutorial-button { + cursor: pointer; + padding: 14px; + border-radius: 4px; + background-color: #00325c; + color: white; + margin-bottom: 14px; + margin-left: 14px; +} + +.tutorial-button[data-jq-dropdown]:after { + font-family: Material Icons; + content: 'expand_more'; + margin-left: 6px; +} + +.tutorial-button:hover { + background-color: white; + color: #c23e46; +} + +.tutorial-button.jq-dropdown-open { + background-color: #c23e46; + color: #00325c; +} + +.jq-dropdown .jq-dropdown-menu { + max-width: none; +} + +.jq-dropdown .jq-dropdown-menu li { + color: #00325c; +} + +.jq-dropdown .jq-dropdown-menu li:hover { + color: #c23e46; +} + +.jq-dropdown .jq-dropdown-menu li .in-progress { + display: block; + color: rgba(0,0,0,.54);; + text-decoration: none; + line-height: 18px; + padding: 3px 15px; + margin: 0; + white-space: nowrap; +} + + +/* Tutorial cards + https://www.w3schools.com/howto/howto_css_column_cards.asp */ +.tutorial-card { + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); + padding: 16px; + text-align: left; + background-color: #f1f1f1; + display: flex; + align-items: flex-start; +} + +.tutorial-number { + flex: 0 0 2rem; + height: 2rem; + margin-left: 1rem; + margin-right: 1rem; + font-family: 'Pangolin'; + font-style: normal; + font-weight: 400; + font-size: 2rem; +} + +.tutorial-title { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.tutorial-description { +} + +.tutorial-buttons { + display: flex; + flex-wrap: wrap; +} diff --git a/_static/images/dolfinx-logo.png b/_static/images/dolfinx-logo.png new file mode 100644 index 00000000..c82fadb2 Binary files /dev/null and b/_static/images/dolfinx-logo.png differ diff --git a/_static/images/email.png b/_static/images/email.png new file mode 100644 index 00000000..5d16f0b2 Binary files /dev/null and b/_static/images/email.png differ diff --git a/_static/images/firedrake-logo.png b/_static/images/firedrake-logo.png new file mode 100644 index 00000000..369165ee Binary files /dev/null and b/_static/images/firedrake-logo.png differ diff --git a/_static/images/github-logo.png b/_static/images/github-logo.png new file mode 100644 index 00000000..ea6ff545 Binary files /dev/null and b/_static/images/github-logo.png differ diff --git a/_static/images/viskex-logo.png b/_static/images/viskex-logo.png new file mode 100644 index 00000000..10e189d0 Binary files /dev/null and b/_static/images/viskex-logo.png differ diff --git a/_static/js/external_links.js b/_static/js/external_links.js new file mode 100644 index 00000000..67de3486 --- /dev/null +++ b/_static/js/external_links.js @@ -0,0 +1,3 @@ +$(document).ready(function () { + $('a[href^="http://"], a[href^="https://"]').not('a[class*=internal]').attr('target', '_blank'); +}); diff --git a/citing.rst b/citing.rst new file mode 100644 index 00000000..22f16c12 --- /dev/null +++ b/citing.rst @@ -0,0 +1,7 @@ +How to cite +=========== +.. meta:: + :description lang=en: + If you use viskex in your work, please cite our website + +If you use **viskex** in your work, please cite the `viskex website `__. diff --git a/conf.py b/conf.py new file mode 100644 index 00000000..936cd6ff --- /dev/null +++ b/conf.py @@ -0,0 +1,120 @@ +# Configuration file for the Sphinx documentation builder. + +# -- Path setup -------------------------------------------------------------- + +import os +import sys +sys.path.insert(0, os.path.abspath("./_ext")) + + +# -- Project information ----------------------------------------------------- + +project = "viskex" +copyright = "2023-, Francesco Ballarin (and contributors)" +author = "Francesco Ballarin (and contributors)" + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here. +extensions = [ + "ext" +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + + +# -- Options for HTML output ------------------------------------------------- +html_title = "viskex" + +# The theme to use for HTML and HTML Help pages. +# From https://github.com/bashtage/sphinx-material +html_theme = "sphinx_material" + +# Material theme options +html_theme_options = { + # Set the name of the project to appear in the navigation. + "nav_title": "viskex", + + # Set you GA account ID to enable tracking + "google_analytics_account": "G-73EEV4MRHG", + + # Specify a base_url used to generate sitemap.xml. If not + # specified, then no sitemap will be built. + "base_url": "https://viskex.github.io/", + + # Set the color and the accent color + "theme_color": "#00325c", + "color_primary": "unicatt", + "color_accent": "unicatt", + + # Set the repo location to get a badge with stats + "repo_url": "https://github.com/viskex/viskex/", + "repo_name": "viskex", + + # Visible levels of the global TOC; -1 means unlimited + "globaltoc_depth": 1, + # If False, expand all TOC entries + "globaltoc_collapse": True, + # If True, show hidden TOC entries + "globaltoc_includehidden": False, + + # Path to a touch icon, should be 152x152 or larger. + "touch_icon": "images/viskex-logo.png", + "logo_icon": "", + + # Main menu links + "nav_links": [ + { + "href": "tutorials", + "internal": True, + "title": "Tutorials", + }, + { + "href": "installing", + "internal": True, + "title": "Installation", + }, + { + "href": "contributing", + "internal": True, + "title": "How to contribute", + }, + { + "href": "citing", + "internal": True, + "title": "How to cite", + } + ], + + # Disable version dropbown + "version_dropdown": False, +} +html_sidebars = { + "**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"] +} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# Custom CSS files +html_css_files = [ + "https://cdnjs.cloudflare.com/ajax/libs/jquery-dropdown/2.0.3/jquery.dropdown.min.css", + "https://fonts.googleapis.com/css?family=Pangolin", + "css/custom.css", +] + +# Custom javascript files +html_js_files = [ + "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js", + "https://cdnjs.cloudflare.com/ajax/libs/jquery-dropdown/2.0.3/jquery.dropdown.min.js", + "js/external_links.js" +] diff --git a/contributing.rst b/contributing.rst new file mode 100644 index 00000000..fe089e6c --- /dev/null +++ b/contributing.rst @@ -0,0 +1,24 @@ +How to contribute +================= +.. meta:: + :description lang=en: + viskex developement takes place on GitHub. We are still at an early developement stage. + Feel free to contact us by email for further information. + +.. image:: _static/images/github-logo.png + :target: https://github.com/viskex/viskex + :height: 80px + :width: 80px + :alt: Go to repository on GitHub +.. image:: _static/images/email.png + :target: mailto:francesco.ballarin@unicatt.it + :height: 80px + :width: 80px + :alt: Contact us via email + +| Developement takes place on our `GitHub repository `__. +| **viskex** developement is still at very early stages. +| Contributions improving either the code or the documentation, as well as proposal of new features, are welcome as `pull requests `__. +| Bug reports and upcoming feature proposals can be reported to `our issue tracker `__. + +For further information or questions about **viskex** feel free to contact us by `email `__ as well. diff --git a/index.rst b/index.rst new file mode 100644 index 00000000..8c4d068c --- /dev/null +++ b/index.rst @@ -0,0 +1,59 @@ +viskex +====== +.. meta:: + :description lang=en: + viskex is a library for the interactive visualization of finite element simulations within jupyter notebooks + in JupyterLab, Google Colab or Kaggle. viskex is currently developed at Università Cattolica del Sacro Cuore + by Dr. Francesco Ballarin. + +.. image:: _static/images/github-logo.png + :target: https://github.com/viskex/viskex + :height: 80px + :width: 80px + :alt: Go to repository on GitHub +.. image:: _static/images/email.png + :target: mailto:francesco.ballarin@unicatt.it + :height: 80px + :width: 80px + :alt: Contact us via email + + +Description +----------- + +.. image:: _static/images/viskex-logo.png + :height: 150px + :width: 150px + :align: right + :alt: viskex + +**viskex** is a library for the interactive visualization of finite element simulations within jupyter notebooks in JupyterLab, Google Colab or Kaggle. Supported finite element backends are `dolfinx `__ and `firedrake `__. + +Authors and contributors +------------------------ + +**viskex** is currently developed and maintained at `Università Cattolica del Sacro Cuore `__ by `Dr. Francesco Ballarin `__. +We acknowledge all contributors listed in the `AUTHORS file `__. + +Timeline and funding +------------------------ +.. list-table:: + :widths: 10 90 + + * - 2023 + - Early development of **viskex** begins at `Università Cattolica del Sacro Cuore `__. + +Learn more about viskex +----------------------- +.. toctree:: + :maxdepth: 1 + + tutorials + installing + contributing + citing + +License +------- + +**viskex** is freely available under the MIT license. diff --git a/installing.rst b/installing.rst new file mode 100644 index 00000000..f7a26e73 --- /dev/null +++ b/installing.rst @@ -0,0 +1,42 @@ +Installation +============ +.. meta:: + :description lang=en: + Installation requirements are automatically handled during the setup. + In order to run the tutorials you may need to install one of the supported finite element backends. + +Prerequisites +------------- + +Installation requirements are automatically handled during the setup. +In order to run the tutorials you may need to install one of the supported finite element backends, namely `dolfinx `__ and `firedrake `__. + +Installation and usage +---------------------- + +Simply clone the **viskex** public repository: + +.. code-block:: console + + git clone https://github.com/viskex/viskex.git + +and install the package by typing + +.. code-block:: console + + python3 -m pip install .[tutorials] + +External libraries used for plotting +------------------------------------ +1D plots are provided by :code:`plotly`, while 2D/3D plots are rendered with :code:`pyvista`. Supported :code:`pyvista` backends are :code:`trame` and :code:`panel`. The default :code:`pyvista` backend is :code:`trame` when running in JupyterLab, and :code:`panel` when running on Google Colab or Kaggle. Users can customize the active :code:`pyvista` backend by exporting the environment variable :code:`VISKEX_PYVISTA_BACKEND`: such operation is typically not required, with the only notable exceptions being testing different :code:`pyvista` backends on CI, or exporting notebooks to html via :code:`nbconvert`. + +Compatibility with upstream releases +------------------------------------ + +**viskex** targets the :code:`main` branch of :code:`dolfinx` and :code:`firedrake`, which may contain API changes compared to the latest release of the finite element backend. A new **viskex** version is not necessarily tagged alongside :code:`dolfinx` or :code:`firedrake` releases. Users willing to work with a fixed release of the finite element backend are encouraged to look for a **viskex** `commit `__ close to the upstream release date, and do a + +.. code-block:: console + + git checkout {commit SHA} + +before installing **viskex**. diff --git a/share/jupyter/nbconvert/templates/html/viskex/conf.json b/share/jupyter/nbconvert/templates/html/viskex/conf.json new file mode 100644 index 00000000..68fdf836 --- /dev/null +++ b/share/jupyter/nbconvert/templates/html/viskex/conf.json @@ -0,0 +1,12 @@ +{ + "base_template": "lab", + "mimetypes": { + "text/html": true + }, + "preprocessors": { + "100-pygments": { + "type": "nbconvert.preprocessors.CSSHTMLHeaderPreprocessor", + "enabled": true + } + } +} diff --git a/share/jupyter/nbconvert/templates/html/viskex/index.html.j2 b/share/jupyter/nbconvert/templates/html/viskex/index.html.j2 new file mode 100644 index 00000000..c3e300a7 --- /dev/null +++ b/share/jupyter/nbconvert/templates/html/viskex/index.html.j2 @@ -0,0 +1,37 @@ +{%- extends 'lab/index.html.j2' -%} + +{%- block html_head_css -%} + {{ super() }} + +{%- endblock html_head_css -%} + +{% block body_header %} + +
    +
    +
    + +
    +
    + This tutorial is part of viskex.
    + + + + + + +
    +
    +
    + +
    +{% endblock body_header %} + +{% block body_footer %} +
    + +{% endblock body_footer %} diff --git a/tutorials.rst b/tutorials.rst new file mode 100644 index 00000000..3c97c219 --- /dev/null +++ b/tutorials.rst @@ -0,0 +1,9 @@ +.. _tutorials: + +Tutorials +============ +.. meta:: + :description lang=en: + viskex is accompanied by a few tutorials, that can be run on JupyterLab through a local installation + of the library, or on cloud computing platforms such as Google Colab and Kaggle. +.. tutorials::