Skip to content

Commit 837afc1

Browse files
authored
documentation etc overhaul (#69)
* improved docstrings, show functions, documentation etc. with assistance of github copilot
1 parent 0559a69 commit 837afc1

35 files changed

+902
-679
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# CHANGES
22

3+
4+
## v1.4.0
5+
6+
### Changed
7+
- improved docstrings, documentation
8+
- improved print_convergencehistory and show functions
9+
310
## v1.3.0 June 17, 2025
411

512
### Added

README.md

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,54 +4,62 @@
44
[![DOI](https://zenodo.org/badge/668345991.svg)](https://zenodo.org/doi/10.5281/zenodo.10563834)
55
[![code style: runic](https://img.shields.io/badge/code_style-%E1%9A%B1%E1%9A%A2%E1%9A%BE%E1%9B%81%E1%9A%B2-black)](https://github.com/fredrikekre/Runic.jl)
66

7-
# ExtendableFEM
8-
High Level API Finite Element Methods based on [ExtendableGrids.jl](https://github.com/WIAS-PDELib/ExtendableGrids.jl) (for grid management)
9-
and [ExtendableFEMBase.jl](https://github.com/WIAS-PDELib/ExtendableFEMBase.jl) (for finite element basis functions and dof management).
10-
It offers a ProblemDescription interface, that basically involves assigning Unknowns and Operators. Such operators usually stem from a weak formulation of the problem and mainly consist of three types that can be customized via kernel functions:
7+
**ExtendableFEM.jl** is a high-level, extensible finite element method (FEM) library for Julia, supporting flexible problem descriptions, custom operators, and advanced grid management.
118

12-
- BilinearOperator,
13-
- LinearOperator,
14-
- NonlinearOperator (that automatically assemble Newton's method by automatic differentiation)
9+
## Features
1510

16-
### Quick Example
11+
- High-level, extensible API for solving PDE problems by finite element methods
12+
- Flexible `ProblemDescription` interface for assigning unknowns and operators
13+
- Supports custom kernel functions for bilinear, linear, and nonlinear forms
14+
- Automatic assembly and Newton's method for NonlinearOperators
15+
- Builds upon [ExtendableGrids.jl](https://github.com/WIAS-PDELib/ExtendableGrids.jl) and low level structures from [ExtendableFEMBase.jl](https://github.com/WIAS-PDELib/ExtendableFEMBase.jl)
1716

18-
The following minimal example demonstrates how to setup a Poisson problem.
17+
## Quick Example
18+
19+
The following minimal example demonstrates how to set up and solve a Poisson problem:
1920

2021
```julia
2122
using ExtendableFEM
2223
using ExtendableGrids
2324

24-
# build/load any grid (here: a uniform-refined 2D unit square into triangles)
25+
# Build a uniform-refined 2D unit square grid with triangles
2526
xgrid = uniform_refine(grid_unitsquare(Triangle2D), 4)
2627

27-
# create empty PDE description
28+
# Create a new PDE description
2829
PD = ProblemDescription()
2930

30-
# create and assign unknown
31+
# Define and assign the unknown
3132
u = Unknown("u"; name = "potential")
3233
assign_unknown!(PD, u)
3334

34-
# assign Laplace operator
35+
# Assign Laplace operator (diffusion term)
3536
assign_operator!(PD, BilinearOperator([grad(u)]; factor = 1e-3))
3637

37-
# assign right-hand side data
38+
# Assign right-hand side data
3839
function f!(fval, qpinfo)
3940
x = qpinfo.x # global coordinates of quadrature point
4041
fval[1] = x[1] * x[2]
4142
end
4243
assign_operator!(PD, LinearOperator(f!, [id(u)]))
4344

44-
# assign boundary data (here: u = 0)
45+
# Assign Dirichlet boundary data (u = 0)
4546
assign_operator!(PD, HomogeneousBoundaryData(u; regions = 1:4))
4647

47-
# discretise = choose FESpace
48+
# Discretize: choose finite element space
4849
FEType = H1Pk{1,2,3} # cubic H1-conforming element with 1 component in 2D
4950
FES = FESpace{FEType}(xgrid)
5051

51-
# solve
52-
sol = solve!(Problem, [FES])
52+
# Solve the problem
53+
sol = solve!(PD, [FES])
5354

54-
# plot
55+
# Plot the solution
5556
using PyPlot
5657
plot(id(u), sol; Plotter = PyPlot)
5758
```
59+
60+
## Citing
61+
62+
If you use ExtendableFEM.jl in your research, please cite [this Zenodo record](https://zenodo.org/doi/10.5281/zenodo.10563834).
63+
64+
## License
65+
ExtendableFEM.jl is licensed under the MIT License. See [LICENSE](https://github.com/WIAS-PDELib/ExtendableFEM.jl/blob/master/LICENSE) for details.

docs/src/bilinearoperator.md

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
1-
21
# BilinearOperator
32

4-
A bilinear operator allows to add matrices to the system matrix that usually refer to
5-
linearisations of the PDE operators or stabilisations. If the bilinear operator
6-
lives on face entities, also jumps of operators can be involved, if they are naturally
7-
continuous for the finite element space in operation (also jumps for broken spaces)
8-
and only involve degrees of freedom on the face, e.g.
9-
normal jumps for Hdiv spaces or jumps for H1-conforming spaces or tangential jumps
10-
of Hcurl spaces. For all other discontinuous operator evaluations
11-
(that needs to evaluat more than the degrees of freedom on the face)
12-
there is the possibility to use BilinearOperatorDG.
13-
It is also possible to assign a matrix assembled by the user as a BilinearOperator.
3+
`BilinearOperator` provides a flexible interface for defining bilinear forms (matrices) in finite element problems. These operators typically represent (linearizations of) PDE operators, stabilization terms, or custom user-defined couplings. The interface supports both standard and discontinuous Galerkin (DG) forms, and allows for custom assembly on cells, faces, or other grid entities.
4+
5+
## Overview
6+
7+
- **Standard Bilinear Operators:** Assemble contributions to the system matrix, including diffusion, mass, and convection terms, as well as custom couplings. Supports both cell- and face-based assembly, including jump terms for conforming and piecewise spaces that only require the dofs on that entity.
8+
- **Discontinuous Galerkin (DG) Operators:** Use `BilinearOperatorDG` for forms that require evaluation of jumps or averages involving all degrees of freedom on neighboring cells (e.g., interior penalty stabilization, gradient jumps for H1 elements).
9+
- **Custom Matrices:** You can also assign a user-assembled matrix as a `BilinearOperator`.
1410

1511
## Constructors
1612

@@ -22,10 +18,7 @@ Order = [:type, :function]
2218

2319
## BilinearOperatorDG
2420

25-
BilinearOperatorDG is intended for bilinear forms that involves jumps of discontinuous quantities
26-
on faces whose assembly requires evaluation of all degrees of freedom on the neighbouring cells,
27-
e.g. gradient jumps for H1 conforming functions. In this case the assembly loop triggers
28-
integration along the boundary of the cells.
21+
`BilinearOperatorDG` is intended for bilinear forms that involve jumps or averages of discontinuous quantities on faces, requiring access to all degrees of freedom on neighboring cells. This is essential for DG methods and certain stabilization techniques.
2922

3023
```@autodocs
3124
Modules = [ExtendableFEM]
@@ -35,11 +28,10 @@ Order = [:type, :function]
3528

3629
## Examples
3730

38-
Below two examples illustrate some use cases.
31+
### Example: Stokes Operator
3932

40-
### Example - Stokes operator
33+
For the linear operator of a Stokes problem, a kernel could look like:
4134

42-
For the linear operator of a Stokes problem a kernel could look like
4335
```julia
4436
μ = 0.1 # viscosity parameter
4537
function kernel!(result, input, qpinfo)
@@ -52,26 +44,29 @@ function kernel!(result, input, qpinfo)
5244
return nothing
5345
end
5446
```
55-
and the coressponding BilinearOperator constructor call reads
47+
48+
The corresponding `BilinearOperator` constructor call reads:
49+
5650
```julia
5751
u = Unknown("u"; name = "velocity")
5852
p = Unknown("p"; name = "pressure")
5953
BilinearOperator(kernel!, [grad(u), id(p)]; use_sparsity_pattern = true)
6054
```
61-
The additional argument causes that the zero pressure-pressure block of the matrix is not (even tried to be) assembled,
62-
since ```input[5]``` does not couple with ```result[5]```.
6355

56+
The `use_sparsity_pattern` argument ensures that the zero pressure-pressure block of the matrix is not assembled, since `input[5]` does not couple with `result[5]`.
57+
58+
### Example: Interior Penalty Stabilization
6459

65-
### Example - interior penalty stabilization
60+
A popular stabilization for convection-dominated problems is based on jumps of the gradient, which can be realized with the following kernel:
6661

67-
A popular convection stabilization is based on the jumps of the gradient, which can be realised with
68-
the kernel
6962
```julia
7063
function stab_kernel!(result, input, qpinfo)
7164
result .= input .* qpinfo.volume^2
7265
end
7366
```
74-
and the BilinearOperatorDG constructor call
67+
68+
and the `BilinearOperatorDG` constructor call:
69+
7570
```julia
7671
u = Unknown("u")
7772
assign_operator!(PD, BilinearOperatorDG(stab_kernel!, [jump(grad(u))]; entities = ON_IFACES, factor = 0.01))

docs/src/callbackoperator.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,37 @@
1-
21
# CallbackOperator
32

4-
A callback operator passes the matrix and rhs to a user-defined function where they can be modified as desired.
5-
An example where this is used is Example265.
3+
`CallbackOperator` provides a flexible interface for injecting custom assembly logic into the finite element workflow. It delegates the assembly of the system matrix and right-hand side to a user-supplied callback function, allowing for advanced or nonstandard modifications that are difficult to express with standard operators.
64

7-
## Constructors
5+
## Constructor
86

97
```@autodocs
108
Modules = [ExtendableFEM]
119
Pages = ["common_operators/callback_operator.jl"]
1210
Order = [:type, :function]
1311
```
12+
13+
## Example
14+
15+
```julia
16+
function my_callback!(A, b, args; assemble_matrix=true, assemble_rhs=true, time=0, kwargs...)
17+
# Example: add a constant to the diagonal
18+
if assemble_matrix && A !== nothing
19+
for i in 1:min(size(A)...)
20+
A[i, i] += 1.0
21+
end
22+
end
23+
if assemble_rhs && b !== nothing
24+
b .+= 2.0
25+
end
26+
end
27+
op = CallbackOperator(my_callback!; u_args=[1], name="CustomOp")
28+
```
29+
30+
## When to Use
31+
32+
- Custom or experimental PDE terms
33+
- Coupling to external codes or data
34+
- Advanced boundary or interface conditions
35+
- Prototyping new assembly strategies
36+
37+
See also: [Example265](https://wias-pdelib.github.io/ExtendableFEM.jl/stable/examples/) for a practical use case.

docs/src/combinedofs.md

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,39 @@
1-
21
# CombineDofs
32

3+
`CombineDofs` provides a mechanism to couple degrees of freedom (DOFs) in a finite element system. This is especially useful for enforcing periodic boundary conditions, multi-point constraints, or other situations where DOFs from different locations or unknowns should be treated as identical in the assembled system.
4+
45
```@autodocs
56
Modules = [ExtendableFEM]
67
Pages = ["common_operators/combinedofs.jl"]
78
Order = [:type, :function]
89
```
910

10-
The following function might be useful to find out the dofs
11-
the need to be coupled for periodic
12-
boundary conditions:
11+
## Periodic Boundary Conditions
1312

13+
To set up periodic boundary conditions, you often need to determine which DOFs should be coupled. The following utility functions can help:
1414

1515
```@docs
1616
get_periodic_coupling_info
17+
get_periodic_coupling_matrix
1718
```
19+
20+
## Example: Periodic Boundary Coupling (extract from Example212)
21+
22+
Suppose you want to enforce periodicity between the left and right boundaries of a 2D domain. You can use `get_periodic_coupling_matrix` to find the corresponding DOFs, and then use `CombineDofs` to couple them in the system. The following code is adapted from [Example212_PeriodicBoundary2D.jl](https://github.com/WIAS-PDELib/ExtendableFEM.jl/blob/main/examples/Example212_PeriodicBoundary2D.jl):
23+
24+
```julia
25+
# Define a function to map points on the left to the right boundary
26+
function give_opposite!(y, x)
27+
y .= x
28+
y[1] = width - x[1]
29+
return nothing
30+
end
31+
32+
# Compute the coupling matrix
33+
coupling_matrix = get_periodic_coupling_matrix(FES, reg_left, reg_right, give_opposite!)
34+
35+
# Assign the CombineDofs operator to the problem description
36+
assign_operator!(PD, CombineDofs(u, u, coupling_matrix))
37+
```
38+
39+
See also [Example212](https://wias-pdelib.github.io/ExtendableFEM.jl/stable/examples/) and [Example312](https://wias-pdelib.github.io/ExtendableFEM.jl/stable/examples/) for more advanced use cases and details on periodic boundary conditions.

docs/src/examples_intro.md

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
1-
# About the examples
2-
3-
The examples have been designed with the following issues in mind:
4-
- they run from the Julia REPL
5-
- each example is a Julia module named similar to the basename of the example file.
6-
- an example can be used as the starting point for a project
7-
- some examples define test cases for the test suite
8-
- ExampleXYZ with X = A can be considered advanced and uses low-level structures
9-
and/or demonstrates customisation features or experimental features
10-
- the default output of the main function is printed on the website and can be
11-
used to check if the code runs as expected (unfortunately REPL messages are not recorded)
12-
- printed assembly and solving times (especially in a first iteration) can be much larger due to first-run compilation times,
13-
the printouts in the documentation are taken from a second run after compilations are done
14-
15-
16-
## Running the examples
17-
18-
In order to run `ExampleXXX`, perform the following steps:
19-
20-
- Download the example file (e.g. via the source code link at the top)
21-
- Make sure all used packages are installed in your Julia environment
22-
- In the REPL:
23-
```
24-
julia> include("ExampleXXX.jl")`
25-
26-
julia> ExampleXXX.main()
27-
```
28-
- Some examples offer visual output via the optional argument Plotter = PyPlot or Plotter = GLMakie
29-
(provided the package PyPlot/GLMakie is installed and loaded)
1+
# About the Examples
2+
3+
The examples in this package are designed to be practical, reproducible, and educational. They demonstrate a wide range of finite element applications and PDE model problems.
4+
5+
## Design Principles
6+
7+
- All examples can be run directly from the Julia REPL.
8+
- Each example is a Julia module named after the file.
9+
- Examples can serve as templates for your own projects.
10+
- Many examples include test cases for automated verification.
11+
12+
## Running the Examples
13+
14+
To run an example (e.g., `Example212_PeriodicBoundary2D`):
15+
16+
1. Download the example file (see the source code link at the top of the example page).
17+
2. Ensure all required packages are installed in your Julia environment.
18+
3. In the Julia REPL:
19+
20+
```julia
21+
julia> include("Example212_PeriodicBoundary2D.jl")
22+
julia> Example212_PeriodicBoundary2D.main()
23+
```
24+
25+
4. Some examples offer visual output via the optional argument `Plotter = PyPlot` or `Plotter = GLMakie` (provided the package is installed and loaded):
26+
27+
```julia
28+
julia> Example212_PeriodicBoundary2D.main(Plotter = PyPlot)
29+
```

docs/src/faceinterpolator.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
1-
# Face interpolator
1+
# Face Interpolator
2+
3+
The face interpolator provides tools for evaluating and interpolating finite element functions on mesh faces. This is particularly useful for postprocessing tasks that require access to traces or jumps of functions across element boundaries.
4+
5+
## API Reference
26

37
```@autodocs
48
Modules = [ExtendableFEM]
59
Pages = ["common_operators/discface_interpolator.jl"]
610
Order = [:type, :function]
711
```
12+
13+
## Example Usage (extracted from Example210)
14+
15+
Suppose you want to compute the jumps of the gradient of a scalar-valued
16+
Lagrange finite element function on the interior edges, e.g. to compute an a posteriori error estimator.
17+
18+
```julia
19+
function gradnormalflux!(result, ∇u, qpinfo)
20+
result[1] = dot(∇u, qpinfo.normal)
21+
end
22+
NormalJumpProjector = FaceInterpolator(gradnormalflux!, [jump(grad(u))]; resultdim = 1, only_interior = true)
23+
Jumps4Faces = evaluate!(NormalJumpProjector, sol)
24+
```
25+
26+
See the [Example212](https://wias-pdelib.github.io/ExtendableFEM.jl/stable/examples/) for the complete example.

docs/src/fixdofs.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
21
# FixDofs
32

3+
`FixDofs` provides a mechanism to fix (constrain) specific degrees of freedom (DOFs) in a finite element system to given values.
4+
5+
## API Reference
6+
47
```@autodocs
58
Modules = [ExtendableFEM]
69
Pages = ["common_operators/fixdofs_operator.jl"]

docs/src/homogeneousdata.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1-
21
# HomogeneousData
32

3+
`HomogeneousData` provides a convenient way to enforce homogeneous (zero) Dirichlet boundary conditions or constraints in a finite element problem. It automatically sets the solution to zero on specified regions or entities.
4+
5+
## API Reference
6+
47
```@autodocs
58
Modules = [ExtendableFEM]
69
Pages = ["common_operators/homogeneousdata_operator.jl"]
710
Order = [:type, :function]
811
```
12+
13+
## Example: Zero Dirichlet Boundary Condition
14+
15+
```julia
16+
# Impose u = 0 on boundary region 1
17+
assign_operator!(PD, HomogeneousBoundaryData(u; regions = [1]))
18+
```

0 commit comments

Comments
 (0)