Метод конечных элементов. Иерархический базис 2-го порядка.

405 группа, Иванов Родион. Задача №6

Решается следующее уравнение на $x \in [0,1]$: $$ -u''(x) + x u(x) = f(x)$$

Граничные условия: $$ u'(0)=u(1)=0$$

Точное решение: $$ u(x) = cos(\frac{5 \pi x}{2})$$

Правая часть: $$ f(x) = (x+\frac{25 \pi^2}{4})cos(\frac{5 \pi x}{2}) $$

Вариационное выражение:

$$\int_0^1 (v'(x) u'(x) + x u(x) v(x)) dx = \int_0^1 f(x) dx$$

Иерархический базис 2-го порядка, определенный на каноническом элементе $\xi \in [-1,1]$:

$ N^1_{-1}(\xi) = \frac{\xi-1}{2} \text{; }$ $N^2(\xi) = \frac{3(\xi^2 - 1)}{2 \sqrt{6}} \text{; }$ $N^1_{1}(\xi) = \frac{\xi+1}{2}$

Вывод выражений для матриц $M_j$, $K_j$ и вектора $I_j$:

Все интегрирования проводились в Wolfram Alpha, а матричные операции - с помощью MatrixCalc.org. Проводим дискретизацию равномерно, чтобы упросить вычисления, имея общий для всех элементов $h$.

Построение глобальных K,M,J:

Комбинируются из $M_j$, $K_j$ и вектора $I_j$, так, что каждый следующий блок перекрывает предыдущий с суммированием в общем элементе. Для учета граничных условий выбрасывается последний столбец и последняя строка для матриц и последний элемент для вектора.


In [1]:
import numpy as np
from matplotlib import pylab as plt
import math
%matplotlib inline

a = 0
b = 1

# m-количество точек
m = 50
n_el = m -1
x = np.linspace(a,b,m, endpoint = True)
h = x[1]-x[0]

# Расчет размера глобальных матриц(до учета гр. условий). Расчёт "в лоб"
global_m_size = 3
for i in range(n_el-1):
    global_m_size += 2

# Точное решение
def u(x):
    return np.cos(5*math.pi*x/2)

# Функция правой части
def f(x):
    return (x+25*math.pi*math.pi/4)*np.cos(5*math.pi*x/2) 

# Базисные функции
def N_1_m1(xi):
    return (xi-1)/2

def N_2(xi):
    return 3*(np.square(xi)-1)/(2*np.sqrt(6))

def N_1_1(xi):
    return (xi+1)/2

K_j = np.zeros((3,3))
K_j[0][0] = 1
K_j[1][1] = 2
K_j[2][2] = K_j[0][0]

K_j[0][1] = 0
K_j[1][0] = K_j[0][1]

K_j[2][0] = -1
K_j[0][2] = K_j[2][0]

K_j[2][1] = 0
K_j[1][2] = K_j[2][1]

K_j = K_j * 1 /h


        

def M_j(a, b):
    M = np.zeros((3,3))
    M[0][0] = (3*a+b)/6
    M[1][1] = (a+b)/5
    M[2][2] = (3*b+a)/6
    
    M[0][1] = -(3*a+2*b)/(5*np.sqrt(6))
    M[1][0] = M[0][1]
    
    M[0][2] = (a+b)/6
    M[2][0] = M[0][2]
    
    M[1][2] = -(2*a+3*b)/(5*np.sqrt(6))
    M[2][1] = M[1][2]
    
    M = M*h/2
    return M

def I_j(a,b):
    I_j = np.zeros(3)
    I_j[0] = 2*f(a)+f(b)
    I_j[1] = -np.sqrt(3/2)*(f(a)+f(b))
    I_j[2] = f(a) + 2*f(b)
    I_j = I_j * h/6
    return I_j

# Посчитаем глобальные K,M,J
K = np.zeros((global_m_size, global_m_size))
M = np.zeros((global_m_size, global_m_size))
I = np.zeros(global_m_size)

# K
K[0:3, 0:3] = K_j
s = 2
for i in range(n_el-1):
    temp = K[s][s]
    K[s:s+3,s:s+3] = K_j
    K[s][s] += temp
    s += 2

# M 
M[0:3, 0:3] = M_j(x[0], x[1])
s = 2
for i in range(1,n_el):
    temp = M[s][s]
    M[s:s+3,s:s+3] = M_j(x[i], x[i+1])
    M[s][s] += temp
    s += 2

# I
I[0:3] = I_j(x[0], x[1])
s = 2
for i in range(1, n_el):
    temp = I[s]
    I[s:s+3] = I_j(x[i], x[i + 1])
    I[s] += temp
    s += 2

# учтем граничные условия
I = I[0:-1]
M = M[0:-1,0:-1]
K = K[0:-1,0:-1]

In [2]:
# Решим СЛАУ:
vect = np.linalg.solve(M+K, I)
coeffs = np.concatenate((vect,[0]))
def get_fem_u_can(xi,c):
    return c[0]*N_1_m1(xi) + c[1]*N_2(xi) + c[2]*N_1_1(xi)

def xi_from_x(calc_x, xj_1, xj):
    return (xj_1 + xj - 2 * calc_x) / (xj_1 - xj)
 
def x_from_xi(z, xj_1, xj):
    return (1-z)/2*xj_1 + (1+z)/2*xj

def calc_solution(calc_x):
    interval_num = 1
    xj_1 = x[0]
    xj = x[1]
    if calc_x == 0:
        return 1
    for index, item in enumerate(x):
        if calc_x <= item:
            interval_num = index
            #print(index)
            xj_1 = x[index - 1]
            xj = x[index]
            break
    c = [0, 0, 0]
    c = coeffs[(interval_num-1)*2:(interval_num-1)*2+3]
    xi = xi_from_x(calc_x, xj_1, xj)
    res = get_fem_u_can(xi,c)
    return res

def calc_solution2(calc_x):
    interval_num = 0
    xj_1 = 0
    xj = 0
    if (calc_x < 0) and (calc_x > 1):
        return False
    if calc_x == 0:
        return 0
    
    for index, item in enumerate(x):
        if calc_x <= item:
            interval_num = index
            #print(index)
            xj_1 = x[index - 1]
            xj = x[index]
            break

    c = [0, 0, 0]
    for i in range(3):
        c[i] = coeffs[(interval_num - 1) * 2 + i]

    cur_qsi = xi_from_x(calc_x, xj_1, xj)
        
    res = c[0]*N_1_m1(cur_qsi) + c[1]*N_2(cur_qsi) + c[2]*N_1_1(cur_qsi)
    return res

In [3]:
coeffs[4:4+3]
coeffs


Out[3]:
array([-9.97804953e-01,  5.21061740e-03, -9.85014154e-01,  5.07702623e-03,
       -9.46969684e-01,  4.81327828e-03, -8.84646903e-01,  4.42613514e-03,
       -7.99643580e-01,  3.92552181e-03, -6.94138935e-01,  3.32427228e-03,
       -5.70837764e-01,  2.63780045e-03, -4.32901106e-01,  1.88370504e-03,
       -2.83865200e-01,  1.08131839e-03, -1.27550832e-01,  2.51210842e-04,
        3.20346207e-02, -5.85336607e-04,  1.90799921e-01, -1.40687786e-03,
        3.44674857e-01, -2.19235154e-03,  4.89714589e-01, -2.92162092e-03,
        6.22200781e-01, -3.57599014e-03,  7.38736923e-01, -4.13868355e-03,
        8.36335410e-01, -4.59527571e-03,  9.12494130e-01, -4.93406125e-03,
        9.65260609e-01, -5.14635498e-03,  9.93282069e-01, -5.22671446e-03,
        9.95840104e-01, -5.17307960e-03,  9.72869101e-01, -4.98682545e-03,
        9.24957919e-01, -4.67272694e-03,  8.53334796e-01, -4.23883647e-03,
        7.59835860e-01, -3.69627747e-03,  6.46858054e-01, -3.05895925e-03,
        5.17297692e-01, -2.34322041e-03,  3.74476206e-01, -1.56740994e-03,
        2.22054995e-01, -7.51416884e-04,  6.39415609e-02,  8.38396028e-05,
       -9.58106653e-02,  9.16946521e-04, -2.53106240e-01,  1.72654598e-03,
       -4.03912701e-01,  2.49188276e-03, -5.44363940e-01,  3.19333635e-03,
       -6.70859323e-01,  3.81292402e-03, -7.80155993e-01,  4.33476177e-03,
       -8.69452007e-01,  4.74547156e-03, -9.36458167e-01,  5.03452431e-03,
       -9.79456706e-01,  5.19450975e-03, -9.97345330e-01,  5.22132648e-03,
       -9.89665471e-01,  5.11428704e-03, -9.56614046e-01,  4.87613557e-03,
       -8.99038409e-01,  4.51297746e-03, -8.18414627e-01,  4.03412283e-03,
       -7.16809639e-01,  3.45184783e-03, -5.96828269e-01,  2.78107993e-03,
       -4.61546443e-01,  2.03901525e-03, -3.14432339e-01,  1.24467770e-03,
       -1.59257470e-01,  4.18431267e-04,  0.00000000e+00])

In [4]:
K


Out[4]:
array([[ 49.,   0., -49., ...,   0.,   0.,   0.],
       [  0.,  98.,   0., ...,   0.,   0.,   0.],
       [-49.,   0.,  98., ...,   0.,   0.,   0.],
       ...,
       [  0.,   0.,   0., ...,  98.,   0.,   0.],
       [  0.,   0.,   0., ...,   0.,  98.,   0.],
       [  0.,   0.,   0., ...,   0.,   0.,  98.]])

In [5]:
aaa = np.linspace(x[2],x[3], 60, endpoint=True)
ress = []
resN2 = []
for item in aaa:
    xi = xi_from_x(item, x[2], x[3])
    #print(xi)
    c = coeffs[2*2:2*2+3]
    ress.append(get_fem_u_can(xi,c))
    resN2.append(N_2(xi)*c[1])


plt.plot(aaa,ress)
plt.plot(aaa,resN2)


Out[5]:
[<matplotlib.lines.Line2D at 0x1509a3d2c18>]

In [6]:
FEM_SOL = []
x_show = np.linspace(0,1, 1000, endpoint=True)
#x_show = x
for item in x_show:
    FEM_SOL.append(calc_solution(item))
plt.plot(x_show,FEM_SOL)


Out[6]:
[<matplotlib.lines.Line2D at 0x1509c73c160>]

In [7]:
fig = plt.figure(figsize=(20,10))
plt.grid(True)
plt.title('U(x) and FEM solution', fontsize=26)
plt.xlabel('x', fontsize=20)
plt.ylabel('U(x)', fontsize=20)
plt.plot(x, u(x), 'rx--', label = 'U(x)')
#plt.plot(x, f(x), 'bx--', label = 'f(x)')
plt.plot(x_show, FEM_SOL, 'gx', label = 'FEM solution')
#plt.plot(x_show, FEM_SOL - u(x_show), 'bx--', label = 'FEM solution')
plt.legend()


Out[7]:
<matplotlib.legend.Legend at 0x1509c7a6358>

In [ ]: