КП: Молекула углекислого газа — различия между версиями
Foten (обсуждение | вклад) |
|||
(не показано 36 промежуточных версий 8 участников) | |||
Строка 1: | Строка 1: | ||
− | [[А.М. Кривцов]] > [[Теоретическая механика: физико-механический факультет|Теоретическая механика]] > [[Курсовые проекты ТМ 2015]] > '''Молекула | + | [[А.М. Кривцов]] > [[Теоретическая механика: физико-механический факультет|Теоретическая механика]] > [[Курсовые проекты ТМ 2015]] > '''Молекула углекислого газа''' <HR> |
Строка 11: | Строка 11: | ||
== Аннотация проекта == | == Аннотация проекта == | ||
+ | Моделирование молекул, даже самых простых - сложная задача. Для их моделирования необходимо использовать многочастичные потенциалы, но их программирование - тоже очень сложная задача. Встает вопрос о том, можно ли найти более простой путь моделирования простейших молекул. | ||
+ | Для моделирования хорошо подходят парные потенциалы, ибо они имеют простой вид и легко программируются. Но как их применить к моделированию молекул ? Моя работа и посвящена решению данной проблемы. | ||
== Формулировка задачи == | == Формулировка задачи == | ||
− | Смоделировать с помощью многочастичного потенциала молекулу углекислого газа ( 2D модель ) и рассмотреть ее простейшую динамику | + | Смоделировать с помощью многочастичного потенциала молекулу углекислого газа ( 2D модель ) и рассмотреть ее простейшую динамику молекулы. |
== Общие сведения по теме == | == Общие сведения по теме == | ||
Строка 33: | Строка 35: | ||
* <math>\alpha</math> — параметр, характеризующий ширину потенциальной ямы. | * <math>\alpha</math> — параметр, характеризующий ширину потенциальной ямы. | ||
− | Потенциал имеет один безразмерный параметр <math>\alpha a </math>. При <math>\alpha a = 6</math> взаимодействия Морзе и Леннард-Джонса близки. При увеличении | + | Потенциал имеет один безразмерный параметр <math>\alpha a </math>. При <math>\alpha a = 6</math> взаимодействия Морзе и Леннард-Джонса близки. При увеличении <math>\alpha a </math> ширина потенциальной ямы для взаимодействия Морзе уменьшается, взаимодействие становится более жестким и хрупким. Уменьшение <math>\alpha a </math> приводит к противоположным изменениям — потенциальная яма расширяется, жесткость падает. |
Сила, соответствующая потенциалу Морзе, вычисляется по формуле: | Сила, соответствующая потенциалу Морзе, вычисляется по формуле: | ||
::<math> | ::<math> | ||
Строка 73: | Строка 75: | ||
Взяв за основу программу [[Balls v4 |Balls v4]], было получено: | Взяв за основу программу [[Balls v4 |Balls v4]], было получено: | ||
* программа, в которой можно рассмотреть динамику одной молекулы углекислого газа в другом газе ( например в азоте ). | * программа, в которой можно рассмотреть динамику одной молекулы углекислого газа в другом газе ( например в азоте ). | ||
− | * 2 версии программы с различными потенциалами. | + | * 2 версии программы с различными потенциалами. |
+ | * создание молекулы за конечное время. | ||
+ | |||
+ | [http://cl49743.tmweb.ru/sites/CO2.html Первая версия (потенциал Морзе) ] | ||
+ | |||
+ | * Синий шар - кислород . | ||
+ | * Коралловый шар - углерод . | ||
+ | * Желтый шар - азот. | ||
+ | |||
+ | |||
+ | {{#widget:Iframe|url=http://cl49743.tmweb.ru/sites/Balls_v4_release.html |width=810|height:800|border=0}} | ||
+ | |||
+ | [http://cl49743.tmweb.ru/sites/Balls_v4_release.html Вторая версия (потенциал Морзе) ] | ||
+ | |||
+ | * Цвет шаров аналогичный. | ||
+ | * Левая кнопка мыши - добавление желтой частицы. | ||
+ | * Правая кнопка мыши - удаление любого шара. | ||
+ | * В системе теперь присутствует несколько молекул. | ||
+ | |||
+ | |||
+ | <div class="mw-collapsible mw-collapsed"> | ||
+ | '''Текст программы на языке JavaScript:''' <div class="mw-collapsible-content"> | ||
+ | Файл '''CO2.js''' | ||
+ | <syntaxhighlight lang="javascript" line start="1" enclose="div"> | ||
+ | // m: Молекула углекислого газа | ||
+ | // Версия 2.0 от 01.06.15 | ||
+ | |||
+ | window.addEventListener("load", MainBalls, true); | ||
+ | function MainBalls() { | ||
+ | |||
+ | // Предварительные установки | ||
+ | |||
+ | var canvas = canvasBalls; | ||
+ | var context = canvas.getContext("2d"); // на context происходит рисование | ||
+ | canvas.oncontextmenu = function (e) {return false;}; // блокировка контекстного меню | ||
+ | |||
+ | var Pi = 3.1415926; // число "пи" | ||
+ | |||
+ | var m0 = 1; // масштаб массы | ||
+ | var T0 = 1; // масштаб времени (период колебаний исходной системы) | ||
+ | var a0 = 1; // масштаб расстояния (диаметр шара) | ||
+ | |||
+ | var g0 = a0 / T0 / T0; // масштаб ускорения (ускорение, при котором за T0 будет пройдено расстояние a0) | ||
+ | var k0 = 2 * Pi / T0; // масштаб частоты | ||
+ | var C0 = m0 * k0 * k0; // масштаб жесткости | ||
+ | var B0 = 2 * m0 * k0; // масштаб вязкости | ||
+ | |||
+ | // *** Задание физических параметров *** | ||
+ | |||
+ | var Ny = 5; // число шаров, помещающихся по вертикали в окно (задает размер шара относительно размера окна) | ||
+ | var m = 1 * m0; // масса | ||
+ | var Cwall = 10 * C0; // жесткость стен | ||
+ | var B = 0.003 * B0; // вязкость среды | ||
+ | var Bwall = 0.03 * B0; // вязкость на стенках | ||
+ | var Cball = 0.1 * Cwall; // жесткость между частицами | ||
+ | var mg = 0//0.25 * m * g0; // сила тяжести | ||
+ | var r = 0.1 * a0; // радиус частицы в расчетных координатах | ||
+ | var K = 0.85; // сила взаимодействия ограничивается значением, реализующимся при r/a = K | ||
+ | var a = 5 * r; // равновесное расстояние между частицами | ||
+ | var a_1 = 2.1 * r; | ||
+ | var a_2 = 2.1 * a ; | ||
+ | var aCut = 2 * r ; // радиус обрезания | ||
+ | var alfa = 5 ; | ||
+ | |||
+ | |||
+ | // *** Задание вычислительных параметров *** | ||
+ | |||
+ | var fps = 50; // frames per second - число кадров в секунду (качечтво отображения) | ||
+ | var spf = 100; // steps per frame - число шагов интегрирования между кадрами (скорость расчета) | ||
+ | var dt = 0.045 * T0 / fps; // шаг интегрирования (качество расчета) | ||
+ | |||
+ | // Выполнение программы | ||
+ | |||
+ | var scale = canvas.height / Ny / a0 ; // масштабный коэффициент для перехода от расчетных к экранным координатам | ||
+ | var r2 = r * r ; // ___в целях оптимизации___ | ||
+ | var aCut2 = aCut * aCut ; // ___в целях оптимизации___ | ||
+ | var a2 = a * a ; // ___в целях оптимизации___ | ||
+ | var a22 = a_2 * a_2 ; | ||
+ | var a11 = a_1 * a_1 ; | ||
+ | var D = a2 * Cball / 72 ; // энергия связи между частицами | ||
+ | var LJCoeff = 12 * D / a2 ; // коэффициент для расчета потенциала Л-Дж | ||
+ | var a1 = alfa / a ; | ||
+ | var MorzCoeff = 2 * a1 * D ; | ||
+ | |||
+ | var Ka = K * r ; // ___в целях оптимизации___ | ||
+ | var K2a2 = Ka*Ka ; // ___в целях оптимизации___ | ||
+ | |||
+ | var w = canvas.width / scale ; // ширина окна в расчетных координатах | ||
+ | var h = canvas.height / scale ; // высота окна в расчетных координатах | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | var dNd = null ; // ссылка на захваченный курсором шар (drag & drop) | ||
+ | |||
+ | // Работа с мышью | ||
+ | |||
+ | var mx_, my_; // буфер позиции мыши (для расчета скорости при отпускании шара) | ||
+ | |||
+ | canvas.onmousedown = function(e) { // функция при нажатии клавиши мыши | ||
+ | var m = mouseCoords(e); // получаем расчетные координаты курсора мыши | ||
+ | // цикл в обратную сторону, чтобы захватывать шар, нарисованный "сверху" | ||
+ | // (т.к. цикл рисования идет в обычном порядке) | ||
+ | for (var i = balls.length - 1; i >= 0; i--) { | ||
+ | var b = balls[i]; | ||
+ | var rx = b.x - m.x; | ||
+ | var ry = b.y - m.y; | ||
+ | var rLen2 = rx * rx + ry * ry; // квадрат расстояния между курсором и центром шара | ||
+ | if (rLen2 <= r2) { // курсор нажал на шар | ||
+ | if (e.which == 1) { // нажата левая клавиша мыши | ||
+ | dNd = b; | ||
+ | dNd.xPlus = dNd.x - m.x; // сдвиг курсора относительно центра шара по x | ||
+ | dNd.yPlus = dNd.y - m.y; // сдвиг курсора относительно центра шара по y | ||
+ | mx_ = m.x; my_ = m.y; | ||
+ | canvas.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения | ||
+ | } else if (e.which == 3) { // нажата правая клавиша мыши | ||
+ | balls.splice(i, 1); // удалить шар | ||
+ | } | ||
+ | return; | ||
+ | } | ||
+ | } | ||
+ | for (var i = C.length - 1; i >= 0; i--) { | ||
+ | var b = C[i]; | ||
+ | var rx = b.x - m.x; | ||
+ | var ry = b.y - m.y; | ||
+ | var rLen2 = rx * rx + ry * ry; // квадрат расстояния между курсором и центром шара | ||
+ | if (rLen2 <= r2) { // курсор нажал на шар | ||
+ | if (e.which == 1) { // нажата левая клавиша мыши | ||
+ | dNd = b; | ||
+ | dNd.xPlus = dNd.x - m.x; // сдвиг курсора относительно центра шара по x | ||
+ | dNd.yPlus = dNd.y - m.y; // сдвиг курсора относительно центра шара по y | ||
+ | mx_ = m.x; my_ = m.y; | ||
+ | canvas.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения | ||
+ | } else if (e.which == 3) { // нажата правая клавиша мыши | ||
+ | C.splice(i, 1); // удалить шар | ||
+ | } | ||
+ | return; | ||
+ | } | ||
+ | } | ||
+ | for (var i = O1.length - 1; i >= 0; i--) { | ||
+ | var b = O1[i]; | ||
+ | var rx = b.x - m.x; | ||
+ | var ry = b.y - m.y; | ||
+ | var rLen2 = rx * rx + ry * ry; // квадрат расстояния между курсором и центром шара | ||
+ | if (rLen2 <= r2) { // курсор нажал на шар | ||
+ | if (e.which == 1) { // нажата левая клавиша мыши | ||
+ | dNd = b; | ||
+ | dNd.xPlus = dNd.x - m.x; // сдвиг курсора относительно центра шара по x | ||
+ | dNd.yPlus = dNd.y - m.y; // сдвиг курсора относительно центра шара по y | ||
+ | mx_ = m.x; my_ = m.y; | ||
+ | canvas.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения | ||
+ | } else if (e.which == 3) { // нажата правая клавиша мыши | ||
+ | O1.splice(i, 1); // удалить шар | ||
+ | } | ||
+ | return; | ||
+ | } | ||
+ | } | ||
+ | for (var i = O2.length - 1; i >= 0; i--) { | ||
+ | var b = O2[i]; | ||
+ | var rx = b.x - m.x; | ||
+ | var ry = b.y - m.y; | ||
+ | var rLen2 = rx * rx + ry * ry; // квадрат расстояния между курсором и центром шара | ||
+ | if (rLen2 <= r2) { // курсор нажал на шар | ||
+ | if (e.which == 1) { // нажата левая клавиша мыши | ||
+ | dNd = b; | ||
+ | dNd.xPlus = dNd.x - m.x; // сдвиг курсора относительно центра шара по x | ||
+ | dNd.yPlus = dNd.y - m.y; // сдвиг курсора относительно центра шара по y | ||
+ | mx_ = m.x; my_ = m.y; | ||
+ | canvas.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения | ||
+ | } else if (e.which == 3) { // нажата правая клавиша мыши | ||
+ | O2.splice(i, 1); // удалить шар | ||
+ | } | ||
+ | return; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // если не вышли по return из цикла - нажатие было вне шара, добавляем новый | ||
+ | if (e.which == 1) { | ||
+ | dNd = addNewBall(m.x, m.y); // добавляем шар и сразу захватываем его курсором | ||
+ | if (dNd == null) return; // если шар не добавился (из за стен или других шаров) - возвращаемся | ||
+ | dNd.xPlus = 0; dNd.yPlus = 0; // держим шар по центру | ||
+ | mx_ = m.x; my_ = m.y; | ||
+ | canvas.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения | ||
+ | } | ||
+ | |||
+ | |||
+ | }; | ||
+ | |||
+ | document.onmouseup = function(e) { // функция при отпускании клавиши мыши | ||
+ | canvas.onmousemove = null; // когда клавиша отпущена - функции перемещения нету | ||
+ | dNd = null; // когда клавиша отпущена - захваченного курсором шара нету | ||
+ | }; | ||
+ | |||
+ | function mouseMove(e) { // функция при перемещении мыши, работает только с зажатой ЛКМ | ||
+ | var m = mouseCoords(e); // получаем расчетные координаты курсора мыши | ||
+ | dNd.x = m.x + dNd.xPlus; | ||
+ | dNd.y = m.y + dNd.yPlus; | ||
+ | dNd.vx = 0.6 * (m.x - mx_) / dt / fps; dNd.vy = 0.6 * (m.y - my_) / dt / fps; | ||
+ | mx_ = m.x; my_ = m.y; | ||
+ | } | ||
+ | |||
+ | function mouseCoords(e) { // функция возвращает расчетные координаты курсора мыши | ||
+ | var m = []; | ||
+ | var rect = canvas.getBoundingClientRect(); | ||
+ | m.x = (e.clientX - rect.left) / scale; | ||
+ | m.y = (e.clientY - rect.top) / scale; | ||
+ | return m; | ||
+ | } | ||
+ | |||
+ | // Работа с массивом | ||
+ | |||
+ | var balls = []; // массив шаров | ||
+ | var C =[] ; | ||
+ | var O1 = [] ; | ||
+ | var O2 = [] ; | ||
+ | |||
+ | var addNewBall = function(x, y) { | ||
+ | // проверка - не пересекается ли новый шар со стенами или уже существующими шарами | ||
+ | if (x - r < 0 || x + r > w || y - r < 0 || y + r > h) return null; | ||
+ | for (var i = 0; i < balls.length; i++) { | ||
+ | var rx = balls[i].x - x; | ||
+ | var ry = balls[i].y - y; | ||
+ | var rLen2 = rx * rx + ry * ry; | ||
+ | if (rLen2 < 4 * r2) return null; | ||
+ | } | ||
+ | var b = []; | ||
+ | |||
+ | b.x = x; b.y = y; // расчетные координаты шара | ||
+ | b.fx = 0; b.fy = mg; // сила, действующая на шар | ||
+ | b.vx = 0; b.vy = 0; // скорость | ||
+ | |||
+ | balls[balls.length] = b; // добавить элемент в конец массива | ||
+ | |||
+ | return b; | ||
+ | }; | ||
+ | |||
+ | var addNewC = function(x, y) { | ||
+ | // проверка - не пересекается ли новый шар со стенами или уже существующими шарами | ||
+ | if (x - r < 0 || x + r > w || y - r < 0 || y + r > h) return null; | ||
+ | for (var i = 0; i < balls.length; i++) { | ||
+ | var rx = balls[i].x - x; | ||
+ | var ry = balls[i].y - y; | ||
+ | var rLen2 = rx * rx + ry * ry; | ||
+ | if (rLen2 < 4 * r2) return null; | ||
+ | } | ||
+ | var b = []; | ||
+ | |||
+ | b.x = x; b.y = y; // расчетные координаты шара | ||
+ | b.fx = 0; b.fy = mg; // сила, действующая на шар | ||
+ | b.vx = 0; b.vy = 0; // скорость | ||
+ | |||
+ | C[C.length] = b; // добавить элемент в конец массива | ||
+ | |||
+ | return b; | ||
+ | }; | ||
+ | |||
+ | var addNewO1 = function(x, y) { | ||
+ | // проверка - не пересекается ли новый шар со стенами или уже существующими шарами | ||
+ | if (x - r < 0 || x + r > w || y - r < 0 || y + r > h) return null; | ||
+ | for (var i = 0; i < balls.length; i++) { | ||
+ | var rx = balls[i].x - x; | ||
+ | var ry = balls[i].y - y; | ||
+ | var rLen2 = rx * rx + ry * ry; | ||
+ | if (rLen2 < 4 * r2) return null; | ||
+ | } | ||
+ | var b = []; | ||
+ | |||
+ | b.x = x; b.y = y; // расчетные координаты шара | ||
+ | b.fx = 0; b.fy = mg; // сила, действующая на шар | ||
+ | b.vx = 0; b.vy = 0; // скорость | ||
+ | |||
+ | O1[O1.length] = b; // добавить элемент в конец массива | ||
+ | |||
+ | return b; | ||
+ | }; | ||
+ | |||
+ | var addNewO2 = function(x, y) { | ||
+ | // проверка - не пересекается ли новый шар со стенами или уже существующими шарами | ||
+ | if (x - r < 0 || x + r > w || y - r < 0 || y + r > h) return null; | ||
+ | for (var i = 0; i < balls.length; i++) { | ||
+ | var rx = balls[i].x - x; | ||
+ | var ry = balls[i].y - y; | ||
+ | var rLen2 = rx * rx + ry * ry; | ||
+ | if (rLen2 < 4 * r2) return null; | ||
+ | } | ||
+ | var b = []; | ||
+ | |||
+ | b.x = x; b.y = y; // расчетные координаты шара | ||
+ | b.fx = 0; b.fy = mg; // сила, действующая на шар | ||
+ | b.vx = 0; b.vy = 0; // скорость | ||
+ | |||
+ | O2[O2.length] = b; // добавить элемент в конец массива | ||
+ | |||
+ | return b; | ||
+ | }; | ||
+ | |||
+ | // Основной цикл программы | ||
+ | |||
+ | function control() { | ||
+ | physics(); | ||
+ | draw(); | ||
+ | } | ||
+ | |||
+ | // Расчетная часть программы | ||
+ | |||
+ | function powers(b ,b2 , hkk , jk ) { | ||
+ | var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b) | ||
+ | var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами | ||
+ | |||
+ | var rLen = (Math.sqrt(r2)); | ||
+ | |||
+ | if (r2 < K2a2) { | ||
+ | if (rLen > 0.00001) { // проверка, чтобы избежать деления на 0 | ||
+ | rx = rx / rLen * Ka; | ||
+ | ry = ry / rLen * Ka; | ||
+ | } | ||
+ | r2 = K2a2; | ||
+ | rLen = Ka; // корень K2a2 | ||
+ | } | ||
+ | |||
+ | // сила взаимодействия | ||
+ | |||
+ | var u = Math.exp( -a1 * ( rLen - hkk )) ; | ||
+ | var F = jk * MorzCoeff * u* ( u - 1 ) /rLen ; | ||
+ | |||
+ | var Fx = F * rx; var Fy = F * ry; | ||
+ | b.fx += Fx; b.fy += Fy; | ||
+ | b2.fx -= Fx; b2.fy -= Fy; | ||
+ | } | ||
+ | |||
+ | |||
+ | function physics() { // то, что происходит каждый шаг времени | ||
+ | for (var s = 1; s <= spf; s++) { | ||
+ | |||
+ | // пересчет сил идет отдельным массивом, т.к. далее будут добавляться силы взаимодействия между шарами | ||
+ | |||
+ | for (var i0 = 0; i0 < balls.length; i0++) { | ||
+ | balls[i0].fx = - B * balls[i0].vx; | ||
+ | balls[i0].fy = mg - B * balls[i0].vy; | ||
+ | } | ||
+ | for (var i0 = 0; i0 < C.length; i0++) { | ||
+ | C[i0].fx = - B * C[i0].vx; | ||
+ | C[i0].fy = mg - B * C[i0].vy; | ||
+ | } | ||
+ | for (var i0 = 0; i0 < O1.length; i0++) { | ||
+ | O1[i0].fx = - B * O1[i0].vx; | ||
+ | O1[i0].fy = mg - B * O1[i0].vy; | ||
+ | } | ||
+ | for (var i0 = 0; i0 < O2.length; i0++) { | ||
+ | O2[i0].fx = - B * O2[i0].vx; | ||
+ | O2[i0].fy = mg - B * O2[i0].vy; | ||
+ | } | ||
+ | |||
+ | |||
+ | for (var i = 0; i < balls.length; i++) { // dlya Balls | ||
+ | // расчет взаимодействия производится со всеми следующими шарами в массиве, | ||
+ | // чтобы не считать каждое взаимодействие дважды | ||
+ | |||
+ | var b = balls[i]; | ||
+ | |||
+ | for (var j = i + 1; j < balls.length; j++) { | ||
+ | var b2 = balls[j]; | ||
+ | var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b) | ||
+ | var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами | ||
+ | |||
+ | if ( r2 > aCut2 ) continue ; | ||
+ | |||
+ | powers(b,b2,a_1,0.3) ; | ||
+ | |||
+ | } | ||
+ | for (var j = 0; j < C.length; j++) { | ||
+ | var b2 = C[j]; | ||
+ | var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b) | ||
+ | var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами | ||
+ | |||
+ | if ( r2 > aCut2 ) continue ; | ||
+ | |||
+ | powers(b,b2,a_1,0.3) ; | ||
+ | |||
+ | } | ||
+ | for (var j = 0; j < O1.length; j++) { | ||
+ | var b2 = O1[j]; | ||
+ | var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b) | ||
+ | var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами | ||
+ | |||
+ | if ( r2 > aCut2 ) continue ; | ||
+ | |||
+ | powers(b,b2,a_1,0.3) ; | ||
+ | |||
+ | } | ||
+ | |||
+ | for (var j = 0; j < O2.length; j++) { | ||
+ | var b2 = O2[j]; | ||
+ | var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b) | ||
+ | var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами | ||
+ | |||
+ | if ( r2 > aCut2 ) continue ; | ||
+ | |||
+ | powers( b, b2, a_1 ,0.3) ; | ||
+ | |||
+ | } | ||
+ | |||
+ | if (b == dNd) continue; // если шар схвачен курсором - его вз. со стенами и перемещение не считаем | ||
+ | |||
+ | if (b.y + r > h) { b.fy += -Cwall * (b.y + r - h) - Bwall * b.vy; } | ||
+ | if (b.y - r < 0) { b.fy += -Cwall * (b.y - r) - Bwall * b.vy;} | ||
+ | if (b.x + r > w) { b.fx += -Cwall * (b.x + r - w) - Bwall * b.vx; } | ||
+ | if (b.x - r < 0) { b.fx += -Cwall * (b.x - r) - Bwall * b.vx; } | ||
+ | |||
+ | b.vx += b.fx / m * dt; b.vy += b.fy / m * dt; | ||
+ | b.x += b.vx * dt; b.y += b.vy * dt; | ||
+ | |||
+ | } | ||
+ | |||
+ | for (var i = 0; i < C.length; i++) { // dlya C | ||
+ | // расчет взаимодействия производится со всеми следующими шарами в массиве, | ||
+ | // чтобы не считать каждое взаимодействие дважды | ||
+ | |||
+ | var b = C[i]; | ||
+ | |||
+ | for (var j = i + 1; j < C.length; j++) { | ||
+ | var b2 = C[j]; | ||
+ | var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b) | ||
+ | var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами | ||
+ | |||
+ | if ( r2 > aCut2 ) continue ; | ||
+ | |||
+ | powers(b,b2,a_1, 0.3) ; | ||
+ | |||
+ | } | ||
+ | for (var j = 0; j < O1.length; j++) { | ||
+ | var b2 = O1[j]; | ||
+ | var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b) | ||
+ | var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами | ||
+ | |||
+ | if ( j == i ) { powers(b,b2,a, 6) ;} | ||
+ | else { | ||
+ | if ( r2 > aCut2 ) continue ; | ||
+ | powers(b,b2,a_1, 0.3) ; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | for (var j = 0; j < O2.length; j++) { | ||
+ | var b2 = O2[j]; | ||
+ | var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b) | ||
+ | var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами | ||
+ | |||
+ | if ( j == i ) { powers(b,b2,a,6) ;} | ||
+ | else { | ||
+ | if ( r2 > aCut2 ) continue ; | ||
+ | powers(b,b2,a_1, 0.3) ; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | if (b == dNd) continue; // если шар схвачен курсором - его вз. со стенами и перемещение не считаем | ||
+ | |||
+ | if (b.y + r > h) { b.fy += -Cwall * (b.y + r - h) - Bwall * b.vy; } | ||
+ | if (b.y - r < 0) { b.fy += -Cwall * (b.y - r) - Bwall * b.vy;} | ||
+ | if (b.x + r > w) { b.fx += -Cwall * (b.x + r - w) - Bwall * b.vx; } | ||
+ | if (b.x - r < 0) { b.fx += -Cwall * (b.x - r) - Bwall * b.vx; } | ||
+ | |||
+ | b.vx += b.fx / m * dt; b.vy += b.fy / m * dt; | ||
+ | b.x += b.vx * dt; b.y += b.vy * dt; | ||
+ | |||
+ | } | ||
+ | |||
+ | for (var i = 0; i < C.length; i++) { // dlya O1 | ||
+ | // расчет взаимодействия производится со всеми следующими шарами в массиве, | ||
+ | // чтобы не считать каждое взаимодействие дважды | ||
+ | |||
+ | var b = O1[i]; | ||
+ | |||
+ | for (var j = i + 1; j < O1.length; j++) { | ||
+ | |||
+ | var b2 = O1[j]; | ||
+ | var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b) | ||
+ | var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами | ||
+ | |||
+ | if ( r2 > aCut2 ) continue ; | ||
+ | |||
+ | powers(b,b2,a_1,0.3) ; | ||
+ | |||
+ | } | ||
+ | |||
+ | for (var j = 0; j < O2.length; j++) { | ||
+ | var b2 = O2[j]; | ||
+ | var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b) | ||
+ | var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами | ||
+ | |||
+ | if ( i == j ) { powers(b,b2,a_2, 3) ;} | ||
+ | else { | ||
+ | if ( r2 > aCut2 ) continue ; | ||
+ | else powers(b,b2,a_1 , 0.3) ; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | if (b == dNd) continue; // если шар схвачен курсором - его вз. со стенами и перемещение не считаем | ||
+ | |||
+ | if (b.y + r > h) { b.fy += -Cwall * (b.y + r - h) - Bwall * b.vy; } | ||
+ | if (b.y - r < 0) { b.fy += -Cwall * (b.y - r) - Bwall * b.vy;} | ||
+ | if (b.x + r > w) { b.fx += -Cwall * (b.x + r - w) - Bwall * b.vx; } | ||
+ | if (b.x - r < 0) { b.fx += -Cwall * (b.x - r) - Bwall * b.vx; } | ||
+ | |||
+ | b.vx += b.fx / m * dt; b.vy += b.fy / m * dt; | ||
+ | b.x += b.vx * dt; b.y += b.vy * dt; | ||
+ | |||
+ | } | ||
+ | |||
+ | for (var i = 0; i < C.length; i++) { // dlya O2 | ||
+ | // расчет взаимодействия производится со всеми следующими шарами в массиве, | ||
+ | // чтобы не считать каждое взаимодействие дважды | ||
+ | |||
+ | var b = O2[i]; | ||
+ | |||
+ | for (var j = i + 1; j < O2.length; j++) { | ||
+ | var b2 = O2[j]; | ||
+ | var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b) | ||
+ | var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами | ||
+ | |||
+ | if ( r2 > aCut2) continue ; | ||
+ | |||
+ | powers(b,b2,a_1, 0.3) ; | ||
+ | |||
+ | } | ||
+ | |||
+ | if (b == dNd) continue; // если шар схвачен курсором - его вз. со стенами и перемещение не считаем | ||
+ | |||
+ | if (b.y + r > h) { b.fy += -Cwall * (b.y + r - h) - Bwall * b.vy; } | ||
+ | if (b.y - r < 0) { b.fy += -Cwall * (b.y - r) - Bwall * b.vy;} | ||
+ | if (b.x + r > w) { b.fx += -Cwall * (b.x + r - w) - Bwall * b.vx; } | ||
+ | if (b.x - r < 0) { b.fx += -Cwall * (b.x - r) - Bwall * b.vx; } | ||
+ | |||
+ | b.vx += b.fx / m * dt; b.vy += b.fy / m * dt; | ||
+ | b.x += b.vx * dt; b.y += b.vy * dt; | ||
+ | |||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Рисование | ||
+ | |||
+ | var rScale13 = r * scale * 1.3; // ___в целях оптимизации___ | ||
+ | var rScaleShift = r * scale / 5; // ___в целях оптимизации___ | ||
+ | function draw() { | ||
+ | context.clearRect(0, 0, w * scale, h * scale); // очистить экран | ||
+ | for (var i = 0; i < balls.length; i++){ | ||
+ | var xS = balls[i].x * scale; var yS = balls[i].y * scale; | ||
+ | |||
+ | context.fillStyle = "#FFD700"; | ||
+ | |||
+ | context.beginPath(); | ||
+ | context.arc(xS, yS, r * scale, 0, 2 * Math.PI, false); | ||
+ | context.closePath(); | ||
+ | context.fill(); | ||
+ | } | ||
+ | |||
+ | for (var i = 0; i < C.length; i++){ | ||
+ | var xS = C[i].x * scale; var yS = C[i].y * scale; | ||
+ | |||
+ | context.fillStyle = "#f08080"; | ||
+ | |||
+ | context.beginPath(); | ||
+ | context.arc(xS, yS, r * scale, 0, 2 * Math.PI, false); | ||
+ | context.closePath(); | ||
+ | context.fill(); | ||
+ | } | ||
+ | for (var i = 0; i < O1.length; i++){ | ||
+ | var xS = O1[i].x * scale; var yS = O1[i].y * scale; | ||
+ | |||
+ | context.fillStyle = "#3070d0"; | ||
+ | |||
+ | context.beginPath(); | ||
+ | context.arc(xS, yS, r * scale, 0, 2 * Math.PI, false); | ||
+ | context.closePath(); | ||
+ | context.fill(); | ||
+ | } | ||
+ | for (var i = 0; i < O2.length; i++){ | ||
+ | var xS = O2[i].x * scale; var yS = O2[i].y * scale; | ||
+ | |||
+ | context.fillStyle = "#3070d0"; | ||
+ | |||
+ | context.beginPath(); | ||
+ | context.arc(xS, yS, r * scale, 0, 2 * Math.PI, false); | ||
+ | context.closePath(); | ||
+ | context.fill(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Запуск системы | ||
+ | for (var i = 0; i < 8; i++){ // добавляем 20 частиц, сдвинув их от стен | ||
+ | //addNewBall(Math.random() * (w - 2 * r) + r, Math.random() * (h - 2 * r) + r , 10 ); | ||
+ | addNewC(Math.random() * (w - 2 * r) + r, Math.random() * (h - 2 * r) + r , 10 ); | ||
+ | addNewO1(Math.random() * (w - 2 * r) + r, Math.random() * (h - 2 * r) + r , 10 ); | ||
+ | addNewO2(Math.random() * (w - 2 * r) + r, Math.random() * (h - 2 * r) + r , 10 ); | ||
+ | |||
+ | } | ||
+ | setInterval(control, 1000 / fps); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | </div> | ||
+ | </div> | ||
== Обсуждение результатов и выводы == | == Обсуждение результатов и выводы == | ||
+ | Разработан алгоритм, с помощью которого можно смоделировать молекулу углекислого газа при помощи парных потенциалов. Данная модель имеет свои особенности: | ||
+ | *За конечное время при небольшой вязкости среды частицы собираются в молекулы углекислого газа. | ||
+ | * Поведение молекулы углекислого газа в системе при небольших скоростях получается реалистичным. Это означает, что можно изучать динамику системы при малых скоростях молекул. | ||
+ | *При больших скоростях молекулы углекислого газа разрушаются. После разрушения они собираются заново, образуя те же самые молекулы. | ||
− | + | В будущем планируется ввести степени насыщенности связи и начать моделировать более сложные молекулы. | |
<br> | <br> | ||
− | Скачать | + | Скачать презентацию: Молекула углекислого газа в среде инертного газа [[File:CO2engine.pdf]] |
<br> | <br> | ||
− | Скачать | + | Скачать отчет:[[ File: SmirnovKurs.docx]] |
== Ссылки по теме == | == Ссылки по теме == |
Текущая версия на 23:05, 10 января 2017
А.М. Кривцов > Теоретическая механика > Курсовые проекты ТМ 2015 > Молекула углекислого газа
Курсовой проект по Теоретической механике
Исполнитель: Смирнов Александр
Группа: 09 (23604)
Семестр: весна 2015
Содержание
Аннотация проекта[править]
Моделирование молекул, даже самых простых - сложная задача. Для их моделирования необходимо использовать многочастичные потенциалы, но их программирование - тоже очень сложная задача. Встает вопрос о том, можно ли найти более простой путь моделирования простейших молекул.
Для моделирования хорошо подходят парные потенциалы, ибо они имеют простой вид и легко программируются. Но как их применить к моделированию молекул ? Моя работа и посвящена решению данной проблемы.
Формулировка задачи[править]
Смоделировать с помощью многочастичного потенциала молекулу углекислого газа ( 2D модель ) и рассмотреть ее простейшую динамику молекулы.
Общие сведения по теме[править]
Для решения задачи будем использовать два потенциала: потенциал Морзе и потенциал Леннард-Джонса.
Потенциал Морзе [править]
Парный силовой потенциал взаимодействия. Определяется формулой:
где
- — энергия связи,
- — длина связи,
- — параметр, характеризующий ширину потенциальной ямы.
Потенциал имеет один безразмерный параметр
. При взаимодействия Морзе и Леннард-Джонса близки. При увеличении ширина потенциальной ямы для взаимодействия Морзе уменьшается, взаимодействие становится более жестким и хрупким. Уменьшение приводит к противоположным изменениям — потенциальная яма расширяется, жесткость падает. Сила, соответствующая потенциалу Морзе, вычисляется по формуле:Или в векторной форме:
Потенциал Леннард-Джонса[править]
Также парный силовой потенциал взаимодействия. Определяется формулой:
где
- — расстояние между частицами,
- — энергия связи,
- — длина связи.
Сила взаимодействия, соответствующая потенциалу Леннард-Джонса, вычисляется по формуле
Векторная сила взаимодействия определяется формулой
Углекислый газ [править]
Углекислый газ ( диоксид углерода ) - газ без запаха и цвета. Молекула углекислого газа имеет линейное строение и ковалентные полярные связи, хотя сама молекула не является полярной. Дипольный момент = 0.
Решение[править]
Взяв за основу программу Balls v4, было получено:
- программа, в которой можно рассмотреть динамику одной молекулы углекислого газа в другом газе ( например в азоте ).
- 2 версии программы с различными потенциалами.
- создание молекулы за конечное время.
Первая версия (потенциал Морзе)
- Синий шар - кислород .
- Коралловый шар - углерод .
- Желтый шар - азот.
Вторая версия (потенциал Морзе)
- Цвет шаров аналогичный.
- Левая кнопка мыши - добавление желтой частицы.
- Правая кнопка мыши - удаление любого шара.
- В системе теперь присутствует несколько молекул.
Файл CO2.js
1 // m: Молекула углекислого газа
2 // Версия 2.0 от 01.06.15
3
4 window.addEventListener("load", MainBalls, true);
5 function MainBalls() {
6
7 // Предварительные установки
8
9 var canvas = canvasBalls;
10 var context = canvas.getContext("2d"); // на context происходит рисование
11 canvas.oncontextmenu = function (e) {return false;}; // блокировка контекстного меню
12
13 var Pi = 3.1415926; // число "пи"
14
15 var m0 = 1; // масштаб массы
16 var T0 = 1; // масштаб времени (период колебаний исходной системы)
17 var a0 = 1; // масштаб расстояния (диаметр шара)
18
19 var g0 = a0 / T0 / T0; // масштаб ускорения (ускорение, при котором за T0 будет пройдено расстояние a0)
20 var k0 = 2 * Pi / T0; // масштаб частоты
21 var C0 = m0 * k0 * k0; // масштаб жесткости
22 var B0 = 2 * m0 * k0; // масштаб вязкости
23
24 // *** Задание физических параметров ***
25
26 var Ny = 5; // число шаров, помещающихся по вертикали в окно (задает размер шара относительно размера окна)
27 var m = 1 * m0; // масса
28 var Cwall = 10 * C0; // жесткость стен
29 var B = 0.003 * B0; // вязкость среды
30 var Bwall = 0.03 * B0; // вязкость на стенках
31 var Cball = 0.1 * Cwall; // жесткость между частицами
32 var mg = 0//0.25 * m * g0; // сила тяжести
33 var r = 0.1 * a0; // радиус частицы в расчетных координатах
34 var K = 0.85; // сила взаимодействия ограничивается значением, реализующимся при r/a = K
35 var a = 5 * r; // равновесное расстояние между частицами
36 var a_1 = 2.1 * r;
37 var a_2 = 2.1 * a ;
38 var aCut = 2 * r ; // радиус обрезания
39 var alfa = 5 ;
40
41
42 // *** Задание вычислительных параметров ***
43
44 var fps = 50; // frames per second - число кадров в секунду (качечтво отображения)
45 var spf = 100; // steps per frame - число шагов интегрирования между кадрами (скорость расчета)
46 var dt = 0.045 * T0 / fps; // шаг интегрирования (качество расчета)
47
48 // Выполнение программы
49
50 var scale = canvas.height / Ny / a0 ; // масштабный коэффициент для перехода от расчетных к экранным координатам
51 var r2 = r * r ; // ___в целях оптимизации___
52 var aCut2 = aCut * aCut ; // ___в целях оптимизации___
53 var a2 = a * a ; // ___в целях оптимизации___
54 var a22 = a_2 * a_2 ;
55 var a11 = a_1 * a_1 ;
56 var D = a2 * Cball / 72 ; // энергия связи между частицами
57 var LJCoeff = 12 * D / a2 ; // коэффициент для расчета потенциала Л-Дж
58 var a1 = alfa / a ;
59 var MorzCoeff = 2 * a1 * D ;
60
61 var Ka = K * r ; // ___в целях оптимизации___
62 var K2a2 = Ka*Ka ; // ___в целях оптимизации___
63
64 var w = canvas.width / scale ; // ширина окна в расчетных координатах
65 var h = canvas.height / scale ; // высота окна в расчетных координатах
66
67
68
69
70
71 var dNd = null ; // ссылка на захваченный курсором шар (drag & drop)
72
73 // Работа с мышью
74
75 var mx_, my_; // буфер позиции мыши (для расчета скорости при отпускании шара)
76
77 canvas.onmousedown = function(e) { // функция при нажатии клавиши мыши
78 var m = mouseCoords(e); // получаем расчетные координаты курсора мыши
79 // цикл в обратную сторону, чтобы захватывать шар, нарисованный "сверху"
80 // (т.к. цикл рисования идет в обычном порядке)
81 for (var i = balls.length - 1; i >= 0; i--) {
82 var b = balls[i];
83 var rx = b.x - m.x;
84 var ry = b.y - m.y;
85 var rLen2 = rx * rx + ry * ry; // квадрат расстояния между курсором и центром шара
86 if (rLen2 <= r2) { // курсор нажал на шар
87 if (e.which == 1) { // нажата левая клавиша мыши
88 dNd = b;
89 dNd.xPlus = dNd.x - m.x; // сдвиг курсора относительно центра шара по x
90 dNd.yPlus = dNd.y - m.y; // сдвиг курсора относительно центра шара по y
91 mx_ = m.x; my_ = m.y;
92 canvas.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения
93 } else if (e.which == 3) { // нажата правая клавиша мыши
94 balls.splice(i, 1); // удалить шар
95 }
96 return;
97 }
98 }
99 for (var i = C.length - 1; i >= 0; i--) {
100 var b = C[i];
101 var rx = b.x - m.x;
102 var ry = b.y - m.y;
103 var rLen2 = rx * rx + ry * ry; // квадрат расстояния между курсором и центром шара
104 if (rLen2 <= r2) { // курсор нажал на шар
105 if (e.which == 1) { // нажата левая клавиша мыши
106 dNd = b;
107 dNd.xPlus = dNd.x - m.x; // сдвиг курсора относительно центра шара по x
108 dNd.yPlus = dNd.y - m.y; // сдвиг курсора относительно центра шара по y
109 mx_ = m.x; my_ = m.y;
110 canvas.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения
111 } else if (e.which == 3) { // нажата правая клавиша мыши
112 C.splice(i, 1); // удалить шар
113 }
114 return;
115 }
116 }
117 for (var i = O1.length - 1; i >= 0; i--) {
118 var b = O1[i];
119 var rx = b.x - m.x;
120 var ry = b.y - m.y;
121 var rLen2 = rx * rx + ry * ry; // квадрат расстояния между курсором и центром шара
122 if (rLen2 <= r2) { // курсор нажал на шар
123 if (e.which == 1) { // нажата левая клавиша мыши
124 dNd = b;
125 dNd.xPlus = dNd.x - m.x; // сдвиг курсора относительно центра шара по x
126 dNd.yPlus = dNd.y - m.y; // сдвиг курсора относительно центра шара по y
127 mx_ = m.x; my_ = m.y;
128 canvas.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения
129 } else if (e.which == 3) { // нажата правая клавиша мыши
130 O1.splice(i, 1); // удалить шар
131 }
132 return;
133 }
134 }
135 for (var i = O2.length - 1; i >= 0; i--) {
136 var b = O2[i];
137 var rx = b.x - m.x;
138 var ry = b.y - m.y;
139 var rLen2 = rx * rx + ry * ry; // квадрат расстояния между курсором и центром шара
140 if (rLen2 <= r2) { // курсор нажал на шар
141 if (e.which == 1) { // нажата левая клавиша мыши
142 dNd = b;
143 dNd.xPlus = dNd.x - m.x; // сдвиг курсора относительно центра шара по x
144 dNd.yPlus = dNd.y - m.y; // сдвиг курсора относительно центра шара по y
145 mx_ = m.x; my_ = m.y;
146 canvas.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения
147 } else if (e.which == 3) { // нажата правая клавиша мыши
148 O2.splice(i, 1); // удалить шар
149 }
150 return;
151 }
152 }
153
154 // если не вышли по return из цикла - нажатие было вне шара, добавляем новый
155 if (e.which == 1) {
156 dNd = addNewBall(m.x, m.y); // добавляем шар и сразу захватываем его курсором
157 if (dNd == null) return; // если шар не добавился (из за стен или других шаров) - возвращаемся
158 dNd.xPlus = 0; dNd.yPlus = 0; // держим шар по центру
159 mx_ = m.x; my_ = m.y;
160 canvas.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения
161 }
162
163
164 };
165
166 document.onmouseup = function(e) { // функция при отпускании клавиши мыши
167 canvas.onmousemove = null; // когда клавиша отпущена - функции перемещения нету
168 dNd = null; // когда клавиша отпущена - захваченного курсором шара нету
169 };
170
171 function mouseMove(e) { // функция при перемещении мыши, работает только с зажатой ЛКМ
172 var m = mouseCoords(e); // получаем расчетные координаты курсора мыши
173 dNd.x = m.x + dNd.xPlus;
174 dNd.y = m.y + dNd.yPlus;
175 dNd.vx = 0.6 * (m.x - mx_) / dt / fps; dNd.vy = 0.6 * (m.y - my_) / dt / fps;
176 mx_ = m.x; my_ = m.y;
177 }
178
179 function mouseCoords(e) { // функция возвращает расчетные координаты курсора мыши
180 var m = [];
181 var rect = canvas.getBoundingClientRect();
182 m.x = (e.clientX - rect.left) / scale;
183 m.y = (e.clientY - rect.top) / scale;
184 return m;
185 }
186
187 // Работа с массивом
188
189 var balls = []; // массив шаров
190 var C =[] ;
191 var O1 = [] ;
192 var O2 = [] ;
193
194 var addNewBall = function(x, y) {
195 // проверка - не пересекается ли новый шар со стенами или уже существующими шарами
196 if (x - r < 0 || x + r > w || y - r < 0 || y + r > h) return null;
197 for (var i = 0; i < balls.length; i++) {
198 var rx = balls[i].x - x;
199 var ry = balls[i].y - y;
200 var rLen2 = rx * rx + ry * ry;
201 if (rLen2 < 4 * r2) return null;
202 }
203 var b = [];
204
205 b.x = x; b.y = y; // расчетные координаты шара
206 b.fx = 0; b.fy = mg; // сила, действующая на шар
207 b.vx = 0; b.vy = 0; // скорость
208
209 balls[balls.length] = b; // добавить элемент в конец массива
210
211 return b;
212 };
213
214 var addNewC = function(x, y) {
215 // проверка - не пересекается ли новый шар со стенами или уже существующими шарами
216 if (x - r < 0 || x + r > w || y - r < 0 || y + r > h) return null;
217 for (var i = 0; i < balls.length; i++) {
218 var rx = balls[i].x - x;
219 var ry = balls[i].y - y;
220 var rLen2 = rx * rx + ry * ry;
221 if (rLen2 < 4 * r2) return null;
222 }
223 var b = [];
224
225 b.x = x; b.y = y; // расчетные координаты шара
226 b.fx = 0; b.fy = mg; // сила, действующая на шар
227 b.vx = 0; b.vy = 0; // скорость
228
229 C[C.length] = b; // добавить элемент в конец массива
230
231 return b;
232 };
233
234 var addNewO1 = function(x, y) {
235 // проверка - не пересекается ли новый шар со стенами или уже существующими шарами
236 if (x - r < 0 || x + r > w || y - r < 0 || y + r > h) return null;
237 for (var i = 0; i < balls.length; i++) {
238 var rx = balls[i].x - x;
239 var ry = balls[i].y - y;
240 var rLen2 = rx * rx + ry * ry;
241 if (rLen2 < 4 * r2) return null;
242 }
243 var b = [];
244
245 b.x = x; b.y = y; // расчетные координаты шара
246 b.fx = 0; b.fy = mg; // сила, действующая на шар
247 b.vx = 0; b.vy = 0; // скорость
248
249 O1[O1.length] = b; // добавить элемент в конец массива
250
251 return b;
252 };
253
254 var addNewO2 = function(x, y) {
255 // проверка - не пересекается ли новый шар со стенами или уже существующими шарами
256 if (x - r < 0 || x + r > w || y - r < 0 || y + r > h) return null;
257 for (var i = 0; i < balls.length; i++) {
258 var rx = balls[i].x - x;
259 var ry = balls[i].y - y;
260 var rLen2 = rx * rx + ry * ry;
261 if (rLen2 < 4 * r2) return null;
262 }
263 var b = [];
264
265 b.x = x; b.y = y; // расчетные координаты шара
266 b.fx = 0; b.fy = mg; // сила, действующая на шар
267 b.vx = 0; b.vy = 0; // скорость
268
269 O2[O2.length] = b; // добавить элемент в конец массива
270
271 return b;
272 };
273
274 // Основной цикл программы
275
276 function control() {
277 physics();
278 draw();
279 }
280
281 // Расчетная часть программы
282
283 function powers(b ,b2 , hkk , jk ) {
284 var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b)
285 var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами
286
287 var rLen = (Math.sqrt(r2));
288
289 if (r2 < K2a2) {
290 if (rLen > 0.00001) { // проверка, чтобы избежать деления на 0
291 rx = rx / rLen * Ka;
292 ry = ry / rLen * Ka;
293 }
294 r2 = K2a2;
295 rLen = Ka; // корень K2a2
296 }
297
298 // сила взаимодействия
299
300 var u = Math.exp( -a1 * ( rLen - hkk )) ;
301 var F = jk * MorzCoeff * u* ( u - 1 ) /rLen ;
302
303 var Fx = F * rx; var Fy = F * ry;
304 b.fx += Fx; b.fy += Fy;
305 b2.fx -= Fx; b2.fy -= Fy;
306 }
307
308
309 function physics() { // то, что происходит каждый шаг времени
310 for (var s = 1; s <= spf; s++) {
311
312 // пересчет сил идет отдельным массивом, т.к. далее будут добавляться силы взаимодействия между шарами
313
314 for (var i0 = 0; i0 < balls.length; i0++) {
315 balls[i0].fx = - B * balls[i0].vx;
316 balls[i0].fy = mg - B * balls[i0].vy;
317 }
318 for (var i0 = 0; i0 < C.length; i0++) {
319 C[i0].fx = - B * C[i0].vx;
320 C[i0].fy = mg - B * C[i0].vy;
321 }
322 for (var i0 = 0; i0 < O1.length; i0++) {
323 O1[i0].fx = - B * O1[i0].vx;
324 O1[i0].fy = mg - B * O1[i0].vy;
325 }
326 for (var i0 = 0; i0 < O2.length; i0++) {
327 O2[i0].fx = - B * O2[i0].vx;
328 O2[i0].fy = mg - B * O2[i0].vy;
329 }
330
331
332 for (var i = 0; i < balls.length; i++) { // dlya Balls
333 // расчет взаимодействия производится со всеми следующими шарами в массиве,
334 // чтобы не считать каждое взаимодействие дважды
335
336 var b = balls[i];
337
338 for (var j = i + 1; j < balls.length; j++) {
339 var b2 = balls[j];
340 var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b)
341 var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами
342
343 if ( r2 > aCut2 ) continue ;
344
345 powers(b,b2,a_1,0.3) ;
346
347 }
348 for (var j = 0; j < C.length; j++) {
349 var b2 = C[j];
350 var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b)
351 var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами
352
353 if ( r2 > aCut2 ) continue ;
354
355 powers(b,b2,a_1,0.3) ;
356
357 }
358 for (var j = 0; j < O1.length; j++) {
359 var b2 = O1[j];
360 var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b)
361 var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами
362
363 if ( r2 > aCut2 ) continue ;
364
365 powers(b,b2,a_1,0.3) ;
366
367 }
368
369 for (var j = 0; j < O2.length; j++) {
370 var b2 = O2[j];
371 var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b)
372 var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами
373
374 if ( r2 > aCut2 ) continue ;
375
376 powers( b, b2, a_1 ,0.3) ;
377
378 }
379
380 if (b == dNd) continue; // если шар схвачен курсором - его вз. со стенами и перемещение не считаем
381
382 if (b.y + r > h) { b.fy += -Cwall * (b.y + r - h) - Bwall * b.vy; }
383 if (b.y - r < 0) { b.fy += -Cwall * (b.y - r) - Bwall * b.vy;}
384 if (b.x + r > w) { b.fx += -Cwall * (b.x + r - w) - Bwall * b.vx; }
385 if (b.x - r < 0) { b.fx += -Cwall * (b.x - r) - Bwall * b.vx; }
386
387 b.vx += b.fx / m * dt; b.vy += b.fy / m * dt;
388 b.x += b.vx * dt; b.y += b.vy * dt;
389
390 }
391
392 for (var i = 0; i < C.length; i++) { // dlya C
393 // расчет взаимодействия производится со всеми следующими шарами в массиве,
394 // чтобы не считать каждое взаимодействие дважды
395
396 var b = C[i];
397
398 for (var j = i + 1; j < C.length; j++) {
399 var b2 = C[j];
400 var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b)
401 var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами
402
403 if ( r2 > aCut2 ) continue ;
404
405 powers(b,b2,a_1, 0.3) ;
406
407 }
408 for (var j = 0; j < O1.length; j++) {
409 var b2 = O1[j];
410 var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b)
411 var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами
412
413 if ( j == i ) { powers(b,b2,a, 6) ;}
414 else {
415 if ( r2 > aCut2 ) continue ;
416 powers(b,b2,a_1, 0.3) ;
417 }
418
419 }
420
421 for (var j = 0; j < O2.length; j++) {
422 var b2 = O2[j];
423 var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b)
424 var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами
425
426 if ( j == i ) { powers(b,b2,a,6) ;}
427 else {
428 if ( r2 > aCut2 ) continue ;
429 powers(b,b2,a_1, 0.3) ;
430 }
431
432 }
433
434 if (b == dNd) continue; // если шар схвачен курсором - его вз. со стенами и перемещение не считаем
435
436 if (b.y + r > h) { b.fy += -Cwall * (b.y + r - h) - Bwall * b.vy; }
437 if (b.y - r < 0) { b.fy += -Cwall * (b.y - r) - Bwall * b.vy;}
438 if (b.x + r > w) { b.fx += -Cwall * (b.x + r - w) - Bwall * b.vx; }
439 if (b.x - r < 0) { b.fx += -Cwall * (b.x - r) - Bwall * b.vx; }
440
441 b.vx += b.fx / m * dt; b.vy += b.fy / m * dt;
442 b.x += b.vx * dt; b.y += b.vy * dt;
443
444 }
445
446 for (var i = 0; i < C.length; i++) { // dlya O1
447 // расчет взаимодействия производится со всеми следующими шарами в массиве,
448 // чтобы не считать каждое взаимодействие дважды
449
450 var b = O1[i];
451
452 for (var j = i + 1; j < O1.length; j++) {
453
454 var b2 = O1[j];
455 var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b)
456 var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами
457
458 if ( r2 > aCut2 ) continue ;
459
460 powers(b,b2,a_1,0.3) ;
461
462 }
463
464 for (var j = 0; j < O2.length; j++) {
465 var b2 = O2[j];
466 var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b)
467 var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами
468
469 if ( i == j ) { powers(b,b2,a_2, 3) ;}
470 else {
471 if ( r2 > aCut2 ) continue ;
472 else powers(b,b2,a_1 , 0.3) ;
473 }
474
475 }
476
477 if (b == dNd) continue; // если шар схвачен курсором - его вз. со стенами и перемещение не считаем
478
479 if (b.y + r > h) { b.fy += -Cwall * (b.y + r - h) - Bwall * b.vy; }
480 if (b.y - r < 0) { b.fy += -Cwall * (b.y - r) - Bwall * b.vy;}
481 if (b.x + r > w) { b.fx += -Cwall * (b.x + r - w) - Bwall * b.vx; }
482 if (b.x - r < 0) { b.fx += -Cwall * (b.x - r) - Bwall * b.vx; }
483
484 b.vx += b.fx / m * dt; b.vy += b.fy / m * dt;
485 b.x += b.vx * dt; b.y += b.vy * dt;
486
487 }
488
489 for (var i = 0; i < C.length; i++) { // dlya O2
490 // расчет взаимодействия производится со всеми следующими шарами в массиве,
491 // чтобы не считать каждое взаимодействие дважды
492
493 var b = O2[i];
494
495 for (var j = i + 1; j < O2.length; j++) {
496 var b2 = O2[j];
497 var rx = b.x - b2.x; var ry = b.y - b2.y; // вектор смотрит на первый шар (b)
498 var r2 = rx * rx + ry * ry; // квадрат расстояния между шарами
499
500 if ( r2 > aCut2) continue ;
501
502 powers(b,b2,a_1, 0.3) ;
503
504 }
505
506 if (b == dNd) continue; // если шар схвачен курсором - его вз. со стенами и перемещение не считаем
507
508 if (b.y + r > h) { b.fy += -Cwall * (b.y + r - h) - Bwall * b.vy; }
509 if (b.y - r < 0) { b.fy += -Cwall * (b.y - r) - Bwall * b.vy;}
510 if (b.x + r > w) { b.fx += -Cwall * (b.x + r - w) - Bwall * b.vx; }
511 if (b.x - r < 0) { b.fx += -Cwall * (b.x - r) - Bwall * b.vx; }
512
513 b.vx += b.fx / m * dt; b.vy += b.fy / m * dt;
514 b.x += b.vx * dt; b.y += b.vy * dt;
515
516 }
517 }
518 }
519
520 // Рисование
521
522 var rScale13 = r * scale * 1.3; // ___в целях оптимизации___
523 var rScaleShift = r * scale / 5; // ___в целях оптимизации___
524 function draw() {
525 context.clearRect(0, 0, w * scale, h * scale); // очистить экран
526 for (var i = 0; i < balls.length; i++){
527 var xS = balls[i].x * scale; var yS = balls[i].y * scale;
528
529 context.fillStyle = "#FFD700";
530
531 context.beginPath();
532 context.arc(xS, yS, r * scale, 0, 2 * Math.PI, false);
533 context.closePath();
534 context.fill();
535 }
536
537 for (var i = 0; i < C.length; i++){
538 var xS = C[i].x * scale; var yS = C[i].y * scale;
539
540 context.fillStyle = "#f08080";
541
542 context.beginPath();
543 context.arc(xS, yS, r * scale, 0, 2 * Math.PI, false);
544 context.closePath();
545 context.fill();
546 }
547 for (var i = 0; i < O1.length; i++){
548 var xS = O1[i].x * scale; var yS = O1[i].y * scale;
549
550 context.fillStyle = "#3070d0";
551
552 context.beginPath();
553 context.arc(xS, yS, r * scale, 0, 2 * Math.PI, false);
554 context.closePath();
555 context.fill();
556 }
557 for (var i = 0; i < O2.length; i++){
558 var xS = O2[i].x * scale; var yS = O2[i].y * scale;
559
560 context.fillStyle = "#3070d0";
561
562 context.beginPath();
563 context.arc(xS, yS, r * scale, 0, 2 * Math.PI, false);
564 context.closePath();
565 context.fill();
566 }
567 }
568
569 // Запуск системы
570 for (var i = 0; i < 8; i++){ // добавляем 20 частиц, сдвинув их от стен
571 //addNewBall(Math.random() * (w - 2 * r) + r, Math.random() * (h - 2 * r) + r , 10 );
572 addNewC(Math.random() * (w - 2 * r) + r, Math.random() * (h - 2 * r) + r , 10 );
573 addNewO1(Math.random() * (w - 2 * r) + r, Math.random() * (h - 2 * r) + r , 10 );
574 addNewO2(Math.random() * (w - 2 * r) + r, Math.random() * (h - 2 * r) + r , 10 );
575
576 }
577 setInterval(control, 1000 / fps);
578 }
Обсуждение результатов и выводы[править]
Разработан алгоритм, с помощью которого можно смоделировать молекулу углекислого газа при помощи парных потенциалов. Данная модель имеет свои особенности:
- За конечное время при небольшой вязкости среды частицы собираются в молекулы углекислого газа.
- Поведение молекулы углекислого газа в системе при небольших скоростях получается реалистичным. Это означает, что можно изучать динамику системы при малых скоростях молекул.
- При больших скоростях молекулы углекислого газа разрушаются. После разрушения они собираются заново, образуя те же самые молекулы.
В будущем планируется ввести степени насыщенности связи и начать моделировать более сложные молекулы.
Скачать презентацию: Молекула углекислого газа в среде инертного газа
Скачать отчет:Файл:SmirnovKurs.docx