Constrained linear systems arise when Dirichlet boundary conditions are imposed on a variational formulation

Find uU such that

a(u,v)=b(v)

for all vV, where

U={uuH1(Ω),u=ˉu on Ωu}V={uuH1(Ω),u=0 on Ωu}

where ˉu is the Dirichlet condition.

We additively decompose the solution into known and unknown parts:

u=ˉu+w

and substitute into our variational formulation

a(ˉu+w,v)=b(v)

We can take advantage of the linearity condition, and reformulate the variational formulation:

Find wV such that

a(w,v)=b(v)a(ˉu,v)

for all vV.

The algorithmic analogue of this formulation will be developed in the following section Direct Modification Approach.

Static Condensation Approach

For a linear system

Au=b,

of size N×N, we constrain the values of the solution or right-hand side at certain degrees of freedom. We sort the system so that these degrees of freedom are grouped together after the unconstrained degrees of freedom. The resulting system is,

[A1,1A1,MA1,M+1A1,NAM,1AM,MAM,M+1AM,NAM+1,1AM+1,MAM+1,M+1AM+1,NAN,1AN,MAN,M+1AN,N][u1uMuM+1uN]=[b1bMbM+1bN],

Defining submatrices and vectors for the partitions, we can write

[A11A12A21A22][u1u2]=[b1b2]

or

A11u1+A12u2=b1A21u1+A22u2=b2,

Let u2=ˉu and b1=ˉb have defined values. The objective is to solve for unknown u1 and b2. We have

u1=A111(b1A12u2)

and

b2=(A22A21A111A12)u2+A21A111b1

In case ˉu=0, we have

u1=A111b1b2=A21A111b1

and in case ˉb=0, we have

u1=A111A12u2b2=(A22A21A111A12)u2

Example: Plane Stress and Strain in Linear Elasticity

The constitutive equation of isotropic linear elasticity reads

[λ+2μλλ000λλ+2μλ000λλλ+2μ000000μ000000μ000000μ][ε11ε22ε33ε12ε23ε13]=[σ11σ22σ33σ12σ23σ13]

The plane stress condition reads σ13=σ23=σ33=0. We group the constrained degrees of freedom together:

[λ+2μλ0λ00λλ+2μ0λ0000μ000λλ0λ+2μ000000μ000000μ][ε11ε22ε12ε33ε23ε13]=[σ11σ22σ12σ33σ23σ13]

which we write as

[C11C12C21C22][εε]=[σσ]

The purpose is to obtain a reduced system without σ or ε. We substitute the plane stress condition σ=0, to obtain ε=C122C21ε. Then we have

(C11C12C122C21)ε=σ

We define the plane stress version of the elasticity tensor as Cσ=C11C12C122C21 which results in

Cσ=μλ+2μ[4(λ+μ)2λ02λ4(λ+μ)000λ+2μ]=E1ν2[1ν0ν1000(1ν)/2]

The plane strain condition reads ε=0. This simply results in

C11ε=σ

The plane strain version of the elasticity tensor Cε=C11 is calculated as

Cε=[λ+2μλ0λλ+2μ000μ]=E(1+ν)(12ν)[1νν0ν1ν000(12ν)/2]

The procedure defined above is called static condensation, named after its application in structural analysis. One impracticality of this formulation is that systems do not always exist with their constrained degrees of freedom grouped together. These are generally scattered arbitrarily throughout the solution vector, and grouping them manually is impractical with current data structure implementations.

Direct Modification Approach

Suppose we have a system where u2 and b1 are known and u1 and b2 are unknown:

[A11A12A21A22][u1u2]=[b1b2]

We can modify the system so that it can be solved without separating the partitions

[A11A120I][u1u2]=[b1u2]

We can additively decompose both sides

[A1100I][u1u2]+[0A1200][u1u2]=[b1u2]

Therefore, the following is equivalent to (10):

[A1100I]˜A[u1u2]=[b1A12u2u2]˜b

This is solved for u:

u=˜A1˜b.

The unknown right hand side can be obtained from the original matrix A

b=Au=A˜A1˜b,

Observe that the modifications on A are symmetric, so we do not need the constrained degrees of freedom be grouped together. ˜A is obtained by zeroing out the rows and columns corresponding to constraints and setting the diagonal components to one. For ˜b, we do not need to extract A12; we simply let

˜bbkAuk

where

uk=[0u2]andbk=[b10]

We then equate the constrained degrees of freedom to their specified values u2.

Below is a pseudocode outlining the algorithm.

fun solve_constrained_system(A, b_known, u_known, is_contrained):
   # A: unmodified matrix, size NxN
   # b_known: known values of the rhs, size N
   # u_known: known values of the solution, size N
   # is_constrained: bool array whether dof is constrained, size N

   N = length(b)
   A_mod = copy(A)
   b_mod = b_known - A_known*u_known # Calculate rhs vector

   for i=1 to N do:
       if is_constained[i] then:
           for j = 1 to N do:
               A_mod[i][j] = 0 # Set row to zero
               A_mod[j][i] = 0 # Set column to zero
           endfor
           A_mod[i][i] = 1 # Set diagonal to one
           b_mod[i] = u_known[i]
       endif
    endfor

    u = inverse(A_mod)*b_mod # Solve constrained system
    # Could also say solve(A_mod, b_mod)
    b = A*u # Substitute solution to get final rhs vector

    return u, b
endfun

Constrained Update Schemes

When using an iterative solution approach, one generally has an update equation of the form

uˉu+ΔuwhereAΔu=b

where u is the solution vector of the primary unknown. The update vector Δu is obtained by solving a linear system and added to the solution vector in each iteration. This process is usually terminated when the approximation error drops below a threshold value.

\When the solution vector itself is constrained, the update system needs to be modified accordingly. Grouping the constrained degrees of freedom together,

[u1u2][ˉu1ˉu2]+[Δu1Δu2]

Let u2 be known and u1 be unknown.

We can make the substitution Δu2=u2ˉu2:

[A11A22A21A22][Δu1u2¯u2]=[b1b2]

This system can then be solved for the unknown Δu1 and Δb2 with the procedure defined in the previous section. The only difference is that,

Δuk=[0u2¯u2]