Задание Реализовать алгоритм решения двумерной задачи теплопроводности через явную разностную схему. Задача задаётся следующей системой уравнений: ut = a 2 (u xx + u yy ) + q (t ) 0 x Lx , 0 y Ly ; u (0, x, y ) = ( x, y ); ut (t , x, 0) = 0, ut (t , x, Ly ) = 0, t 0; u (t , 0, y ) = T , u (t , L , y ) = T , t 0, n x s (1) где t – время, x – координата по оси X, y – координата по оси Y, a – коэффициент теплопроводности. Для построения явной схемы определим равномерную сетку как множество узлов: xi = ihx , i 0, I1 , hx = y j = jhy , Lx ; I1 j 0, I 2 , hy = tk = k , k 0, K , = Ly I2 ; T , K где 𝐼1 – число разбиений по X, 𝐼2 – число разбиений по Y, K – число разбиений по времени. Теперь заменим функции непрерывных аргументов в уравнении (1) на их сеточные аналоги, тогда значение функции u для каждого последующего временного слоя будет вычисляться из предыдущего следующим образом: uik, +j 1 = (1 − 21 − 22 )uik, j + 1 (uik+1, j + uik−1, j ) + 2 (uik, j +1 + uik, j −1 ) , где 1 = / hx2 , 2 = / hy2 . Эксперимент 1. Цель эксперимента Целью эксперимента является проверка правильности реализованного алгоритма для решения двумерной задачи теплопроводности с помощью явной разностной схемы. Для этого необходимо проверить сходимость полученного решения к аналитическому. 2. Выбор программно-аппаратной базы. Для написания кода выбран язык Python c интерпретатором версии 3.8. Это высокоуровневый язык программирования общего назначения, с динамической строгой типизацией и автоматическим управлением памятью. Основной упор в Python делается на скорости написания кода, а не на скорости его выполнения, как например в языках С и C++. Поэтому этот язык удобно использовать там, где нужно быстро написать что-то работающее. А так как основной задачей данного эксперимента является проверка корректности решения, а не проверка скорости его выполнения, то он хорошо подходит для этих целей. Для работы с Python выбрана среда PyCharm. Используемый компьютер имеет следующие показатели: Операционная система – Windows 10; Процессор – Intel Core i5-1135G7; Оперативная память – 16,0 Гб; Количество ядер – 4; Количество логических процессоров – 8. Код программы представлен в приложение А. 3. Выбор параметров эксперимента Для упрощения расчётов для системы (1) было решено установить следующие значения: Коэффициент теплопроводности a =1; Границы: 0 x , 0 y , 0 t 1 ; 2 Начальное условие ( x, y ) = sin( x) sin( y ) ; Граничные условия u (t , 0, y ) = 0, u (t , Lx , y) = 0 . Аналитическое решение u (t , x, y ) = sin( x) sin( y )e −2t . будет рассчитываться по формуле: Так же важными параметрами являются мелкость разбиения по осям и мелкость разбиения по времени. Для проведения эксперимента будут использоваться сетки следующих размеров: 20×20, 40×40, 80×80, 140×140, 200×200, 260×260. Это поможет рассмотреть сходимость при изменении шага дискретизации. Значение K будет рассчитываться в соответствии с условием устойчивости: 2 x h + hy2 0.5 , где ℎ𝑥 – шаг по x, ℎ𝑦 – шаг по y, τ – шаг по времени. 4. Теоретическое предсказание результатов экспериментов При проверке сходимости разностного решения к аналитическому ожидается, что при уменьшении мелкости разбиения, численное решение будет сходиться к аналитическому, что означает – с увеличением количества узлов, погрешность будет уменьшаться. 5. Проведение эксперимента Для проверки сходимости запустим программу для сеток заданного размера, и посчитаем погрешность между численным решением и аналитическим на последнем временном слое (Таблица 1). Визуализация результатов на рисунке 1. Таблица 1 Размер сетки 20×20 40×40 80×80 140×140 200×200 260×260 Значение 1.860067 6.243436 1.482690 4.737352 2.301318 1.355416 погрешнос e-04 e-05 e-05 e-06 e-06 e-06 ти 3 Рисунок 1 – Погрешность численного решения при увеличении количества узлов Так же можно графически продемонстрировать сходимость зафиксировав два показателя из трех. Например, для случая 40×40 рассмотреть последний слой при x=20 (рисунок 2). (а) (б) Рисунок 2 – (a) Графическое представление сходимости решения к явному решению, (б) приближение полученного графика 6. Анализ результатов Из рисунка 2 видно, что графики буквально накладываются друг на друга, что доказывает, как минимум визуальную сходимость полученного решения. 4 График 1 показывает довольно быструю сходимость полученного решения к аналитическому. Видно, что с увеличением количества разбиений уменьшается погрешность, и достигается большая точность. 7. Соответствие теоретическим ожиданиям В результате работы видно, что практические результаты совпали с теоретическими ожиданиями. 8. Выводы Таким образом можно сделать вывод, что поставленные цели достигнуты. Численно и графически показано, что алгоритм работает верно, разностное решение сходится к аналитическому и показывает достаточный уровень точности. 5 ПРИЛОЖЕНИЕ А Код программы import numpy as np import matplotlib.pylab as plt import math import time def my_u(Lx, Ly, T, I1, I2): K = I1 * 2 ht = (T / K) hx = Lx / (I1 - 1) hy = Ly / (I2 - 1) while ((ht / (hx * hx) + ht / (hy * hy)) > 0.5): K=K+1 ht = T / K print(K) lambda1 = ht / (hx ** 2) lambda2 = ht / (hy ** 2) c1 = 1 - 2 * lambda1 - 2 * lambda2 u = np.zeros((I1, I2), dtype=np.float64) u_new = np.zeros((I1, I2), dtype=np.float64) for i in range(0, I1): for j in range(0, I2): u[i, j] = math.sin((i * hx)) * math.sin((j * hy)) one = time.time() for k in range(1, K): if (k % 2 == 1): for i in range(1, I1 - 1): for j in range(1, I2 - 1): u_new[i, j] = u[i, j] * c1 + lambda1 * (u[i + 1, j] + u[i - 1, j]) + lambda2 * ( u[i, j + 1] + u[i, j - 1]) else: for i in range(1, I1 - 1): for j in range(1, I2 - 1): u[i, j] = u_new[i, j] * c1 + lambda1 * (u_new[i + 1, j] + u_new[i - 1, j]) + lambda2 * ( u_new[i, j + 1] + u_new[i, j - 1]) two = time.time() print("Real Time ", two - one) if (K % 2 == 0): return u_new, K else: return u, K def a_solution2(K, I1, I2, T, nt): t = np.linspace(0, T, K + 1, endpoint=True) x = np.linspace(0, np.pi, I1, endpoint=True) y = np.linspace(0, np.pi, I2, endpoint=True) u = np.zeros((I1, I2), dtype=np.float64) for i in range(u.shape[0]): for j in range(u.shape[1]): 6 u[i, j] = np.sin((x[i])) * np.sin((y[j])) * math.exp((-2) * t[nt]) return u def main(): I1 = 40 I2 = 40 T=1 # Решение - схема U, K = my_u(np.pi, np.pi, T, I1, I2) # Аналитическое решение UA2 = a_solution2(K, I1, I2, T, K) x = np.linspace(0, np.pi, I1, endpoint=True) y = np.linspace(0, np.pi, I2, endpoint=True) ax = plt.subplot() ax.set_title("Сходимость") ax.plot(x, U[20, :], color="blue") ax.plot(x, UA2[20, :], color="red") plt.legend(['Явная схема', 'Аналитическое решение']) plt.xlabel('y', color='gray') plt.ylabel('t', color='gray') ax.grid() print('My', U[14, :]) print('My', UA2[14, :]) sum = 0; for i in range(1, I1 - 1): for j in range(1, I2 - 1): sum = sum + abs(U[i, j] - UA2[i, j]) print("pp", sum / ((I1 - 2) * (I2 - 2))) plt.show() if __name__ == '__main__': main() 7