The Finite Element Method
The aim of the Finite Element Method (FEM) is to solve (or more precisely approximate the solution of) a Partial Differential Equation (PDE) using a computer. In general the solution to a PDE is a function. Unfortunately it is computationally intractable to task a computer with finding this underlying function. The idea to resolve this issue is to parametrize a family of functions with the aim of computing the parameters through solving a linear system of equations. There is a plethora of ways to get to such a linear system of equations, with the most common being the so-called Galerkin approach.
1. Getting the computer to understand functions
In the most basic terms, computers are only capable of understanding numbers, which means that they are inherently unable to solve equations where the unknowns are functions. This is a problem when trying to solve differential equations. To solve this problem, the functions are instead approximated using parameterizations for which the coefficients (numbers) are unknown. Intuitively, these numbers are exactly what the computer is asked to find. For element methods, this parameterization is chosen to be the simplest possible: a linear combination of functions
(1)
where is the unknown function being approximated. Note that the linearity is with respect to the unknown parameters , but not necessarily in the known basis functions .
One might ask: How does the above relate to the Finite Element Method? The answer is that the functions are chosen to be simpler functions with support equal to only a few subdomains of the original domain. These subdomains are commonly referred to as elements.
Interactive figureย 1: Piecewise polynomial approximation
Interactive figure 1 (Piecewise polynomial approximation)ย ย In one dimension an approximation of the form (1) is easy to visualize. The graph shows the function (dashed) and the approximation (solid) on elements (every other one shaded). The coefficients are the large dots, and each basis function , scaled by its , is drawn faint. There are two ways to improve the approximation: more elements11 Called -refinement, as it decreases the element size . or basis functions of a higher polynomial order .22 Called -refinement. Here is the order, not the function being approximated.
2. The Finite Element Method for the Helmholtz equation
In acoustics we are often interested in solving the Helmholtz equation, given as
(2)
where is most often referred to as the wavenumber. In its current form the basis functions must be twice differentiable; piecewise linear functions, for example, have a vanishing second derivative inside each element and cannot be used. This constraint can be relieved using the so-called weak formulation. In order to do so we multiply the Helmholtz equation with a so-called test function followed by an integration over the domain
(3)
Utilizing integration by parts on the term including the Laplacian we can move derivatives from onto as
(4)
In the above the constraint on the smoothness of has been reduced to first order. Furthermore the last term
(5)
can be used to include the boundary conditions into the equation. For simplification purposes we will in the following assume that the above is equal to zero. As such we have
(6)
We will now use the Galerkin approach to discretize the above equation. Note that โGalerkinโ simply refers to the approach where and are discretized using the same basis functions (). In short this means that we introduce
(7)
where is a set of arbitrary coefficients that parametrize a whole family of test functions and are the coefficients that we aim to find. Inserting the approximations it follows that
(8)
We can make the above equality hold for all possible test functions, i.e. for all , if we find such that
(9)
This is exactly what we do in Finite Element computations. As a shorthand the above can be written as
(10)
where is referred to as the stiffness matrix and as the mass matrix. In the literature the equation can also be found as
(11)
where is the propagation speed and is the angular frequency.
3. What is an element?
A key insight is that the element serves two purposes: it represents a subdomain of the original domain (also referred to as the geometry) while also describing parts of the unknown function(s) of interest. In general this subdomain is described by a parameterization, i.e. the element, as
(12)
where the superscript denotes the element number, is a matrix with columns equal to the interpolation nodes of the geometry, are the so-called shape functions, is the element in global coordinates and are the local coordinates. In addition to the geometric interpolation of each element, we need to further define interpolations of the unknown functions, which in acoustics is usually taken as the pressure . On element this interpolation can be done as
(13)
where is a permutation-like matrix that extracts the relevant values of and the relevant functions of and orders them such that they correspond to the local values and the local basis functions .
Exampleย 1: Linear triangular elements
Example 1 (Linear triangular elements)ย ย
The linear shape functions for a triangular element can have the form
(14)
The choice in the wording is because the ordering of the columns of can change the ordering of the rows of or vice versa. This is something that one should keep in mind in practice when using different mesh file formats. Taking the second element of the figure above as an example, it could be that
(15)
Note that extending the geometric interpolation to higher orders is as simple as adding more rows/functions to as well as more columns/points to .
Exampleย 2: Basis functions for continuous linear interpolation
Example 2 (Basis functions for continuous linear interpolation)ย ย
Continuous linear basis functions on triangular elements are similar to shape functions for a linear triangular element and differ only in the fact that they are the transpose:
(16)
where the subscript โcontinuousโ is only there to highlight that it is a continuous formulation. Again, the ordering of the columns of the row vector depends on the ordering of the element corners.
Exampleย 3: Element localization matrix
Example 3 (Element localization matrix)ย ย For a continuous linear element all three corners correspond to a value of the global vector . For example, the second element in the continuous plot has local corner values given by . This element would have given as
(17)
so that . Note that is only an artifact of the mathematical description. Any reasonable implementation should use indexing instead of multiplication with .
4. Computing the stiffness and mass matrices
Using the element description of both the geometry and the pressure function the mass matrix can be computed as follows
(18)
where the first approximation is due to the geometry being approximated by the elements, and the second is due to the quadrature with the points and weights . Furthermore, is a function that describes the distortion from the local coordinates onto the global element . This distortion represents length, area, or volume depending on the dimensionality of the problem. Note that if the elements are the same size then is constant with respect to each element (this is the case in the code below).
The stiffness matrix is computed similarly but with a difference in the fact that the gradient must have its coordinates changed from global to local. Using the chain rule it follows that
(19)
where , i.e. , so that . From this we can isolate the global gradient as
(20)
Putting things together the stiffness matrix can therefore be computed as
(21)
In the following code we implement three different ways of assembling the mass and stiffness matrices. Note that the first two implementations are only for educational purposes as they are both based on dense matrices.
Exampleย 4: Matrix assembly implementations
Example 4 (Matrix assembly implementations)ย ย
1### Importing relevant packages2using FastGaussQuadrature3using BenchmarkTools4using LinearAlgebra5using SparseArrays6using ForwardDiff7using Random8Random.seed!(42)9## Defining geometry.10# Impedance tube of diameter 10 cm and length 1 m (used later)11D = 0.1 # 100 mm diameter12L = 10*D # Length of the cavity13ne = 600 # Number of quadratic elements14nnt = 2*ne+1 # Total number of nodes15h = L/ne # Length of the elements16x = Vector(0:h/2:L) # Coordinates table1718## Computing the element matrices19# Local basis functions (gradient by ForwardDiff: slow but easy)20Tแต(u) = [u .* (u .- 1)/2; 1 .- u .^2; u .* (u .+ 1)/2]'21โTแต(u) = hcat(ForwardDiff.derivative.(Tแต,u)...)22# All elements are equal, so the Jacobian is the same for each.23# It maps [-1,1] onto [x_i,x_{i+1}], i.e. length 2 onto length h.24jacobian(u) = h/225# In 1D the Jacobian function and matrix are equal (not so in 2D).26J(u) = h/227# The element matrices, the same for all elements of equal size.28Q = 3 # Number of Gauss points29u,w = gausslegendre(Q)30Me = sum(i -> w[i]*Tแต(u[i])'*Tแต(u[i])*jacobian(u[i]),1:Q)31Ke = sum(i -> w[i]*โTแต(u[i])'*J(u[i])^(-1)*J(u[i])^(-1)*โTแต(u[i])*32 jacobian(u[i]),1:Q)3334## Assembly 1: with the localization matrices (never do this!)35function assembly1(Me, Ke, nnt, ne)36 K = zeros(nnt, nnt) # Dense matrix! Not ideal!37 M = zeros(nnt, nnt) # Dense matrix! Not ideal!38 for ie = 1:ne39 Le = zeros(3, nnt)40 Le[:, ie*2-1:ie*2+1] = Diagonal(ones(3))41 K += Le'*Ke*Le42 M += Le'*Me*Le43 end44 return K, M45end46@btime K, M = assembly1(Me, Ke, nnt, ne)4748## Assembly 2: with indexing instead of localization matrices49function assembly2(Me, Ke, nnt, ne)50 K = zeros(nnt, nnt) # Dense matrix! Not ideal!51 M = zeros(nnt, nnt) # Dense matrix! Not ideal!52 for ie = 1:ne53 K[ie*2-1:ie*2+1, ie*2-1:ie*2+1] += Ke54 M[ie*2-1:ie*2+1, ie*2-1:ie*2+1] += Me55 end56 return K, M57end58@btime K, M = assembly2(Me, Ke, nnt, ne)5960## Assembly 3: sparse, using the compact support of the elements61function assembly3(Me, Ke, nnt, ne)62 I = zeros(Int64, 4nnt - 3)63 J = zeros(Int64, 4nnt - 3)64 Kd = zeros(ComplexF64, length(I))65 Md = zeros(ComplexF64, length(I))66 for ie=1:ne67 for i = 1:368 r = (8*(ie-1)+1 + 3*(i-1)):(8*(ie-1) + 3*i)69 I[r] .= ie*2-1:ie*2-1+270 J[r] .= (ie-1)*2 + i71 Kd[r] += Ke[:, i]72 Md[r] += Me[:, i]73 end74 end75 K = sparse(I, J, Kd)76 M = sparse(I, J, Md)77 return K, M78end79@btime K, M = assembly3(Me, Ke, nnt, ne)5. Examples
Exampleย 5: Impedance tube
Example 5 (Impedance tube)ย ย The procedure used in an impedance tube to measure the surface impedance and absorption coefficient of an acoustic material works as follows. A loudspeaker is installed at one end () and an acoustic material of thickness and surface impedance is bonded onto the other rigid and impervious end, with the surface of the material at . Below the cut-off frequency of the tube, only plane waves propagate and the problem is amenable to a one-dimensional analysis.
In this case the surface impedance of the material can be obtained from the measurement of the transfer function between two microphones adequately placed in the tube (e.g., standard ASTM E1050):
(22)
where is the distance from microphone 2 to the sample, is the spacing between the two microphones, and is the wavenumber of air. The normal-incidence absorption coefficient is directly obtained from the reflection coefficient : .
The impedance of a material of thickness bonded onto a rigid wall (at ) and excited by a plane wave with incidence angle is given by [1]:
(23)
In the following the loudspeaker is modeled as a displacement of . Furthermore, the specific details of the setup are:
- Diameter of impedance tube cm (and thus cut-off frequency Hz).
- Length of impedance tube: .
- Microphone spacing: .
- Distance between microphone 2 and the surface of the material: .
- Thickness of the material: cm.
- Characteristic impedance (where ).
- Wavenumber (where ).
- Density and propagation speed: kg/mยณ, m/s.
- Flow resistivity of the material: Rayls/m.
A 1D model of an impedance tube with a loudspeaker at and a material at can be described by the following set of equations
(24)
where is the surface admittance of the material, normalized by the characteristic impedance of air, and is the displacement of the loudspeaker, with velocity . Here, and in the formulas above, time-harmonic quantities vary as .
The PDE is modeled using the FEM as previously
(25)
However, in this case . Instead we have
(26)
In the above we utilized the prescribed boundary conditions as well as the definition of , so that is the first entry of . Putting things together we find that
(27)
Using the previously implemented FEM routines we can numerically solve the problem, and use the analytical expression to check the results, as shown in Figureย 2.
1include("assembly_1d.jl")2using CairoMakie3## Recomputing FEM matrices4K,M = assembly3(Me,Ke,nnt,ne)5## Setup6ฯโ = 1.2 # Fluid density7cโ = 342.2 # Speed of sound8U_L = 1 # Piston displacement9D = 0.1 # Diameter of Impedance Tube10s = 0.5*D # Microphone spacing11d = D/2 # Distance between mic 2 and sample12## Frequency domain13fc = floor(1.84*cโ/D/pi) # Cut off frequency14freq = Vector(100:2:fc)15ฯ = 2*pi*freq16kโ = ฯ/cโ17## Impedance properties18Zโ = ฯโ * cโ19thickness = 0.02 # thickness of the material20ฯ = 10000 # flow resistivity21X = ฯโ*freq/ฯ22Zc = Zโ*(1 .+ 0.057*X.^(-0.754) - im*0.087.*X.^(-0.732))23kc = kโ .*(1 .+ 0.0978*X.^(-0.700) - im*0.189.*X.^(-0.595))24Z = -im.*Zc.*cot.(kc*thickness) / Zโ25beta = 1.0 ./ Z # convert to admittance26# Finding nodes located on the microphones27in2 = findall(x->x,abs.(x .- d) .< 1e-6)[1]28in1 = findall(x->x,abs.(x .- (d+s)) .< 1e-6)[1]29# Correcting the s and d distances to fit the numerical values30s = abs(x[in1] - x[in2])31d = x[in2]3233## Output34ndof = nnt35nfreqs = length(ฯ)36P_mic1 = zeros(ComplexF64,nfreqs)37P_mic2 = zeros(ComplexF64,nfreqs)38A = Diagonal(zeros(ComplexF64,nnt))39F = zeros(ComplexF64,ndof)4041## Frequency sweep42for i in eachindex(ฯ)43 A[1,1] = im*kโ[i]*beta[i]44 F[end,1] = ฯโ*ฯ[i]^2*U_L45 S = K - kโ[i]^2*M + A46 p = S\F47 P_mic2[i] = p[in2]48 P_mic1[i] = p[in1]49end5051# Calculate the normalized impedance52Hโโ = P_mic2 ./ P_mic153R = (Hโโ - exp.(-im*kโ*s))./(exp.(im*kโ*s) - Hโโ) .*54 exp.(im*2*kโ * (d + s))55Z_num = (1 .+ R)./(1 .- R)56## Comparison with the exact solution57fig = Figure(size=(800,320))58ax_re = Axis(fig[1,1],xlabel="Frequency (Hz)",ylabel="Real part")59lines!(ax_re,freq,real.(Z),label="Analytical")60lines!(ax_re,freq,real.(Z_num),label="FEM",linestyle=:dash)61ax_im = Axis(fig[1,2],xlabel="Frequency (Hz)",ylabel="Imaginary part")62lines!(ax_im,freq,imag.(Z))63lines!(ax_im,freq,imag.(Z_num),linestyle=:dash)64axislegend(ax_re)65figExampleย 6: Modes of a 10 ร 4 m room
Example 6 (Modes of a 10 ร 4 m room)ย ย The Finite Element Method can also be used to compute the modes, i.e. finding the eigenvalues of the generalized eigenvalue problem
(28)
For a rectangular room with side lengths and , here m and m, the frequencies of the modes can be computed analytically as
(29)
The room is meshed with a regular grid of bilinear quadrilateral elements:
1using LinearAlgebra, CairoMakie2## Defining geometry.3Lx = 104Ly = 45n = 20+16m = 8+17ne = (n-1)*(m-1) # Number of linear elements8nnt = n*m # Total number of nodes9## Plotting the elements10x = Vector(0:Lx/(n-1):Lx)11y = Vector(0:Ly/(m-1):Ly)12X = kron(x,ones(m))13Y = kron(ones(n),y)14scatter(X,Y,axis=(aspect=DataAspect(),))The Finite Element computation for the 2D room looks similar to the one for the 1D impedance tube. One difference is the reliance on the topology (connectivity) matrix, which lists the nodes of each element. The end of the script computes the analytical frequencies for comparison:
1include("modes_geometry.jl")2using ForwardDiff, SparseArrays, LinearAlgebra3using FastGaussQuadrature, Arpack4cโ = 342.25## Creating the topology6T = reshape(1:nnt,m,n) # Numbering all nodes on the grid7topology = zeros(Int,4,ne)8topology[1,:] = T[1:end-1,1:end-1][:]9topology[2,:] = T[1:end-1,2:end][:]10topology[3,:] = T[2:end,2:end][:]11topology[4,:] = T[2:end,1:end-1][:]12## Computing Element matrices13# Local basis functions (gradient by ForwardDiff: slow but easy)14Tแต(u) = [(1-u[1])*(1-u[2]); (1+u[1])*(1-u[2]);15 (1+u[1])*(1+u[2]); (1-u[1])*(1+u[2])]'/416โTแต(u) = hcat(ForwardDiff.jacobian(Tแต,u))'17# All elements are equal, so the Jacobian is the same for each.18jacobian(u) = (x[2]-x[1])/2*(y[2]-y[1])/219J(u) = Diagonal([x[2]-x[1];y[2]-y[1]])/220# Defining the local element matrices.21Q = 222u,wu = gausslegendre(Q)23v,wv = gausslegendre(Q)24U = kron(u,ones(Q))25V = kron(ones(Q),v)26W = kron(wu,wv)27P = [U';V']2829Me = sum(i -> W[i]*jacobian(P[:,i])*Tแต(P[:,i])'*Tแต(P[:,i]),1:Q^2)30Ke = sum(i -> W[i]*jacobian(P[:,i])*โTแต(P[:,i])'*31 J(P[:,i])'^(-1)*J(P[:,i])^(-1)*โTแต(P[:,i]),1:Q^2)3233## Assembly34function connected_topology(topology,nnt,ne)35 source_connections = [zeros(Int,0) for _ in 1:nnt]36 for element = 1:ne37 for i = 1:438 node = topology[i,element]39 append!(source_connections[node],topology[:,element])40 end41 end42 sort!.(unique.(source_connections))43end44function create_I_J(connections)45 I = zeros(Int,sum(length.(connections)))46 J = zeros(Int,sum(length.(connections)))47 lower = 148 for (idx,con) in enumerate(connections)49 upper = lower + length(con)50 I[lower:upper-1] .= con51 J[lower:upper-1] .= idx52 lower = upper53 end54 return I,J55end56function assembly(Me,Ke,topology,nnt)57 ne = size(topology,2)58 connections = connected_topology(topology,nnt,ne)59 I,J = create_I_J(connections)60 S = sparse(I,J,1:length(I))61 Kd = zeros(length(I))62 Md = zeros(length(I))63 for ie=1:ne64 top = topology[:,ie]65 Kd[S[top,top]] += Ke66 Md[S[top,top]] += Me67 end68 K = sparse(I,J,Kd)69 M = sparse(I,J,Md)70 return K,M71end72K,M = assembly(Me,Ke,topology,nnt);7374using Arpack75F = eigs(cโ^2*K,M,which=:SM,nev=10);76freq = sort(sqrt.(abs.(F[1]))/2/ฯ);7778## The analytical frequencies, for comparison79nx, ny = 0:4, 0:480freq_analytical = cโ/2*sqrt.((nx/Lx).^2 .+ (ny'/Ly).^2)81analytical_freqs = sort(freq_analytical[:])82println("FEM: ", round.(freq[2:10],digits=2))83println("Analytical: ", round.(analytical_freqs[2:10],digits=2))As seen in Figureย 3, the FEM frequencies lie slightly above the analytical ones, and the difference grows with the frequency, as the mesh resolves the shorter wavelengths of the higher modes less accurately.
Cite this post
@misc{paltorp2026femintroduction, author = {Paltorp, Mikkel}, title = {{The Finite Element Method}}, year = {2026}, month = may, url = {https://mipals.github.io/pdf/2026/05-11-fem-introduction/fem-introduction.pdf}, note = {Blog post}}Bibliography
- [1] J.-F. Allard and N. Atalla, Propagation of Sound in Porous Media: Modelling Sound Absorbing Materials, 2nd ed. Wiley, 2009. doi: 10.1002/9780470747339.