Двумерное уравнение теплопроводности — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
Денис (обсуждение | вклад) |
Денис (обсуждение | вклад) |
||
Строка 3: | Строка 3: | ||
Численное решение двумерного уравнения теплопроводности. | Численное решение двумерного уравнения теплопроводности. | ||
− | + | Управление: | |
* '''''Левая кнопка мыши''''' - нагреть область | * '''''Левая кнопка мыши''''' - нагреть область | ||
* '''''Средняя кнопка мыши''''' - придать области нормальную температуру | * '''''Средняя кнопка мыши''''' - придать области нормальную температуру |
Версия 12:43, 7 октября 2014
Виртуальная лаборатория > Двумерное уравнение теплопроводностиЧисленное решение двумерного уравнения теплопроводности.
Управление:
- Левая кнопка мыши - нагреть область
- Средняя кнопка мыши - придать области нормальную температуру
- Правая кнопка мыши - охладить область
Скачать Heat_2D_v1-4-mini_release.zip.
Текст программы на языке JavaScript (разработчики Цветков Денис, Кривцов Антон): <toggledisplay status=hide showtext="Показать↓" hidetext="Скрыть↑" linkstyle="font-size:default"> Файл "Heat_2D.js"
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;
}
}
Файл "Heat_2D.html"
<!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>
<br><br>
<input type="button" id="button_pause" value="Пауза/Старт"/>
<input type="button" id="button_clear" value="Очистить"/>
</body>
</html>
</toggledisplay>