КП: Молекула углекислого газа — различия между версиями

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск
(Решение)
 
(не показано 20 промежуточных версий 6 участников)
Строка 1: Строка 1:
[[А.М. Кривцов]] > [[Теоретическая механика: физико-механический факультет|Теоретическая механика]] > [[Курсовые проекты ТМ 2015]] > '''Молекула метана''' <HR>
+
[[А.М. Кривцов]] > [[Теоретическая механика: физико-механический факультет|Теоретическая механика]] > [[Курсовые проекты ТМ 2015]] > '''Молекула углекислого газа''' <HR>
  
  
Строка 11: Строка 11:
  
 
== Аннотация проекта ==
 
== Аннотация проекта ==
Моделирование молекул, даже самых простых - сложная задача. Для их моделирования необходимо использовать многочастичные потенциалы, но их поограммирование - тоже очень сложная задача. Встает вопрос о том, можло ли найти более простой путь моделирования простейших молекул.
+
Моделирование молекул, даже самых простых - сложная задача. Для их моделирования необходимо использовать многочастичные потенциалы, но их программирование - тоже очень сложная задача. Встает вопрос о том, можно ли найти более простой путь моделирования простейших молекул.
  
Для моделирования хорошо подходят парные потенциалы, ибо они имеют простой вид и легко программируются. Но как их применить к моделирования молекул ? Моя работа и посвещена решению данной проблемы.
+
Для моделирования хорошо подходят парные потенциалы, ибо они имеют простой вид и легко программируются. Но как их применить к моделированию молекул ? Моя работа и посвящена решению данной проблемы.
  
 
== Формулировка задачи ==
 
== Формулировка задачи ==
Смоделировать с помощью многочастичного потенциала молекулу углекислого газа ( 2D модель ) и рассмотреть ее простейшую динамику частицы.
+
Смоделировать с помощью многочастичного потенциала молекулу углекислого газа ( 2D модель ) и рассмотреть ее простейшую динамику молекулы.
  
 
== Общие сведения по теме ==
 
== Общие сведения по теме ==
Строка 85: Строка 85:
  
  
{{#widget:Iframe|url=http://cl49743.tmweb.ru/sites/Balls_v4_release.html |width=810|height:600|border=0}}
+
{{#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 Вторая версия (потенциал Морзе) ]
 
[http://cl49743.tmweb.ru/sites/Balls_v4_release.html Вторая версия (потенциал Морзе) ]
Строка 93: Строка 93:
 
* Правая кнопка мыши - удаление любого шара.
 
* Правая кнопка мыши - удаление любого шара.
 
* В системе теперь присутствует несколько молекул.
 
* В системе теперь присутствует несколько молекул.
 +
 +
 +
<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]]
 
Скачать презентацию: Молекула углекислого газа в среде инертного газа [[File:CO2engine.pdf]]
 +
<br>
 +
Скачать отчет:[[ File: SmirnovKurs.docx]]
  
 
== Ссылки по теме ==
 
== Ссылки по теме ==

Текущая версия на 23:05, 10 января 2017

А.М. Кривцов > Теоретическая механика > Курсовые проекты ТМ 2015 > Молекула углекислого газа


Курсовой проект по Теоретической механике

Исполнитель: Смирнов Александр

Группа: 09 (23604)

Семестр: весна 2015

Аннотация проекта[править]

Моделирование молекул, даже самых простых - сложная задача. Для их моделирования необходимо использовать многочастичные потенциалы, но их программирование - тоже очень сложная задача. Встает вопрос о том, можно ли найти более простой путь моделирования простейших молекул.

Для моделирования хорошо подходят парные потенциалы, ибо они имеют простой вид и легко программируются. Но как их применить к моделированию молекул ? Моя работа и посвящена решению данной проблемы.

Формулировка задачи[править]

Смоделировать с помощью многочастичного потенциала молекулу углекислого газа ( 2D модель ) и рассмотреть ее простейшую динамику молекулы.

Общие сведения по теме[править]

Для решения задачи будем использовать два потенциала: потенциал Морзе и потенциал Леннард-Джонса.

Потенциал Морзе [править]

Парный силовой потенциал взаимодействия. Определяется формулой:

[math] \varPi(r) = D\left[e^{-2\alpha(r-a)}-2e^{-\alpha(r-a)}\right], [/math]

где

  • [math]D[/math] — энергия связи,
  • [math]a[/math] — длина связи,
  • [math]\alpha[/math] — параметр, характеризующий ширину потенциальной ямы.

Потенциал имеет один безразмерный параметр [math]\alpha a [/math]. При [math]\alpha a = 6[/math] взаимодействия Морзе и Леннард-Джонса близки. При увеличении [math]\alpha a [/math] ширина потенциальной ямы для взаимодействия Морзе уменьшается, взаимодействие становится более жестким и хрупким. Уменьшение [math]\alpha a [/math] приводит к противоположным изменениям — потенциальная яма расширяется, жесткость падает. Сила, соответствующая потенциалу Морзе, вычисляется по формуле:

[math] F(r) = -\varPi'(r) = 2\alpha D\left[e^{-2\alpha(r-a)}-e^{-\alpha(r-a)}\right]. [/math]

Или в векторной форме:

[math] {\bf F}({\bf r})= -\nabla\varPi(r) = 2\alpha D\left[e^{-2\alpha(r-a)}-e^{-\alpha(r-a)}\right]\frac{{\bf r}}{r} [/math]
Потенциал Леннард-Джонса[править]

Также парный силовой потенциал взаимодействия. Определяется формулой:

[math] \varPi(r) = D\left[\left(\frac{a}{r}\right)^{12}-2\left(\frac{a}{r}\right)^{6}\right], [/math]

где

  • [math]r[/math] — расстояние между частицами,
  • [math]D[/math] — энергия связи,
  • [math]a[/math] — длина связи.

Сила взаимодействия, соответствующая потенциалу Леннард-Джонса, вычисляется по формуле

[math] F(r) = \frac{12D}{a}\left[\left(\frac{a}{r}\right)^{13} - \left(\frac{a}{r}\right)^{7}\right]. [/math]

Векторная сила взаимодействия определяется формулой

[math] {\bf F}({\bf r})= -\nabla\varPi(r) = \frac{12D}{a^2}\left[\left(\frac{a}{r}\right)^{14}-\left(\frac{a}{r}\right)^{8}\right]{\bf r} [/math]
Углекислый газ [править]

Углекислый газ ( диоксид углерода ) - газ без запаха и цвета. Молекула углекислого газа имеет линейное строение и ковалентные полярные связи, хотя сама молекула не является полярной. Дипольный момент = 0.

Решение[править]

Взяв за основу программу Balls v4, было получено:

  • программа, в которой можно рассмотреть динамику одной молекулы углекислого газа в другом газе ( например в азоте ).
  • 2 версии программы с различными потенциалами.
  • создание молекулы за конечное время.

Первая версия (потенциал Морзе)

  • Синий шар - кислород .
  • Коралловый шар - углерод .
  • Желтый шар - азот.


Вторая версия (потенциал Морзе)

  • Цвет шаров аналогичный.
  • Левая кнопка мыши - добавление желтой частицы.
  • Правая кнопка мыши - удаление любого шара.
  • В системе теперь присутствует несколько молекул.


Текст программы на языке JavaScript:

Файл 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 }

Обсуждение результатов и выводы[править]

Разработан алгоритм, с помощью которого можно смоделировать молекулу углекислого газа при помощи парных потенциалов. Данная модель имеет свои особенности:

  • За конечное время при небольшой вязкости среды частицы собираются в молекулы углекислого газа.
  • Поведение молекулы углекислого газа в системе при небольших скоростях получается реалистичным. Это означает, что можно изучать динамику системы при малых скоростях молекул.
  • При больших скоростях молекулы углекислого газа разрушаются. После разрушения они собираются заново, образуя те же самые молекулы.

В будущем планируется ввести степени насыщенности связи и начать моделировать более сложные молекулы.
Скачать презентацию: Молекула углекислого газа в среде инертного газа CO2engine.pdf
Скачать отчет:Файл:SmirnovKurs.docx

Ссылки по теме[править]

См. также[править]