In [3]:
%matplotlib inline
CIVL4250 Numerical Methods in Engineering
Dr Dorival Pedroso
The code for this notebook is available in https://github.com/cpmech/CIVL4250py
The following fourth order partial differential equation
$$ \frac{\mathrm{d}^2}{\mathrm{d} x^2} \left (E\,I\,\frac{\mathrm{d}^2 u}{\mathrm{d} x^2} \right) = q(x) $$represents the transverse deflection ($u$) of a beam according to Euler-Bernoulli beam theory (see, e.g. Euler-Bernoulli in Wikipedia. Therein, $q(x)$ is a transverse distributed load, $E$ is the Young's elasticity modulus and $I$ the moment of inertia of the cross-sectional area.
With constant properties ($E\,I$), simple loads and simple boundary conditions, the above equation can be solved in closed form. For the cantilever illustrated above (fully fixed at $x=0$, with a concentrated load $F$ at $x=L$ and distributed load given by $q(x)=x^2$), the resulting transverse displacement $u$ can be analytically deduced.
The following convention is adopted: positive values of displacements and forces are those corresponding to the $y$ axis. In this way, negative values of q and F mean downward loads.
With constant properties, the differential equation becomes
$$ \frac{\mathrm{d}^4 u}{\mathrm{d} x^4} = f(x) $$where $f(x) = q(x) / (E\,I)$.
This equation can be approximated with a 5-point stencil (grid) using the following fourth order central differences formula
$$ \frac{\mathrm{d}^4 u}{\mathrm{d} x^4} \approx \frac{ u_{i-2} - 4\,u_{i-1} + 6\,u_{i} - 4\,u_{i+1} + u_{i+2} } {h^4} $$where $h = \Delta x$ and the grid indices go from $0$ to $n-1$ with $n$ being the number of points.
Substituting the above approximation into the differential equation, the following general expression for any point is obtained
$$ u_{i-2} - 4\,u_{i-1} + 6\,u_{i} - 4\,u_{i+1} + u_{i+2} = f_i \, h^4 $$where the points outside $0\leq i\leq n-1$ are known as ghost points and must be handled after considering the boundary conditions.
The boundary conditions are now taken into consideration.
At $x=0$, the deflection $u_0$ at point $i=0$ is known and is equal to zero. The derivative at $i=0$ is also zero; thus, by means of a first order finite differences approximation at $i=0$,
$$ u_0 = 0 \qquad \text{and} \qquad u_{-1} = u_{1} $$At $x=L$, although the deflection is maximum, its second derivative is zero because the bending moment is zero at this position. Note that the bending moment is proportional to the second derivative of $u$. Thus, by using a second order central differences formula
$$ \left.{\frac{\mathrm{d}^2 u}{\mathrm{d} x^2}}\right\rvert_{x=L} \approx \frac{ u_{b-1} - 2\,u_b + u_{b+1} } {h^2} = 0 $$where $b$ is the index of the last point at $x=L$; i.e. $b=n-1$. Therefore
$$ u_{b+1} = 2\,u_b - u_{b-1} $$The third derivative of deflection is proportional to the shear force $Q$, i.e.:
$$ Q = -E\,I\,\frac{\mathrm{d}^3 u}{\mathrm{d} x^3} $$At $x=L$, the shear force equals the applied concentrated force $F$ (that could be zero). Therefore, with a third order central differences,
$$ \left.{\frac{\mathrm{d}^3 u}{\mathrm{d} x^3}}\right\rvert_{x=L} \approx \frac{ -0.5\,u_{b-2} + u_{b-1} - u_{b+1} + 0.5\,u_{b+2} } {h^3} = g_b $$where $g_b = -F / (E\,I)$.
From the above approximation, the deflection at the right-most (ghost) point $b+2$ can be found as follows
$$ u_{b+2} = 2\,g_b\,h^3 + u_{b-2} - 2\,u_{b-1} + 2\,u_{b+1} $$which, after substituting the results for $u_{b+1}$, becomes
$$ u_{b+2} = 2\,g_b\,h^3 + u_{b-2} - 4\,u_{b-1} + 4\,u_b $$Now, the expressions for the ghost points can be inserted into the general formula for any point. Note also that the equation for point $i=0$ is not required since $u_0=0$.
For point $i=1$, from the general expression given in the previous section, the equation becomes
$$ u_{-1} - 4\,u_{0} + 6\,u_{1} - 4\,u_{2} + u_{3} = f_1 \, h^4 $$thus, since $u_0=0$ and $u_{-1}=u_1$,
$$ \text{eq. for point i=1}:\quad 7\,u_{1} - 4\,u_{2} + u_{3} = f_1 \, h^4 $$Similarly, at the right-hand side, for point $i=b-1$,
$$ u_{b-1-2} - 4\,u_{b-1-1} + 6\,u_{b-1} - 4\,u_{b-1+1} + u_{b-1+2} = f_{b-1} \, h^4 $$i.e.
$$ u_{b-3} - 4\,u_{b-2} + 6\,u_{b-1} - 4\,u_b + u_{b+1} = f_{b-1} \, h^4 $$which, after substituting the value for ghost point $b+1$, becomes
$$ \text{eq. for point i=b-1}:\quad u_{b-3} - 4\,u_{b-2} + 5\,u_{b-1} - 2\,u_b = f_{b-1} \, h^4 $$Finally, for point $i=b$,
$$ u_{b-2} - 4\,u_{b-1} + 6\,u_b - 4\,u_{b+1} + u_{b+2} = f_b \, h^4 $$which, after substituting the value for ghost points $b+1$ and $b+2$, becomes
$$ u_{b-2} - 4\,u_{b-1} + 6\,u_b - 4\,(2\,u_b - u_{b-1}) + (2\,g_b\,h^3 + u_{b-2} - 4\,u_{b-1} + 4\,u_b) = f_b \, h^4 $$i.e.
$$ 2\,u_{b-2} - 4\,u_{b-1} + 2\,u_b = f_b \, h^4 - 2\,g_b\,h^3 $$or, dividing by 2,
$$ \text{eq. for point i=b}:\quad u_{b-2} - 2\,u_{b-1} + u_b = 0.5\,f_b \, h^4 - g_b\,h^3 $$Hence, the resulting linear system of equations, expressed in matrix form, is
where we can observe that the resulting matrix is symmetric and banded. Note also that this matrix corresponds to the $K_{11}$ matrix from the lecture notes, since the prescribed boundary conditions were already considered.
The Python calculation script for the cantilever beam equations is similar to the one presented for the 1D Poisson equation in the lecture notes. The complete code can be downloaded from here.
Considering the figure below
where negative values of q and F mean downward loads, the input data and FDM grid are defined as follows
In [11]:
from numpy import linspace
# input data
E = 1.0 # Young's modulus
Izz = 1.0 # inertia coefficient
EI = E * Izz # auxiliary
L = 1.0 # length of beam
F = -1.0 # concentrated force
def qFcn(x): return -1.0 # distributed load
# FDM grid data
dx = 0.025 # grid spacing
n = int(L / dx) + 1 # number of points
b = n - 1 # index of right-most point
X = linspace(0.0, L, n) # points positions
h3 = dx**3.0 # auxiliary variable
h4 = dx * h3 # auxiliary variable
Although a specialised solver considering the banded and symmetric form of the $K$ matrix could provide the fastest computations, a general sparse solver as used for the finite element code is employed here. We start then with the assemblage of the $K_{11}$ matrix using the lil_matrix
structure from scipy
.
In [5]:
from numpy import zeros
from scipy.sparse import lil_matrix
# auxiliary coefficients
C1 = [7.0, -4.0, 1.0] # for first equation
C2 = [-4.0, 6.0, -4.0, 1.0] # for second equation
C3 = [1.0, -4.0, 6.0, -4.0, 1.0] # for generic (i) equations
C4 = [1.0, -4.0, 5.0, -2.0] # for last-but-one equation (b-1)
C5 = [1.0, -2.0, 1.0] # for last equation (b)
# assembly
K11 = lil_matrix((n-1, n-1))
F1 = zeros(n-1)
for i in range(1, n): # start with 1 to skip first equation
I = i - 1 # row in K11 matrix
J = I - 2 # column of first insertion in K11 matrix
C = C3 # default coefficients
if i == 1: C, J = C1, 0
elif i == 2: C, J = C2, 0
elif i == b-1: C = C4
elif i == b: C = C5
for c in C:
K11[I, J] = c
J += 1
F1[I] = h4 * qFcn(X[i]) / EI
if i == b:
F1[I] = F1[I]/2.0 - h3*(-F/EI)
# debugging
#print 'K11 =\n', K11.todense()
#print 'F1 =\n', F1
Now, the system of equations can be solved for the deflections according to
In [6]:
from scipy.sparse.linalg import spsolve
# solve
K11 = K11.tocsr() # convert matrix to required form by scipy
U1 = spsolve(K11, F1) # solve: U1 = inv(K11) * F1
and the results can be plotted as follows
In [12]:
from numpy import hstack
from pylab import xlabel, ylabel, grid, plot, show, legend
U = hstack([0.0, U1])
plot(X, U, 'b-', label='FDM', clip_on=0)
xlabel('x')
ylabel('u')
grid()
legend()
show()