Skip to content

Commit

Permalink
Merge pull request #780 from festim-dev/doctest
Browse files Browse the repository at this point in the history
Test documentation code blocks
  • Loading branch information
RemDelaporteMathurin authored Jul 4, 2024
2 parents 66d2e25 + 48842dd commit 362cf71
Show file tree
Hide file tree
Showing 14 changed files with 193 additions and 72 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/doctest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Documentation test

on: [push, pull_request]

jobs:
docbuild:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Conda
uses: conda-incubator/setup-miniconda@v2
with:
activate-environment: festim-docs
environment-file: docs/environment.yml

- name: Doc Tests
shell: bash -l {0}
run: sphinx-build -b doctest docs/source docs/_build/doctest
1 change: 1 addition & 0 deletions docs/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ dependencies:
- pip>=20.1
- sphinx==7
- folium
- numpy==1.24
- pip:
- sympy
- sphinx_book_theme==1.1.2
Expand Down
28 changes: 16 additions & 12 deletions docs/source/userguide/boundary_conditions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
Boundary conditions
===================

.. testsetup:: BCs

from festim import *

The boundary conditions (BCs) are essential to FESTIM simulations. They describe the mathematical problem at the boundaries of the simulated domain.
If no BC is set on a boundary, it is assumed that the flux is null. This is also called a symmetry BC.

Expand All @@ -17,7 +21,7 @@ Imposing the solution

The value of solutions (concentration, temperature) can be imposed on boundaries with :class:`festim.DirichletBC`:

.. code-block:: python
.. testcode:: BCs

my_bc = DirichletBC(surfaces=[2, 4], value=10, field=0)

Expand All @@ -27,15 +31,15 @@ The value of solutions (concentration, temperature) can be imposed on boundaries

The `value` argument can be space and time dependent by making use of the FESTIM variables ``x``, ``y``, ``z`` and ``t``:

.. code-block:: python
.. testcode:: BCs

from festim import x, y, z, t
my_bc = DirichletBC(surfaces=3, value=10 + x**2 + t, field="T")


To use more complicated mathematical expressions, you can use the sympy package:

.. code-block:: python
.. testcode:: BCs

from festim import x, y, z, t
import sympy as sp
Expand All @@ -46,7 +50,7 @@ To use more complicated mathematical expressions, you can use the sympy package:

The value of the concentration field can be temperature-dependent (useful when dealing with heat-transfer solvers) with :class:`festim.CustomDirichlet`:

.. code-block:: python
.. testcode:: BCs

def value(T):
return 3*T + 2
Expand All @@ -59,14 +63,14 @@ Imposing the flux
When the flux needs to be imposed on a boundary, use the :class:`festim.FluxBC` class.


.. code-block:: python
.. testcode:: BCs

my_bc = FluxBC(surfaces=3, value=10 + x**2 + t, field="T")


As for the Dirichlet boundary conditions, the flux can be dependent on temperature and mobile hydrogen concentration:

.. code-block:: python
.. testcode:: BCs

def value(T, mobile):
return mobile**2 + T
Expand All @@ -86,7 +90,7 @@ Recombination flux
A recombination flux can be set on boundaries as follows: :math:`Kr \, c_\mathrm{m}^n` (See :class:`festim.RecombinationFlux`).
Where :math:`Kr` is the recombination coefficient, :math:`c_\mathrm{m}` is the mobile hydrogen concentration and :math:`n` is the recombination order.

.. code-block:: python
.. testcode:: BCs

my_bc = RecombinationFlux(surfaces=3, Kr_0=2, E_Kr=0.1, order=2)

Expand All @@ -97,7 +101,7 @@ Dissociation flux
Dissociation flux can be set on boundaries as: :math:`Kd \, P` (see :class:`festim.DissociationFlux`).
Where :math:`Kd` is the dissociation coefficient, :math:`P` is the partial pressure of hydrogen.

.. code-block:: python
.. testcode:: BCs

my_bc = DissociationFlux(surfaces=2, Kd_0=2, E_Kd=0.1, P=1e05)

Expand All @@ -107,7 +111,7 @@ Sievert's law of solubility

Impose the mobile concentration of hydrogen as :math:`c_\mathrm{m} = S(T) \sqrt{P}` where :math:`S` is the Sievert's solubility and :math:`P` is the partial pressure of hydrogen (see :class:`festim.SievertsBC`).

.. code-block:: python
.. testcode:: BCs

from festim import t

Expand All @@ -120,7 +124,7 @@ Henry's law of solubility
Similarly, the mobile concentration can be set from Henry's law of solubility :math:`c_\mathrm{m} = K_H P` where :math:`K_H` is the Henry solubility (see :class:`festim.HenrysBC`).


.. code-block:: python
.. testcode:: BCs

from festim import t

Expand All @@ -132,7 +136,7 @@ Plasma implantation approximation
Plasma implantation can be approximated by a Dirichlet boundary condition with the class :class:`festim.ImplantationDirichlet` . Refer to the :ref:`theory` section for more details.


.. code-block:: python
.. testcode:: BCs

from festim import t

Expand All @@ -152,7 +156,7 @@ Heat transfer BCs

A convective heat flux can be set as :math:`\mathrm{flux} = - h (T - T_\mathrm{ext})` (see :class:`festim.ConvectiveFlux`).

.. code-block:: python
.. testcode:: BCs

from festim import t

Expand Down
61 changes: 42 additions & 19 deletions docs/source/userguide/export_post_processing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ The most straightforward way to export solutions (concentrations, temperature) w
This class leverages the ``XDMFFile`` class of ``fenics`` and allows solutions to be exported in the XDMF format.
The following example shows how to export the solution of a 1D problem:

.. code-block:: python
.. testcode::

import festim as F
import numpy as np

my_model = F.Simulation()
my_model.mesh = F.MeshFromVertices([0, 1, 2, 3])
my_model.mesh = F.MeshFromVertices(np.linspace(0, 1, 60))
my_model.materials = F.Material(id=1, D_0=1, E_D=0)
my_model.boundary_conditions = [
F.DirichletBC(surfaces=[1, 2], value=0, field="solute"),
Expand All @@ -54,6 +55,11 @@ The following example shows how to export the solution of a 1D problem:
my_model.initialise()
my_model.run()

.. testoutput::
:options: +ELLIPSIS
:hide:

...

Running this should produce a file called ``mobile_conc.xdmf`` in the current directory.
The file can then be opened in Paraview or any other software that can read XDMF files.
Expand All @@ -63,7 +69,7 @@ It is possible to change this behaviour to limit the number of times the file is
By setting the ``mode`` attribute to ``10``, for example, the solution will be exported every 10 timesteps.
Setting it to ``last`` will export the solution only at the last timestep.

.. code-block:: python
.. testcode::

my_model.exports = [
F.XDMFExport(
Expand All @@ -75,7 +81,7 @@ Setting it to ``last`` will export the solution only at the last timestep.
)
]

The ``checkpoint`` attribute must be set to ``True`` for the XDMF file to be readable by Paraveiw.
The ``checkpoint`` attribute must be set to ``True`` for the XDMF file to be readable by Paraview.

^^^^^^^^^^^^^^^
TXT export (1D)
Expand All @@ -84,7 +90,7 @@ TXT export (1D)
The ``TXTExport`` class allows solutions to be exported in a simple text format.
It works in 1D only. For multi-dimensional problems, use the :class:`festim.XDMFExport` class instead.

.. code-block:: python
.. testcode::

import festim as F

Expand All @@ -95,7 +101,7 @@ This file will contain the solution of the ``solute`` field at the degrees of fr

To only export at specific times in the simulation, use the ``times`` argument:

.. code-block:: python
.. testcode::

my_export = F.TXTExport(
field="solute", filename="./mobile_conc.txt", times=[0, 1, 2, 3]
Expand All @@ -108,7 +114,7 @@ Point value
If information about the solution at a specific point is needed, the :class:`festim.PointValue` class can be used.
It is implemented as a derived quantity. See :ref:`Derived quantities` for more information. Here are a few examples:

.. code-block:: python
.. testcode::

import festim as F

Expand All @@ -129,7 +135,7 @@ First, you want to create a :class:`festim.DerivedQuantities` object. This will
Then, you can add the derived quantities you want to compute to this object.
Finally, you can add the :class:`festim.DerivedQuantities` object to the simulation object.

.. code-block:: python
.. testcode::

my_derived_quantities = F.DerivedQuantities(
[
Expand All @@ -140,49 +146,55 @@ Finally, you can add the :class:`festim.DerivedQuantities` object to the simulat
]
)

my_model.exports = [my_derived_quantities, ....]
my_model.exports = [my_derived_quantities]


The complete list of derived quantities can be found at: :ref:`Exports`.

The data can be accessed in three different ways:
- directly from the :class:`festim.DerivedQuantities` (plural) object:

.. code-block:: python
.. testcode::

my_derived_quantities = F.DerivedQuantities(
[
F.SurfaceFlux(field="solute", surface=3),
F.SurfaceFlux(field="T", surface=1),
F.AverageVolume(field="T", volume=1),
F.AverageVolume(field="retention", volume=1),
F.TotalVolume(field="retention", volume=2),
]
)

my_model.exports = [my_derived_quantities, ....]
my_model.exports = [my_derived_quantities]

my_model.initialise()
my_model.run()

print(my_derived_quantities.t)
print(my_derived_quantities.data)

.. testoutput::
:options: +ELLIPSIS
:hide:

...

- from the :class:`festim.DerivedQuantity` (singular) object (eg. ``F.SurfaceFlux(...)``):

.. code-block:: python
.. testcode::

flux_surf_3 = F.SurfaceFlux(field="solute", surface=3)

my_derived_quantities = F.DerivedQuantities(
[
flux_surf_3,
F.SurfaceFlux(field="T", surface=1),
F.AverageVolume(field="T", volume=1),
F.AverageVolume(field="retention", volume=1),
F.TotalVolume(field="retention", volume=2),
]
)

my_model.exports = [my_derived_quantities, ....]
my_model.exports = [my_derived_quantities]

my_model.initialise()
my_model.run()
Expand All @@ -191,25 +203,36 @@ The data can be accessed in three different ways:
print(flux_surf_3.data)
print(my_derived_quantities[2].data)

.. testoutput::
:options: +ELLIPSIS
:hide:

...

- export and read from a .csv file:

.. code-block:: python
.. testcode::

my_derived_quantities = F.DerivedQuantities(
[
F.SurfaceFlux(field="solute", surface=3),
F.SurfaceFlux(field="T", surface=1),
F.AverageVolume(field="T", volume=1),
F.AverageVolume(field="retention", volume=1),
F.TotalVolume(field="retention", volume=2),
],
filename="./my_derived_quantities.csv",
)

my_model.exports = [my_derived_quantities, ....]
my_model.exports = [my_derived_quantities]

my_model.initialise()
my_model.run()

.. testoutput::
:options: +ELLIPSIS
:hide:

...

By default, the derived quantities will be computed at each timestep and exported at the last timestep.
This behaviour can be changed by setting the ``nb_iterations_between_compute`` and ``nb_iterations_between_exports`` attributes of the :class:`festim.DerivedQuantities` object.
Expand All @@ -219,7 +242,7 @@ This behaviour can be changed by setting the ``nb_iterations_between_compute`` a
my_derived_quantities = F.DerivedQuantities(
[
F.SurfaceFlux(field="solute", surface=3),
F.SurfaceFlux(field="T", surface=1),
F.AverageVolume(field="T", volume=1),
F.AverageVolume(field="retention", volume=1),
F.TotalVolume(field="retention", volume=2),
],
Expand Down
10 changes: 5 additions & 5 deletions docs/source/userguide/initial_conditions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ The initial conditions are essential to transient FESTIM simulations. They descr
By default, the initial conditions are set to zero.
However, it is possible to set the initial conditions with the :class:`festim.InitialCondition` class.

.. code-block:: python
.. testcode::

import festim as F

my_ic = F.InitialCondition(value=10, field=0)

The value can also be a function of space:

.. code-block:: python
.. testcode::

import festim as F
from festim import x, y, z
Expand All @@ -23,14 +23,14 @@ The value can also be a function of space:

Initial conditions can also be read from a previously written XDMF file. This is useful when restarting a simulation.

.. code-block:: python
.. testcode::

import festim as F

my_ic = F.InitialCondition(
filename="ic_file.xdmf",
value="ic_file.xdmf",
label="mobile",
timestep=-1,
time_step=-1,
field=0
)

Expand Down
Loading

0 comments on commit 362cf71

Please sign in to comment.