Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop lint ignores except in demos #266

Merged
merged 12 commits into from
Dec 24, 2024
22 changes: 12 additions & 10 deletions demos/burgers-goal_oriented.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Burgers equation with Goal-oriented mesh adaptation
# ===================================================

# In the `Hessian-based adaptation <./burgers-hessian.py.html>`__, we applied a Hessian-based
# mesh adaptation to the time-dependent Burgers equation. Here, we alternatively consider
# a goal-oriented error estimation to drive the mesh adaptation. Again, we will
# choose to partition the problem over multiple subintervals and hence multiple meshes
# to adapt. We also chose to apply a QoI which integrates in time as well as space.
# In the `Hessian-based adaptation <./burgers-hessian.py.html>`__, we applied a
# Hessian-based mesh adaptation to the time-dependent Burgers equation. Here, we
# alternatively consider a goal-oriented error estimation to drive the mesh adaptation.
# Again, we will choose to partition the problem over multiple subintervals and hence
# multiple meshes to adapt. We also chose to apply a QoI which integrates in time as
# well as space.
#
# We copy over the setup as before. The only difference is that we import from
# ``goalie_adjoint`` rather than ``goalie``. ::
Expand Down Expand Up @@ -115,8 +116,8 @@ def time_integrated_qoi(t):

# Compared to the previous `Hessian-based adaptation <./burgers-hessian.py.html>`__,
# this adaptor depends on adjoint solution data as well as forward solution data.
# For simplicity, we begin by using :meth:`~.RiemannianMetric.compute_isotropic_metric()`.
# ::
# For simplicity, we begin by using
# :meth:`~.RiemannianMetric.compute_isotropic_metric()`. ::


def adaptor(mesh_seq, solutions=None, indicators=None):
Expand Down Expand Up @@ -257,7 +258,8 @@ def adaptor(mesh_seq, solutions=None, indicators=None):
# (See documentation for details.) To use it, we just need to define
# a different adaptor function. The same error indicator is used as
# for the isotropic approach. Additionally, the Hessian of the forward
# solution is estimated as in the `Hessian-based adaptation <./burgers-hessian.py.html>`__
# solution is estimated as in the
# `Hessian-based adaptation <./burgers-hessian.py.html>`__
# to give anisotropy to the metric.
#
# For this driver, normalisation is handled differently than for
Expand Down Expand Up @@ -351,8 +353,8 @@ def adaptor(mesh_seq, solutions=None, indicators=None):
fig.savefig(f"burgers-anisotropic_mesh{iteration + 1}.jpg")
plt.close()

# Since we have multiple subintervals, we should check if the target complexity has been
# (approximately) reached on each subinterval
# Since we have multiple subintervals, we should check if the target complexity has
# been (approximately) reached on each subinterval
continue_unconditionally = np.array(complexities) < 0.90 * target
return continue_unconditionally

Expand Down
1 change: 1 addition & 0 deletions demos/burgers-hessian.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from animate.adapt import adapt
from animate.metric import RiemannianMetric
from firedrake import *
from firedrake.__future__ import interpolate

from goalie import *

Expand Down
17 changes: 9 additions & 8 deletions demos/burgers_ee.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,15 @@ def end_time_qoi():
qoi_type="end_time",
)

# Given the description of the PDE problem in the form of a :class:`GoalOrientedMeshSeq`,
# Goalie is able to extract all of the relevant information to automatically compute
# error estimators. During the computation, we solve the forward and adjoint equations
# over the mesh sequence, as before. In addition, we solve the adjoint problem again
# in an *enriched* finite element space. Currently, Goalie supports uniform refinement
# of the meshes (:math:`h`-refinement) or globally increasing the polynomial order
# (:math:`p`-refinement). Choosing one (or both) of these as the ``"enrichment_method"``,
# we are able to compute error indicator fields as follows. ::
# Given the description of the PDE problem in the form of a
# :class:`GoalOrientedMeshSeq`, Goalie is able to extract all of the relevant
# information to automatically compute error estimators. During the computation, we
# solve the forward and adjoint equations over the mesh sequence, as before. In
# addition, we solve the adjoint problem again in an *enriched* finite element space.
# Currently, Goalie supports uniform refinement of the meshes (:math:`h`-refinement) or
# globally increasing the polynomial order (:math:`p`-refinement). Choosing one (or
# both) of these as the ``"enrichment_method"``, we are able to compute error indicator
# fields as follows. ::

solutions, indicators = mesh_seq.indicate_errors(
enrichment_kwargs={"enrichment_method": "h"}
Expand Down
3 changes: 2 additions & 1 deletion demos/burgers_oo.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ def time_integrated_qoi(t):
enrichment_kwargs={"enrichment_method": "h"}
)

# Plotting this, we find that the results are consistent with those generated previously. ::
# Plotting this, we find that the results are consistent with those generated
# previously. ::

fig, axes, tcs = plot_indicator_snapshots(indicators, time_partition, "u", levels=50)
fig.savefig("burgers-oo_ee.jpg")
Expand Down
56 changes: 25 additions & 31 deletions demos/burgers_time_integrated.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
# Adjoint Burgers equation with a time integrated QoI
# ======================================================
#
# So far, we only considered a quantity of interest
# corresponding to a spatial integral at the end time.
# For some problems, it is more suitable to have a QoI
# which integrates in time as well as space.
# So far, we only considered a quantity of interest corresponding to a spatial integral
# at the end time. For some problems, it is more suitable to have a QoI which integrates
# in time as well as space.
#
# Begin by importing from Goalie and the first Burgers demo. ::
# Begin by importing from Firedrake and Goalie. Note that we use the *future* version
# Firedrake's `interpolate` function: :function:`firedrake.__future__.interpolate`. ::

from firedrake import *
from firedrake.__future__ import interpolate

from goalie_adjoint import *

# Redefine the ``get_initial_condition`` and ``get_function_spaces``,
# functions as in the first Burgers demo. ::
# Redefine the ``get_initial_condition`` and ``get_function_spaces``, functions as in
# the first Burgers demo. ::


def get_function_spaces(mesh):
Expand All @@ -26,14 +27,12 @@ def get_initial_condition(mesh_seq):
return {"u": assemble(interpolate(as_vector([sin(pi * x), 0]), fs))}


# The solver needs to be modified slightly in order to take
# account of time dependent QoIs. The Burgers solver
# uses backward Euler timestepping. The corresponding
# quadrature routine is like the midpoint rule, but takes
# the value from the next timestep, rather than the average
# between that and the current value. As such, the QoI may
# be computed by simply incrementing the :attr:`J` attribute
# of the :class:`AdjointMeshSeq` as follows. ::
# The solver needs to be modified slightly in order to take account of time dependent
# QoIs. The Burgers solver uses backward Euler timestepping. The corresponding
# quadrature routine is like the midpoint rule, but takes the value from the next
# timestep, rather than the average between that and the current value. As such, the QoI
# may be computed by simply incrementing the :attr:`J` attribute of the
# :class:`AdjointMeshSeq` as follows. ::


def get_solver(mesh_seq):
Expand Down Expand Up @@ -69,17 +68,15 @@ def solver(index):
return solver


# The QoI is effectively just a time-integrated version
# of the one previously seen.
# The QoI is effectively just a time-integrated version of the one previously seen.
#
# .. math::
# J(u) = \int_0^{T_{\mathrm{end}}} \int_0^1
# \mathbf u(1,y,t) \cdot \mathbf u(1,y,t)
# \;\mathrm dy\;\mathrm dt.
#
# Note that in this case we multiply by the timestep.
# It is wrapped in a :class:`Function` from `'R'` space to avoid
# recompilation if the value is changed. ::
# Note that in this case we multiply by the timestep. It is wrapped in a
# :class:`Function` from `'R'` space to avoid recompilation if the value is changed. ::


def get_qoi(mesh_seq, i):
Expand All @@ -106,9 +103,8 @@ def time_integrated_qoi(t):
end_time, num_subintervals, dt, ["u"], num_timesteps_per_export=1
)

# The only difference when defining the :class:`AdjointMeshSeq`
# is that we specify ``qoi_type="time_integrated"``, rather than
# ``qoi_type="end_time"``. ::
# The only difference when defining the :class:`AdjointMeshSeq` is that we specify
# ``qoi_type="time_integrated"``, rather than ``qoi_type="end_time"``. ::

mesh_seq = AdjointMeshSeq(
time_partition,
Expand All @@ -128,14 +124,12 @@ def time_integrated_qoi(t):
# :figwidth: 90%
# :align: center
#
# With a time-integrated QoI, the adjoint problem
# has a source term at the right-hand boundary, rather
# than a instantaneous pulse at the terminal time. As such,
# the adjoint solution field accumulates at the right-hand
# boundary, as well as propagating westwards.
# With a time-integrated QoI, the adjoint problem has a source term at the right-hand
# boundary, rather than a instantaneous pulse at the terminal time. As such, the adjoint
# solution field accumulates at the right-hand boundary, as well as propagating
# westwards.
#
# In the `next demo <./burgers_oo.py.html>`__, we solve
# the Burgers problem one last time, but using an
# object-oriented approach.
# In the `next demo <./burgers_oo.py.html>`__, we solve the Burgers problem one last
# time, but using an object-oriented approach.
#
# This demo can also be accessed as a `Python script <burgers_time_integrated.py>`__.
10 changes: 6 additions & 4 deletions demos/mantle_convection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
# involve a time derivative. Those are clearly *time-dependent* equations. However,
# time-dependent equations need not involve a time derivative. For example, they might
# include fields that vary with time. Examples of where this might happen are
# in continuous pressure projection approaches, ice sheet and glaciological modelling, and
# mantle convection modelling. In this demo, we illustrate how Goalie can be used
# in continuous pressure projection approaches, ice sheet and glaciological modelling,
# and mantle convection modelling. In this demo, we illustrate how Goalie can be used
# to solve such problems.

# We consider the problem of a mantle convection in a 2D unit square domain. The
Expand All @@ -19,8 +19,10 @@
#
# .. math::
# \begin{align}
# \nabla \cdot \mu \left[\nabla \mathbf{u} + (\nabla \mathbf{u})^T \right] - \nabla p + \mathrm{Ra}\,T\,\mathbf{k} &= 0, \\
# \frac{\partial T}{\partial t} \cdot \mathbf{u}\cdot\nabla T - \nabla \cdot (\kappa\nabla T) &= 0,
# \nabla \cdot \mu \left[\nabla \mathbf{u} + (\nabla \mathbf{u})^T \right] -
# \nabla p + \mathrm{Ra}\,T\,\mathbf{k} &= 0, \\
# \frac{\partial T}{\partial t} \cdot \mathbf{u}\cdot\nabla T
# - \nabla \cdot (\kappa\nabla T) &= 0,
# \end{align}
#
# where :math:`\mu`, :math:`\kappa`, and :math:`\mathrm{Ra}` are constant viscosity,
Expand Down
11 changes: 6 additions & 5 deletions demos/ode.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ def solver(index):

solutions = point_seq.solve_forward()["u"]["forward"]

# Note that the solution trajectory does not include the initial value, so we prepend it.
# We also convert the solution :class:`~.Function`\s to :class:`~.float`\s, for plotting
# purposes. Whilst there is only one subinterval in this example, we show how to loop
# over subintervals, as this is instructive for the general case. ::
# Note that the solution trajectory does not include the initial value, so we prepend
# it. We also convert the solution :class:`~.Function`\s to :class:`~.float`\s, for
# plotting purposes. Whilst there is only one subinterval in this example, we show how
# to loop over subintervals, as this is instructive for the general case. ::

forward_euler_trajectory = [1]
forward_euler_trajectory += [
Expand Down Expand Up @@ -257,7 +257,8 @@ def solver(index):
# .. math::
# \frac{u_{i+1} - u_i}{\Delta t} = (\theta u_{i+1} + (1-\theta) u_i),
#
# where :math:`\theta\in(0,1)`. The standard choice is to take :math:`\theta=\frac12`. ::
# where :math:`\theta\in(0,1)`. The standard choice is to take :math:`\theta=\frac12`.
# ::


def get_solver_crank_nicolson(point_seq):
Expand Down
13 changes: 7 additions & 6 deletions demos/point_discharge2d-goal_oriented.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,11 @@ def adaptor(mesh_seq, solutions, indicators):
#
# Looking at the final adapted mesh, we can make a few observations. Firstly, the mesh
# elements are indeed isotropic. Secondly, there is clearly increased resolution
# surrounding the point source, as well as the "receiver region" which the QoI integrates
# over. There is also a band of increased resolution between these two regions. Finally,
# the mesh has low resolution downstream of the receiver region. This is to be expected
# because we have an advection-dominated problem, so the QoI value is independent of the
# dynamics there.
# surrounding the point source, as well as the "receiver region" which the QoI
# integrates over. There is also a band of increased resolution between these two
# regions. Finally, the mesh has low resolution downstream of the receiver region. This
# is to be expected because we have an advection-dominated problem, so the QoI value is
# independent of the dynamics there.
#
# Goalie also provides drivers for *anisotropic* goal-oriented mesh adaptation. Here,
# we consider the ``anisotropic_dwr_metric`` driver. (See documentation for details.) To
Expand Down Expand Up @@ -372,4 +372,5 @@ def adaptor(mesh_seq, solutions, indicators):
# In the `next demo <./burgers-hessian.py.html>`__, we consider mesh adaptation in the
# time-dependent case.
#
# This demo can also be accessed as a `Python script <point_discharge2d-goal_oriented.py>`__.
# This demo can also be accessed as a
# `Python script <point_discharge2d-goal_oriented.py>`__.
10 changes: 5 additions & 5 deletions demos/point_discharge2d-hessian.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# before progressing with this demo.
#
# In addition to importing from Firedrake and Goalie, we also import the mesh
# adaptation functionality from Firedrake, which can be found in ``firedrake.meshadapt``.
# adaptation functionality from Animate, which can be found in ``animate.adapt``.
# ::

from animate.adapt import adapt
Expand All @@ -20,8 +20,8 @@
from goalie import *

# We again consider the "point discharge with diffusion" test case from the
# `previous demo <./point_discharge2d.py.html>`__, approximating the tracer concentration
# :math:`c` in :math:`\mathbb P1` space. ::
# `previous demo <./point_discharge2d.py.html>`__, approximating the tracer
# concentration :math:`c` in :math:`\mathbb P1` space. ::

field_names = ["c"]

Expand Down Expand Up @@ -187,8 +187,8 @@ def adaptor(mesh_seq, solutions):
)
solutions = mesh_seq.fixed_point_iteration(adaptor, parameters=params)

# Mesh adaptation often gives slightly different results on difference machines. However,
# the output should look something like
# Mesh adaptation often gives slightly different results on difference machines.
# However, the output should look something like
#
# .. code-block:: console
#
Expand Down
6 changes: 4 additions & 2 deletions demos/point_discharge2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
# \left\{\begin{array}{rl}
# \mathbf u\cdot\nabla c - \nabla\cdot(D\nabla c) = S & \text{in}\:\Omega\\
# c=0 & \text{on}\:\partial\Omega_{\mathrm{inflow}}\\
# \nabla c\cdot\widehat{\mathbf n}=0 & \text{on}\:\partial\Omega\backslash\partial\Omega_{\mathrm{inflow}}
# \nabla c\cdot\widehat{\mathbf n}=0 &
# \text{on}\:\partial\Omega\backslash\partial\Omega_{\mathrm{inflow}}
# \end{array}\right.,
#
# for a tracer concentration :math:`c`, with fluid velocity
Expand Down Expand Up @@ -73,7 +74,8 @@ def source(mesh):
# With these ingredients, we can now define the :meth:`get_solver` method. Don't forget
# to apply the corresponding `ad_block_tag` to the solve call. Additionally, we must
# communicate the defined variational form to ``mesh_seq`` using the
# :meth:`mesh_seq.read_form()` method for Goalie to utilise it during error indication. ::
# :meth:`mesh_seq.read_form()` method for Goalie to utilise it during error indication.
# ::


def get_solver(mesh_seq):
Expand Down
7 changes: 0 additions & 7 deletions goalie/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,4 @@
from goalie.function_data import * # noqa
from goalie.error_estimation import * # noqa

from animate.utility import Mesh, VTKFile # noqa

from firedrake.__future__ import interpolate # noqa

import numpy as np # noqa
import os # noqa

__version__ = "0.1"
Loading
Loading