Двумерное уравнение теплопроводности
Материал из Department of Theoretical and Applied Mechanics
Виртуальная лаборатория > Двумерное уравнение теплопроводности
Численное решение двумерного уравнения теплопроводности.
Управление:
- Левая кнопка мыши - нагреть область
- Средняя кнопка мыши - придать области нормальную температуру
- Правая кнопка мыши - охладить область
Скачать Heat_2D_v1-4-mini_release.zip.
Текст программы на языке JavaScript (разработчики Цветков Денис, Кривцов Антон):
Файл "Heat_2D.js"
1 window.addEventListener("load", main_heat, false);
2 function main_heat() {
3
4 // Предварительные установки
5
6 var canv = init_canvas(Heat_2D_canvas);
7
8 var a0 = 1; // масштаб расстояния
9 var t0 = 1; // масштаб времени
10 var m0 = 1; // масштаб массы
11 var T0 = 1; // масштаб температуры
12
13 var dx = 1 * a0; // шаг сетки по оси x
14
15 var spf = 1; // steps per frame - сколько расчетов проходит за каждый кадр отображения
16 var fps = 15;
17 var dt = 0.005 * t0; // шаг интегрирования по времени
18
19 var p0 = m0 / (a0 * a0 * a0); // единица плотности, кг/м3
20 var c0 = a0 * a0 / (t0 * t0 * T0); // единица удельной теплоемкости, Дж/(кг * К) (Дж = кг * м2 / с2)
21 var kap0 = m0 * a0 / (t0 * t0 * t0 * T0);// единица теплопроводности (?, каппа)
22
23 var p = 0.15 * p0;
24 var c = 0.2 * c0;
25 var k = 1 * kap0;
26 var X = k / (c * p); // температуропроводность (?, хи)
27
28 var Nx = 50 + 2; // количество узлов по оси x + 2 для ГУ
29 var Ny = 50 + 2;
30
31 var cell_w = canv.w / (Nx - 2); // ширина клетки
32 var cell_h = canv.h / (Ny - 2); // высота клетки
33
34 // Минимальная и максимальная температуры используются для подбора цветовой гаммы
35 var T_min = 0 * T0;
36 var T_max = 10 * T0;
37
38 var T_mouse_max = 9; // температура для левой клавиши мыши
39 var T_mouse_min = 1; // температура для правой клавиши мыши
40
41 var color_N = 60; // цветов не больше, чем color_N, саму переменную color_N в расчетах лучше не использовать
42 var colors = prepare_colors(color_N);
43 var cell_pics = prepare_cell_pics(colors);
44
45 var pause = false;
46 button_pause.onclick = function () {pause = !pause;};
47 button_clear.onclick = function () {
48 for (var i = 0; i < Nx; i++) {
49 for (var j = 0; j < Ny; j++) {
50 T[i][j].u = (T_max - T_min) / 2;
51 T[i][j].v = 0;
52 }
53 }
54 draw_graph();
55 };
56
57 var T = [];
58 for (var i = 0; i < Nx; i++) {
59 T[i] = [];
60 for (var j = 0; j < Ny; j++) {
61 T[i][j] = {};
62 var x = i / (Nx - 1);
63 var y = j / (Ny - 1);
64
65 var width = 0.05;
66 var power = 5;
67 var plus = 5;
68
69 T[i][j].u = Math.exp(-Math.pow(x - 0.5, 2) / width) * Math.exp(-Math.pow(y - 0.5, 2) / width) * power + plus;
70 T[i][j].v = 0;
71 }
72 }
73
74 // периодические граничные условия
75 for (i = 1; i < Nx - 1; i++) {
76 T[i][0] = T[i][Ny - 2];
77 T[i][Ny - 1] = T[i][1];
78 }
79 for (j = 0; j < Ny; j++) {
80 T[0][j] = T[Nx - 2][j];
81 T[Nx - 1][j] = T[1][j];
82 }
83
84 function prepare_cell_pics(col) {
85 var pics = [];
86 for (var i = 0; i < col.length; i++) {
87 var cell = document.createElement('canvas');
88 var cell_ctx = cell.getContext('2d');
89
90 cell_ctx.fillStyle = col[i];
91 cell_ctx.beginPath();
92 cell_ctx.rect(0, 0, cell_w, cell_h);
93 cell_ctx.fill();
94 pics.push(cell);
95 }
96 return pics;
97 }
98
99
100 function control() {
101 if (!pause) {
102 calculate_steps(spf, dt);
103 draw_graph();
104 }
105 }
106
107 setInterval(control, 1000 / fps); // Запуск системы
108
109
110 // Работа с мышью
111
112 Heat_2D_canvas.onmousedown = function(e){ // функция при нажатии клавиши мыши
113 var T1;
114 if (e.which == 1) T1 = T_mouse_max; // при нажатии левой клавиши мыши клетка нагревается
115 else if (e.which == 2) T1 = (T_max - T_min) / 2; // при нажатии средней клавиши мыши клетка получает среднюю температуру
116 else if (e.which == 3) T1 = T_mouse_min; // при нажатии правой клавиши мыши клетка остывает
117 else return;
118
119 set_cell(e, T1);
120 Heat_2D_canvas.onmousemove = function(e) {set_cell(e, T1);}; // функция, выполняющаяся при перемещении курсора мыши
121 return false;
122 };
123
124 document.onmouseup = function(e){ // функция при отпускании клавиши мыши
125 Heat_2D_canvas.onmousemove = null; // когда клавиша отпущена - функции перемещения нету
126 };
127
128 function set_cell(e, T1){ // придать клетке определенное состояние с нажатия клавиши мыши
129 var m = mouse_coords(e); // обновить координаты в переменных mouseX, mouseY
130 if (m.x < 0 || m.x >= canv.w || m.y < 0 || m.y >= canv.h) return; // проверка на ошибочные координаты
131 // везде прибавляем 1 - из за периодических условий массив сдвинут на 1
132 var i = Math.floor(m.x / cell_w) + 1; // получаем ячейку по горизонтали
133 var j = Math.floor(m.y / cell_h) + 1; // получаем ячейку по вертикали
134 T[i][j].u = T1;
135 draw_cell(i, j);
136 }
137
138 function mouse_coords(e) { // функция возвращает экранные координаты курсора мыши
139 var m = [];
140 var rect = Heat_2D_canvas.getBoundingClientRect();
141 m.x = e.clientX - rect.left;
142 m.y = e.clientY - rect.top;
143 return m;
144 }
145
146 function calculate_steps(spf, dt) {
147 var koeff1 = X / (dx * dx) * dt;
148 for (var s = 0; s < spf; s++) {
149 for (var i = 1; i < Nx - 1; i++) {
150 for (var j = 1; j < Ny - 1; j++) {
151 T[i][j].v = (T[i + 1][j].u + T[i][j + 1].u - 4 * T[i][j].u + T[i - 1][j].u + T[i][j - 1].u) * koeff1;
152 }
153 }
154
155 for (var i = 1; i < Nx - 1; i++) {
156 for (var j = 1; j < Ny - 1; j++) {
157 T[i][j].u += T[i][j].v;
158 }
159 }
160 }
161 }
162
163
164 function draw_graph() {
165 // график
166 canv.ctx.clearRect(0, 0, canv.w, canv.h);
167 for (var i = 1; i <= Nx - 1; i++) {
168 for (var j = 1; j <= Ny - 1; j++) {
169 var col = Math.round((T[i][j].u - T_min) * (colors.length - 1) / (T_max - T_min)); // 0 <= col <= color_N
170 if (col < 0) col = 0;
171 if (col > (colors.length - 1)) col = (colors.length - 1);
172 canv.ctx.drawImage(cell_pics[col], (i - 1) * cell_w, (j - 1) * cell_h);
173 }
174 }
175 }
176
177 function draw_cell(i, j) {
178 var col = Math.round((T[i][j].u - T_min) * (colors.length - 1) / (T_max - T_min)); // 0 < col < color_N
179 canv.ctx.drawImage(cell_pics[col], (i - 1) * cell_w, (j - 1) * cell_h);
180 }
181 function RGBtoHEX(r, g, b) {
182 return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
183 }
184
185 function prepare_colors(N) {
186 var col = [];
187 var n = N / 6 - 1;
188 for (var i = 0; i < 256; i += Math.floor(255 / n))
189 col.push(RGBtoHEX(255 - i, 255, 255));
190 for (var i = 0; i < 256; i += Math.floor(255 / n))
191 col.push(RGBtoHEX(0, 255 - i, 255));
192 for (var i = 0; i < 256; i += Math.floor(255 / n))
193 col.push(RGBtoHEX(0, 0, 255 - i));
194 for (var i = 0; i < 256; i += Math.floor(255 / n))
195 col.push(RGBtoHEX(i, 0, 0));
196 for (var i = 0; i < 256; i += Math.floor(255 / n))
197 col.push(RGBtoHEX(255, i, 0));
198 for (var i = 0; i < 256; i += Math.floor(255 / n))
199 col.push(RGBtoHEX(255, 255, i));
200 return col;
201 }
202
203 function init_canvas(canvas) {
204 canvas.onselectstart = function () {return false;}; // запрет выделения canvas
205 canvas.oncontextmenu = function () {return false;}; // блокировка контекстного меню
206
207 var canv_obj = {};
208 canv_obj.ctx = canvas.getContext("2d"); // на context происходит рисование
209 canv_obj.w = canvas.width; // ширина окна в расчетных координатах
210 canv_obj.h = canvas.height; // высота окна в расчетных координатах
211
212 return canv_obj;
213 }
214 }
Файл "Heat_2D.html"
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8" />
5 <title>Heat 2D</title>
6 <script src="Heat_2D.js"></script>
7 </head>
8 <body>
9 <canvas id="Heat_2D_canvas" width="700" height="700" style="border:1px solid #000000; border-radius:6px; margin-bottom: -5px"></canvas>
10 <br><br>
11 <input type="button" id="button_pause" value="Пауза/Старт"/>
12 <input type="button" id="button_clear" value="Очистить"/>
13 </body>
14 </html>