Skip to content

Commit

Permalink
Merge branch 'main' into timestepping_physics
Browse files Browse the repository at this point in the history
  • Loading branch information
tommbendall committed Jul 27, 2023
2 parents a6bc71a + c1b50f0 commit 866e46a
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 15 deletions.
11 changes: 3 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,15 @@ jobs:
- name: Gusto unit-tests
run: |
. /home/firedrake/firedrake/bin/activate
python $(which firedrake-clean)
which firedrake-clean
python -m pytest -n 12 -v unit-tests
- name: Gusto integration-tests
run: |
. /home/firedrake/firedrake/bin/activate
python $(which firedrake-clean)
firedrake-clean
python -m pytest -n 12 -v integration-tests
- name: Gusto examples
run: |
. /home/firedrake/firedrake/bin/activate
python $(which firedrake-clean)
firedrake-clean
python -m pytest -n 12 -v examples
- name: Lint
if: ${{ always() }}
run: |
. /home/firedrake/firedrake/bin/activate
make lint
57 changes: 57 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Check docs build cleanly

on:
# Run on pushes to master
push:
branches:
- master
# And all pull requests
pull_request:

concurrency:
# Cancels jobs running if new commits are pushed
group: >
${{ github.workflow }}-
${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
build_docs:
name: Run doc build
# The type of runner that the job will run on
runs-on: ubuntu-latest
# The docker container to use.
container:
image: firedrakeproject/firedrake-docdeps:latest
options: --user root
volumes:
- ${{ github.workspace }}:/home/firedrake/output
# Steps represent a sequence of tasks that will be executed as
# part of the jobs
steps:
- uses: actions/checkout@v3
- name: Install checkedout Gusto
run: |
. /home/firedrake/firedrake/bin/activate
python -m pip install -e .
- name: Install Read the Docs theme
run: |
. /home/firedrake/firedrake/bin/activate
python -m pip install sphinx_rtd_theme
- name: Check documentation links
if: ${{ github.ref == 'refs/heads/master' }}
run: |
. /home/firedrake/firedrake/bin/activate
cd docs
make linkcheck
- name: Build docs
run: |
. /home/firedrake/firedrake/bin/activate
cd docs
make html
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
name: github-pages
path: /__w/gusto/gusto/docs/build/html
retention-days: 1
40 changes: 40 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Run lint

on:
# Push to master or PR
push:
branches:
- master
pull_request:

jobs:
linter:
name: "Run linter"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup python
uses: actions/setup-python@v4
with:
python-version: 3.11
- name: Setup flake8 annotations
uses: rbialon/flake8-annotations@v1
- name: Install linter
run: |
pip install flake8 pylint
- name: Lint codebase
run: |
make lint GITHUB_ACTIONS_FORMATTING=1
actionlint:
name: "Lint Github actions YAML files"
# There's a way to add error formatting so GH actions adds messages to code,
# but I can't work out the right number of quotes to get it to work
# https://github.com/rhysd/actionlint/blob/main/docs/usage.md
# #example-error-annotation-on-github-actions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check workflow files
uses: docker://rhysd/actionlint:latest
with:
args: -color
20 changes: 14 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
# Adds file annotations to Github Actions (only useful on CI)
GITHUB_ACTIONS_FORMATTING=0
ifeq ($(GITHUB_ACTIONS_FORMATTING), 1)
FLAKE8_FORMAT=--format='::error file=%(path)s,line=%(row)d,col=%(col)d,title=%(code)s::%(path)s:%(row)d:%(col)d: %(code)s %(text)s'
else
FLAKE8_FORMAT=
endif

lint:
@echo " Linting gusto codebase"
@python3 -m flake8 gusto
@python3 -m flake8 $(FLAKE8_FORMAT) gusto
@echo " Linting gusto examples"
@python3 -m flake8 examples
@python3 -m flake8 $(FLAKE8_FORMAT) examples
@echo " Linting gusto unit-tests"
@python3 -m flake8 unit-tests
@python3 -m flake8 $(FLAKE8_FORMAT) unit-tests
@echo " Linting gusto integration-tests"
@python3 -m flake8 integration-tests
@python3 -m flake8 $(FLAKE8_FORMAT) integration-tests
@echo " Linting gusto plotting scripts"
@python3 -m flake8 plotting
@python3 -m flake8 $(FLAKE8_FORMAT) plotting

test:
@echo " Running all tests"
Expand All @@ -24,4 +32,4 @@ integration_test:

example:
@echo " Running all examples"
@python3 -m pytest examples $(PYTEST_ARGS)
@python3 -m pytest examples $(PYTEST_ARGS)
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,5 +254,5 @@
'pyop2': ('https://op2.github.io/PyOP2', None),
'ufl': ('https://fenics.readthedocs.io/projects/ufl/en/latest/', None),
'h5py': ('http://docs.h5py.org/en/latest/', None),
'python':('https://docs.python.org/2.7/', None),
'python':('https://docs.python.org/', None),
}
1 change: 1 addition & 0 deletions gusto/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from gusto.limiters import * # noqa
from gusto.linear_solvers import * # noqa
from gusto.meshes import * # noqa
from gusto.numerical_integrator import * # noqa
from gusto.physics import * # noqa
from gusto.preconditioners import * # noqa
from gusto.recovery import * # noqa
Expand Down
63 changes: 63 additions & 0 deletions gusto/numerical_integrator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import numpy as np


class NumericalIntegral(object):
"""
A class for numerically evaluating and tabulating some 1D integral.
Args:
lower_bound(float): lower bound of integral
upper_bound(float): upper bound of integral
num_points(float): number of points to tabulate integral at
"""
def __init__(self, lower_bound, upper_bound, num_points=500):

# if upper_bound <= lower_bound:
# raise ValueError('lower_bound must be lower than upper_bound')
self.x = np.linspace(lower_bound, upper_bound, num_points)
self.x_double = np.linspace(lower_bound, upper_bound, 2*num_points-1)
self.lower_bound = lower_bound
self.upper_bound = upper_bound
self.num_points = num_points
self.tabulated = False

def tabulate(self, expression):
"""
Tabulate some integral expression using Simpson's rule.
Args:
expression (func): a function representing the integrand to be
evaluated. should take a numpy array as an argument.
"""

self.cumulative = np.zeros_like(self.x)
self.interval_areas = np.zeros(len(self.x)-1)
# Evaluate expression in advance to make use of numpy optimisation
# We evaluate at the tabulation points and the midpoints of the intervals
f = expression(self.x_double)

# Just do Simpson's rule for evaluating area of each interval
self.interval_areas = ((self.x[1:] - self.x[:-1]) / 6.0
* (f[2::2] + 4.0 * f[1::2] + f[:-1:2]))

# Add the interval areas together to create cumulative integral
for i in range(self.num_points - 1):
self.cumulative[i+1] = self.cumulative[i] + self.interval_areas[i]

self.tabulated = True

def evaluate_at(self, points):
"""
Evaluates the integral at some point using linear interpolation.
Args:
points (float or iter) the point value, or array of point values to
evaluate the integral at.
Return:
returns the numerical approximation of the integral from lower
bound to point(s)
"""
# Do linear interpolation from tabulated values
if not self.tabulated:
raise RuntimeError(
'Integral must be tabulated before we can evaluate it at a point')

return np.interp(points, self.x, self.cumulative)
34 changes: 34 additions & 0 deletions unit-tests/test_numerical_integrator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""
Tests the numerical integrator.
"""
from gusto import NumericalIntegral
from numpy import sin, pi
import pytest


def quadratic(x):
return x**2


def sine(x):
return sin(x)


@pytest.mark.parametrize("integrand_name", ["quadratic", "sine"])
def test_numerical_integrator(integrand_name):
if integrand_name == "quadratic":
integrand = quadratic
upperbound = 3
answer = 9
elif integrand_name == "sine":
integrand = sine
upperbound = pi
answer = 2
else:
raise ValueError(f'{integrand_name} integrand not recognised')
numerical_integral = NumericalIntegral(0, upperbound)
numerical_integral.tabulate(integrand)
area = numerical_integral.evaluate_at(upperbound)
err_tol = 1e-10
assert abs(area-answer) < err_tol, \
f'numerical integrator is incorrect for {integrand_name} function'

0 comments on commit 866e46a

Please sign in to comment.