Skip to content

Commit

Permalink
Increase visibility on mismatch between dof ordering and node ordering (
Browse files Browse the repository at this point in the history
  • Loading branch information
termi-official authored Feb 14, 2025
1 parent ed1f6a9 commit 5f20e7b
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 13 deletions.
28 changes: 22 additions & 6 deletions docs/src/literate-howto/postprocessing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,28 @@
#
# ## Introduction
#
# After running a simulation, we usually want to visualize the results in different ways.
# The `L2Projector` and the `PointEvalHandler` build a pipeline for doing so. With the `L2Projector`,
# integration point quantities can be projected to the nodes. The `PointEvalHandler` enables evaluation of
# the finite element approximated function in any coordinate in the domain. Thus with the combination of both functionalities,
# both nodal quantities and integration point quantities can be evaluated in any coordinate, allowing for example
# cut-planes through 3D structures or cut-lines through 2D-structures.
# After running a simulation, we usually want to postprocess and visualize the results in
# different ways. Ferrite provides several tools to facilitate these tasks:
#
# - L2 projection of (discrete) data onto FE interpolations using the `L2Projector`
# - Evalutation of fields (solutions, projections, etc) at arbitrary, user-defined, points
# using the `PointEvalHandler`
# - Builtin functionality for exporting data (solutions, cell data, projections, etc) to
# the VTK format
# - [Makie.jl](https://docs.makie.org/) based plotting using
# [FerriteViz.jl](https://ferrite-fem.github.io/FerriteViz.jl/)
#
# This how-to demonstrates the VTK export, the `L2Projector` for projecting discrete
# quadrature point data onto a continuous FE interpolation, and the `PointEvalHandler` for
# evaluating the FE solution, and the projection, along a user-defined cut line through the
# domain.

# !!! warning "Custom visualization"
# A common assumption is that the numbering of degrees of freedom matche the numbering
# of the nodes in the grid. This is *NOT* the case in Ferrite. If the available tools
# don't suit your needs and you decide to "roll your own" visualization you need to be
# aware of this and take it into account. For the specific case of evaluating the
# solution at the grid nodes you can use [`evaluate_at_grid_nodes`](@ref).
#
# This example continues from the Heat equation example, where the temperature field was
# determined on a square domain. In this example, we first compute the heat flux in each
Expand Down
10 changes: 10 additions & 0 deletions docs/src/literate-tutorials/heat_equation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ dh = DofHandler(grid)
add!(dh, :u, ip)
close!(dh);

# !!! warning "Numbering of degrees of freedom"
# A common assumption is that the numbering of degrees of freedom follows the global
# numbering of the nodes in the grid. This is *NOT* the case in Ferrite. For more
# details, see the [Ferrite numbering rules](@ref "Ordering-of-Dofs").

# Now that we have distributed all our dofs we can create our tangent matrix,
# using `allocate_matrix`. This function returns a sparse matrix
# with the correct entries stored.
Expand Down Expand Up @@ -210,6 +215,11 @@ K, f = assemble_global(cellvalues, K, dh);
apply!(K, f, ch)
u = K \ f;

# !!! warning "Numbering of degrees of freedom"
# Once again, recall that numbering of degrees of freedom does *NOT* follow the global
# numbering of the nodes in the grid. Specifically, `u[i]` is *NOT* the temperature at
# node `i`.

# ### Exporting to VTK
# To visualize the result we export the grid and our field `u`
# to a VTK-file, which can be viewed in e.g. [ParaView](https://www.paraview.org/).
Expand Down
10 changes: 10 additions & 0 deletions docs/src/literate-tutorials/linear_elasticity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ dh = DofHandler(grid)
add!(dh, :u, ip)
close!(dh);

# !!! warning "Numbering of degrees of freedom"
# A common assumption is that the numbering of degrees of freedom follows the global
# numbering of the nodes in the grid. This is *NOT* the case in Ferrite. For more
# details, see the [Ferrite numbering rules](@ref "Ordering-of-Dofs").

# ### Boundary conditions
# We set Dirichlet boundary conditions by fixing the motion normal to the bottom and left
# boundaries. The last argument to `Dirichlet` determines which components of the field should be
Expand Down Expand Up @@ -315,6 +320,11 @@ assemble_external_forces!(f_ext, dh, getfacetset(grid, "top"), facetvalues, trac
apply!(K, f_ext, ch)
u = K \ f_ext;

# !!! warning "Numbering of degrees of freedom"
# Once again, recall that numbering of degrees of freedom does *NOT* follow the global
# numbering of the nodes in the grid. Specifically, `u[2 * i - 1]` and `u[2 * i]` are
# *NOT* the displacements at node `i`.

# ### Postprocessing
# In this case, we want to analyze the displacements, as well as the stress field.
# We calculate the stress in each quadrature point, and then export it in two different
Expand Down
19 changes: 12 additions & 7 deletions docs/src/topics/fe_intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,18 @@ set of *elements* or *cells*. We call this geometric discretization *grid* (or *
and denote it with $\Omega_h$. In this example the corners of the triangles are called
*nodes*.

Next we introduce the finite element approximation $u_\mathrm{h} \approx u$ as a sum of N nodal
*shape functions*, where we denote each of these function by $\phi_i$ and the corresponding
*nodal values* $\hat{u}_i$. Note that *shape functions* are sometimes referred to as
*basis functions* or *trial functions*, and instead of $\phi_i$ they are sometimes denoted $N_i$.
In this example we choose to approximate the test function in the same way. This approach is known
as the *Galerkin finite element method*. Formally we write the evaluation of our approximations
at a specific point $\mathbf{x}$ in our domain $\Omega$ as:
Next, we introduce the finite element approximation $u_\mathrm{h} \approx u$ as linear combination of
*shape functions*, $\phi_i$. The corresponding weights are usually called *degree of freedoms* (dofs), $\hat{u}_i$.
Sometimes, the dofs are called *weights* or *nodal values*. In Ferrite, the numbering of the dofs does not correspond
to the node numbers in the grid. While such numbering is common in basic finite element codes,
Ferrite supports different approximations of the finite element fields and the geometry, prohibiting
such basic numbering. For more details, see the [Ferrite numbering rules](@ref "Ordering-of-Dofs").

Note that *shape functions* are sometimes referred to as *basis functions* or *trial functions*,
and instead of $\phi_i$ they are sometimes denoted $N_i$. In this example we choose to approximate
the test function in the same way. This approach is known as the *Bubnov-Galerkin finite element
method*. Formally we write the evaluation of our approximations at a specific point $\mathbf{x}$
in our domain $\Omega$ as:

```math
u_\mathrm{h}(\mathbf{x}) = \sum_{i=1}^{\mathrm{N}} \phi_i(\mathbf{x}) \, \hat{u}_i,\qquad
Expand Down
4 changes: 4 additions & 0 deletions src/Dofs/DofHandler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ add!(dh, :u, ip_u)
add!(dh, :p, ip_p)
close!(dh)
```
!!! note "Numbering of degree of freedom"
Note that the numbering of degrees of freedom do *NOT* follow the global numbering of
nodes in the associated grid.
"""
function DofHandler(grid::G) where {dim, G <: AbstractGrid{dim}}
ncells = getncells(grid)
Expand Down

0 comments on commit 5f20e7b

Please sign in to comment.