Двумерное уравнение теплопроводности
Материал из Department of Theoretical and Applied Mechanics
Версия от 18:56, 8 марта 2015; Wikiadmin (обсуждение | вклад) (Замена текста — «</source>» на «</syntaxhighligh>»)
Виртуальная лаборатория > Двумерное уравнение теплопроводности
Численное решение двумерного уравнения теплопроводности.
Управление:
- Левая кнопка мыши - нагреть область
- Средняя кнопка мыши - придать области нормальную температуру
- Правая кнопка мыши - охладить область
Скачать Heat_2D_v1-4-mini_release.zip.
Текст программы на языке JavaScript (разработчики Цветков Денис, Кривцов Антон): <toggledisplay status=hide showtext="Показать↓" hidetext="Скрыть↑" linkstyle="font-size:default"> Файл "Heat_2D.js" <syntaxhighlight lang="javascript" line start="1" enclose="div"> window.addEventListener("load", main_heat, false); function main_heat() {
// Предварительные установки
var canv = init_canvas(Heat_2D_canvas);
var a0 = 1; // масштаб расстояния var t0 = 1; // масштаб времени var m0 = 1; // масштаб массы var T0 = 1; // масштаб температуры
var dx = 1 * a0; // шаг сетки по оси x
var spf = 1; // steps per frame - сколько расчетов проходит за каждый кадр отображения var fps = 15; var dt = 0.005 * t0; // шаг интегрирования по времени
var p0 = m0 / (a0 * a0 * a0); // единица плотности, кг/м3 var c0 = a0 * a0 / (t0 * t0 * T0); // единица удельной теплоемкости, Дж/(кг * К) (Дж = кг * м2 / с2) var kap0 = m0 * a0 / (t0 * t0 * t0 * T0);// единица теплопроводности (?, каппа)
var p = 0.15 * p0; var c = 0.2 * c0; var k = 1 * kap0; var X = k / (c * p); // температуропроводность (?, хи)
var Nx = 50 + 2; // количество узлов по оси x + 2 для ГУ var Ny = 50 + 2;
var cell_w = canv.w / (Nx - 2); // ширина клетки var cell_h = canv.h / (Ny - 2); // высота клетки
// Минимальная и максимальная температуры используются для подбора цветовой гаммы var T_min = 0 * T0; var T_max = 10 * T0;
var T_mouse_max = 9; // температура для левой клавиши мыши var T_mouse_min = 1; // температура для правой клавиши мыши
var color_N = 60; // цветов не больше, чем color_N, саму переменную color_N в расчетах лучше не использовать var colors = prepare_colors(color_N); var cell_pics = prepare_cell_pics(colors);
var pause = false; button_pause.onclick = function () {pause = !pause;}; button_clear.onclick = function () { for (var i = 0; i < Nx; i++) { for (var j = 0; j < Ny; j++) { T[i][j].u = (T_max - T_min) / 2; T[i][j].v = 0; } } draw_graph(); };
var T = []; for (var i = 0; i < Nx; i++) { T[i] = []; for (var j = 0; j < Ny; j++) { T[i][j] = {}; var x = i / (Nx - 1); var y = j / (Ny - 1);
var width = 0.05; var power = 5; var plus = 5;
T[i][j].u = Math.exp(-Math.pow(x - 0.5, 2) / width) * Math.exp(-Math.pow(y - 0.5, 2) / width) * power + plus; T[i][j].v = 0; } }
// периодические граничные условия for (i = 1; i < Nx - 1; i++) { T[i][0] = T[i][Ny - 2]; T[i][Ny - 1] = T[i][1]; } for (j = 0; j < Ny; j++) { T[0][j] = T[Nx - 2][j]; T[Nx - 1][j] = T[1][j]; }
function prepare_cell_pics(col) { var pics = []; for (var i = 0; i < col.length; i++) { var cell = document.createElement('canvas'); var cell_ctx = cell.getContext('2d');
cell_ctx.fillStyle = col[i]; cell_ctx.beginPath(); cell_ctx.rect(0, 0, cell_w, cell_h); cell_ctx.fill(); pics.push(cell); } return pics; }
function control() { if (!pause) { calculate_steps(spf, dt); draw_graph(); } }
setInterval(control, 1000 / fps); // Запуск системы
// Работа с мышью
Heat_2D_canvas.onmousedown = function(e){ // функция при нажатии клавиши мыши var T1; if (e.which == 1) T1 = T_mouse_max; // при нажатии левой клавиши мыши клетка нагревается else if (e.which == 2) T1 = (T_max - T_min) / 2; // при нажатии средней клавиши мыши клетка получает среднюю температуру else if (e.which == 3) T1 = T_mouse_min; // при нажатии правой клавиши мыши клетка остывает else return;
set_cell(e, T1); Heat_2D_canvas.onmousemove = function(e) {set_cell(e, T1);}; // функция, выполняющаяся при перемещении курсора мыши return false; };
document.onmouseup = function(e){ // функция при отпускании клавиши мыши Heat_2D_canvas.onmousemove = null; // когда клавиша отпущена - функции перемещения нету };
function set_cell(e, T1){ // придать клетке определенное состояние с нажатия клавиши мыши var m = mouse_coords(e); // обновить координаты в переменных mouseX, mouseY if (m.x < 0 || m.x >= canv.w || m.y < 0 || m.y >= canv.h) return; // проверка на ошибочные координаты // везде прибавляем 1 - из за периодических условий массив сдвинут на 1 var i = Math.floor(m.x / cell_w) + 1; // получаем ячейку по горизонтали var j = Math.floor(m.y / cell_h) + 1; // получаем ячейку по вертикали T[i][j].u = T1; draw_cell(i, j); }
function mouse_coords(e) { // функция возвращает экранные координаты курсора мыши var m = []; var rect = Heat_2D_canvas.getBoundingClientRect(); m.x = e.clientX - rect.left; m.y = e.clientY - rect.top; return m; }
function calculate_steps(spf, dt) { var koeff1 = X / (dx * dx) * dt; for (var s = 0; s < spf; s++) { for (var i = 1; i < Nx - 1; i++) { for (var j = 1; j < Ny - 1; j++) { 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; } }
for (var i = 1; i < Nx - 1; i++) { for (var j = 1; j < Ny - 1; j++) { T[i][j].u += T[i][j].v; } } } }
function draw_graph() { // график canv.ctx.clearRect(0, 0, canv.w, canv.h); for (var i = 1; i <= Nx - 1; i++) { for (var j = 1; j <= Ny - 1; j++) { var col = Math.round((T[i][j].u - T_min) * (colors.length - 1) / (T_max - T_min)); // 0 <= col <= color_N if (col < 0) col = 0; if (col > (colors.length - 1)) col = (colors.length - 1); canv.ctx.drawImage(cell_pics[col], (i - 1) * cell_w, (j - 1) * cell_h); } } }
function draw_cell(i, j) { var col = Math.round((T[i][j].u - T_min) * (colors.length - 1) / (T_max - T_min)); // 0 < col < color_N canv.ctx.drawImage(cell_pics[col], (i - 1) * cell_w, (j - 1) * cell_h); } function RGBtoHEX(r, g, b) { return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); }
function prepare_colors(N) { var col = []; var n = N / 6 - 1; for (var i = 0; i < 256; i += Math.floor(255 / n)) col.push(RGBtoHEX(255 - i, 255, 255)); for (var i = 0; i < 256; i += Math.floor(255 / n)) col.push(RGBtoHEX(0, 255 - i, 255)); for (var i = 0; i < 256; i += Math.floor(255 / n)) col.push(RGBtoHEX(0, 0, 255 - i)); for (var i = 0; i < 256; i += Math.floor(255 / n)) col.push(RGBtoHEX(i, 0, 0)); for (var i = 0; i < 256; i += Math.floor(255 / n)) col.push(RGBtoHEX(255, i, 0)); for (var i = 0; i < 256; i += Math.floor(255 / n)) col.push(RGBtoHEX(255, 255, i)); return col; }
function init_canvas(canvas) { canvas.onselectstart = function () {return false;}; // запрет выделения canvas canvas.oncontextmenu = function () {return false;}; // блокировка контекстного меню
var canv_obj = {}; canv_obj.ctx = canvas.getContext("2d"); // на context происходит рисование canv_obj.w = canvas.width; // ширина окна в расчетных координатах canv_obj.h = canvas.height; // высота окна в расчетных координатах
return canv_obj; }
} </syntaxhighligh> Файл "Heat_2D.html" <syntaxhighlight lang="html" line start="1" enclose="div"> <!DOCTYPE html> <html> <head>
<meta charset="UTF-8" /> <title>Heat 2D</title> <script src="Heat_2D.js"></script>
</head> <body>
<canvas id="Heat_2D_canvas" width="700" height="700" style="border:1px solid #000000; border-radius:6px; margin-bottom: -5px"></canvas>
<input type="button" id="button_pause" value="Пауза/Старт"/> <input type="button" id="button_clear" value="Очистить"/>
</body> </html> </syntaxhighligh> </toggledisplay>