КП: Разрушение нанокластера — различия между версиями

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск
 
(не показано 12 промежуточных версий этого же участника)
Строка 50: Строка 50:
  
 
{{#widget:Iframe |url=http://tm.spbstu.ru/htmlets/Vorobev/Nano_kl.html |width=830 |height=830 |border=0 }}
 
{{#widget:Iframe |url=http://tm.spbstu.ru/htmlets/Vorobev/Nano_kl.html |width=830 |height=830 |border=0 }}
 +
<div class="mw-collapsible mw-collapsed">
 +
 +
'''Текст программы на языке JavaScript:''' <div class="mw-collapsible-content">
 +
Файл '''"Nano_kl.js"'''
 +
<syntaxhighlight lang="javascript" line start="1" enclose="div">
 +
function MainBalls(canvas, slider_01, text_01, slider_02, text_02) {
 +
 +
    canvas.onselectstart = function () {return false;};    // запрет выделения canvas
 +
 +
    // Предварительные установки
 +
 +
    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 = 16;                        // число шаров, помещающихся по вертикали в окно (задает размер шара относительно размера окна)
 +
    var m = 1 * m0;                    // масса
 +
    var CWall = 10 * C0;                // жесткость стен
 +
    var CBall = 0.1 * CWall;            // жесткость между частицами
 +
    var BVisc = 0.008 * B0;            // вязкость среды
 +
    var BWall = 0.03 * B0;              // вязкость на стенках
 +
   
 +
    var r = 0.5 * a0;                  // радиус частицы в расчетных координатах
 +
    var K = 0.7;                        // все силы, зависящие от радиуса, ограничиваются значением, реализующимся при r/a = K
 +
    var a = 2 * r;                      // равновесное расстояние между частицами
 +
    var aCut = 2 * a;                  // радиус обрезания
 +
var alfa = 2;                    // коэффициент для хрупкого вз. Лен-Дж
 +
 +
    // *** Задание вычислительных параметров ***
 +
 +
    var fps = 60;                      // frames per second - число кадров в секунду (качечтво отображения)
 +
    var spf = 100;                      // steps per frame  - число шагов интегрирования между кадрами (скорость расчета)
 +
    var dt  = 0.04 * t0 / fps;          // шаг интегрирования (качество расчета)
 +
var mg = 0 * m * g0;            // сила тяжести
 +
 +
    // Выполнение программы
 +
var sqrt3 = Math.sqrt(3);
 +
    var r2 = r * r;                    // ___в целях оптимизации___
 +
    var a2 = a * a;                    // ___в целях оптимизации___
 +
    var D = a2 * CBall / 72;            // энергия связи между частицами
 +
    var LJCoeff = 12 * D / a2;          // коэффициент для расчета потенциала Л-Дж
 +
    var bet = Math.pow(13 / 7, 1/6) * a;    // коэффициент для SLJ потенциала
 +
    var bet2 = bet * bet;                    // ___в целях оптимизации___
 +
    var SLJDenominator = 1 / (aCut * aCut - bet2);    // знаменатель для расчета SLJ потенциала
 +
var sqrtkoef = Math.sqrt(alfa/(1+alfa));  //___в целях оптимизации___
 +
 +
    var Ka = K * a;                    // ___в целях оптимизации___
 +
    var K2a2 = K * K * a2;              // ___в целях оптимизации___
 +
 +
    var dNd = null;                    // ссылка на захваченный курсором шар (drag & drop)
 +
    var SLJEnabled = document.getElementById('checkbox_01').checked;
 +
 +
    this.setSlider_01 = function(c) {mg = c * m * g0;}; // функция для слайдера гравитации;
 +
    this.setCheckbox_01 = function(bool) {SLJEnabled = bool;};
 +
this.setCheckbox_01(SLJEnabled);
 +
 +
    // Настройка интерфейса
 +
 +
    slider_01.min = 0;              slider_01.max = 5;
 +
    slider_01.step = 0.05;
 +
    slider_01.value = mg / m / g0;          // начальное значение ползунка должно задаваться после min и max
 +
    text_01.value = mg / m / g0;
 +
 +
    // Запуск новой системы
 +
 +
    // следующие переменные должны пересчитываться каждый раз, когда мы изменяем значение Ny
 +
    var scale, w, h;
 +
    var rScale13, rScaleShift;
 +
    this.newSystem = function() {
 +
        scale = canvas.height / Ny / a0;    // масштабный коэффициент для перехода от расчетных к экранным координатам
 +
        w = canvas.width / scale;          // ширина окна в расчетных координатах
 +
        h = canvas.height / scale;          // высота окна в расчетных координатах
 +
 +
        rScale13 = r * scale * 1.3;        // ___в целях оптимизации___
 +
        rScaleShift = r * scale / 5;        // ___в целях оптимизации___
 +
 +
        this.setTriangularLattice(5);                  // сразу создаем конфигурацию
 +
    };
 +
 +
    // Работа с мышью
 +
 +
    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;
 +
            }
 +
        }
 +
 +
        // если не вышли по return из цикла - нажатие было вне шара, добавляем новый
 +
        if (e.which == 1) {
 +
            dNd = addNewBall(m.x, m.y, true);  // добавляем шар и сразу захватываем его курсором
 +
            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 addNewBall =  function(x, y, check) {
 +
        // проверка - не пересекается ли новый шар со стенами или уже существующими шарами
 +
        if (check) {
 +
            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;
 +
    };
 +
 +
 +
 +
/*    this.setRose = function() {balls = [];      //розочка
 +
addNewBall(w/2, h/8);
 +
for (var i = 0; i< 5*Math.PI/3; i+= Math.PI/3){
 +
addNewBall(w/2+a*Math.cos(i), h/8+a*Math.sin(i));
 +
}
 +
};
 +
 +
    this.setQuad = function() {              // квадратная конфигурация
 +
        balls = [];
 +
        for (var i = 1; i < 4; i++)
 +
for(var j = 1; j < 4; j++)
 +
addNewBall(i *(a0)+7*w/16, j * (a0));
 +
    }; */
 +
 +
    this.setTriangularLattice = function(lat) {            // задать на поле треугольную решетку
 +
        balls = [];
 +
        for (var j = 0; j < Math.floor(lat / (sqrt3 * r)); j++)
 +
        for (var j = 0; j < Math.floor(lat / (sqrt3 * r)); j++)
 +
            for (var i = 0; i < Math.floor(lat / r)-1; i++)
 +
                if ((i + j) % 2 == 0) addNewBall(r * (i + 1) +3.2*w/8, r * (1 + sqrt3 * j), false);
 +
    };
 +
 +
this.setEmpty = function() {balls = [];};
 +
 +
    // Основной цикл программы
 +
 +
    function control() {
 +
        physics();
 +
        draw();
 +
    }
 +
 +
    // Расчетная часть программы
 +
 +
    function physics() {                            // то, что происходит каждый шаг времени
 +
        for (var s = 1; s <= spf; s++) {
 +
 +
            var BViscTh = BVisc;
 +
            // пересчет сил идет отдельным массивом, т.к. далее будут добавляться силы взаимодействия между шарами
 +
            for (var i0 = 0; i0 < balls.length; i0++) {
 +
                balls[i0].fx = - BViscTh * balls[i0].vx;
 +
                balls[i0].fy = mg - BViscTh * balls[i0].vy;
 +
            }
 +
 +
            for (var i = 0; i < balls.length; i++) {
 +
                // расчет взаимодействия производится со всеми следующими шарами в массиве,
 +
                // чтобы не считать каждое взаимодействие дважды
 +
                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;                        // квадрат расстояния между шарами
 +
                    var rLen = (Math.sqrt(r2));
 +
 +
 +
                    // сила взаимодействия
 +
                    var s2 = a2 / r2;        var s4 = s2 * s2;        // ___в целях оптимизации___
 +
                    var F = LJCoeff * s4 * s4 * (s4 * s2 - 1);          // сила взаимодействия Леннарда-Джонса
 +
                    if (SLJEnabled) {
 +
 +
                        var kSLJ;                                          // k(r) - сглаживающий коэффициент SLJ потенциала
 +
                        if (rLen <= bet) kSLJ = 1;
 +
 +
                        if (rLen <= aCut && rLen > bet) {
 +
                            var brackets = (r2 - bet2) * SLJDenominator;
 +
var brackets2=((1-(1+sqrtkoef)*brackets*brackets))*((1-(1+sqrtkoef)*brackets*brackets));
 +
                            kSLJ = (1+alfa)*(brackets2)-alfa;
 +
 +
                        }                                                 
 +
if (rLen >=aCut) {
 +
kSLJ=0;
 +
}
 +
                        F *= kSLJ;
 +
                    }
 +
 +
                    // суммируем силы
 +
                    var Fx = F * rx;        var Fy = F * ry;
 +
 +
                    b.fx += Fx;            b.fy += Fy;
 +
                    b2.fx -= Fx;            b2.fy -= Fy;
 +
                }
 +
 +
                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;
 +
            }
 +
        }
 +
    }
 +
 +
    // Рисование
 +
context.fillStyle = "#3070d0";
 +
    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.beginPath();
 +
            context.arc(xS, yS, r * scale, 0, 2 * Math.PI, false);
 +
            context.closePath();
 +
            context.fill();
 +
        }
 +
    }
 +
 +
    // Запуск системы
 +
    this.newSystem();
 +
    setInterval(control, 1000 / fps);
 +
    // след. функция обновляет информацию о количестве частиц на поле
 +
    setInterval(function(){document.getElementById('ballsNum').innerHTML = balls.length;}, 1000 / 20);
 +
}
 +
 +
 +
 +
</syntaxhighlight>
 +
Файл '''"Nano_kl.html"'''
 +
<syntaxhighlight lang="javascript" line start="1" enclose="div">
 +
<!DOCTYPE html>
 +
<html>
 +
<head>
 +
    <meta charset="UTF-8" />
 +
    <title>Balls</title>
 +
    <script src="Nano_kl.js"></script>
 +
</head>
 +
<body>
 +
    <canvas id="canvasBalls" width="800" height="600" style="border:1px solid #000000;"></canvas>
 +
    <br>
 +
    <div>Гравитация:
 +
        <input type="range" id="slider_01" style="width: 150px;" oninput="app.setSlider_01(this.value); document.getElementById('text_01').value = this.value;">
 +
        mg =
 +
        <input id="text_01" style="width: 5ex;" required pattern="[-+]?([0-9]*\.[0-9]+|[0-9]+)" oninput="
 +
            // если введено не число - строка не пройдет валидацию по паттерну выше, и checkValidity() вернет false
 +
            if (!this.checkValidity()) return;
 +
            app.setSlider_01(this.value);
 +
            document.getElementById('slider_01').value = this.value;
 +
        ">
 +
    ⋅ m ⋅ g0</div><br>
 +
 +
    <div>Конфигурация:
 +
        <input type="button" name="" onclick="app.setTriangularLattice(5); return false;" value="Треугольная решетка[1]"/>
 +
        <input type="button" name="" onclick="app.setTriangularLattice(6); return false;" value="Треугольная решетка[2]"/>
 +
        <input type="button" name="" onclick="app.setTriangularLattice(8); return false;" value="Треугольная решетка[3]"/>
 +
    <input type="button" name="" onclick="app.setEmpty(); return false;" value="Пустое поле"/>
 +
    </div><br>
 +
 +
    <div>
 +
        <input type="checkbox" id="checkbox_01" name="" onchange="app.setCheckbox_01(this.checked);"/>
 +
        <a title="SLJ" class="mw-redirect">Хрупкое взаимодействие Леннарда-Джонса</a>
 +
    </div><br>
 +
 +
    <div>Количество частиц: <span id="ballsNum"></span></div>
 +
 +
    <script type="text/javascript">var app = new MainBalls(
 +
            document.getElementById('canvasBalls'),
 +
            document.getElementById('slider_01'),
 +
            document.getElementById('text_01')
 +
    );</script>
 +
</body>
 +
</html>
 +
</syntaxhighlight>
 +
</div>
  
 
== Обсуждение результатов и выводы ==
 
== Обсуждение результатов и выводы ==
  
Данная работа демонстрирует различия между хрупким и обычным потенциалом Леннард-Джонса. Видно, что при хрупком взаимодействии нанокластер не стремится вернуться в исходное состояние,благодаря коэффициенту, создающему дополнительные условия для отталкивания частиц, что, в свою очередь, отображает реальное поведение структуры после деформации.
+
Данная работа демонстрирует различия между хрупким и обычным потенциалами Леннард-Джонса. Видно, что при хрупком взаимодействии нанокластер фрагментируется, а при обычном взаимодействии наблюдается пластическая деформация.
 
<br>
 
<br>
Пзентация:  [[ Медиа: Разрушение_нанокластера.ppt|скачать]]
+
Презентация:  [[ Медиа: Разрушение_нанокластера1.ppt|скачать]]<br>
 +
Отчет: [[ Медиа: Krsach_V.doc|скачать]]
  
 
== Ссылки по теме ==
 
== Ссылки по теме ==

Текущая версия на 21:11, 15 июня 2015

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


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

Исполнитель: Воробьёв Сергей

Группа: 09 (23604)

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

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

Данный проект посвящен изучению деформации структуры нанокластера при соударении с твердой поверхностью под действием силы тяжести.

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

Написать программу, отображающую поведение нанокластера под действием силы.

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


Nanoclaster.png [[1]]
Нанокластер — частица, состоящая из десятков, сотен или тысяч атомов, которая может рассматриваться как самостоятельная единица, обладающая определенными свойствами.

Потенциал Леннард-Джонса (потенциал 6-12) — простая модель парного взаимодействия неполярных молекул, описывающая зависимость энергии взаимодействия двух частиц от расстояния между ними. Эта модель достаточно реалистично передаёт свойства реального взаимодействия сферических неполярных молекул и поэтому широко используется в расчётах и при компьютерном моделировании. Впервые этот вид потенциала был предложен Леннард-Джонсом в 1924 году.

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

За основу взят код Balls_v6
1. Создание структуры, имитирующей нанокластер.
2. Взаимодействие между молекулами описывается потенциалом Леннард-Джонса:
[math] \varPi(r) = D\left[\left(\frac{a}{r}\right)^{12}-2\left(\frac{a}{r}\right)^{6}\right], [/math]
[math] F_{LJ}(r) = \frac{12D}{a}\left[\left(\frac{a}{r}\right)^{13} - \left(\frac{a}{r}\right)^{7}\right] [/math] — сила Леннард-Джонса


или хрупким взаимодействием Леннард-Джонса:
[math] F(r) = k(r)F_{LJ}(r)[/math], где [math]k(r)[/math] — коэффициент формы:
[math] k(r) = \left\{ \begin{array}{ll} 1, \qquad & r\le b; \\ \displaystyle (1+\alpha)\left(1-\left(1+\sqrt{\frac{\alpha}{1+\alpha}}\,\right)\left(\frac{r^2-b^2}{a_{\rm cut}^2-b^2}\right)^2\right)^2 - \alpha, \qquad & b\lt r\le a_{\rm cut}; \\ 0, \qquad & r \gt a_{\rm cut}; \\ \end{array} \right. [/math]
Здесь [math]b = \sqrt[6]{\frac{13}7}\,a[/math] — расстояние, на котором реализуется минимальное значение силы Леннард-Джонса (расстояние разрыва связи), [math]a_{\rm cut}[/math] — радиус обрезания взаимодействия, [math]\alpha[/math] — положительный параметр, определяющий хрупкость взаимодействия.

3. Деформирование структуры нанокластера с помощью силы тяжести.

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

Файл "Nano_kl.js"

  1 function MainBalls(canvas, slider_01, text_01, slider_02, text_02) {
  2 
  3     canvas.onselectstart = function () {return false;};     // запрет выделения canvas
  4 
  5     // Предварительные установки
  6 
  7     var context = canvas.getContext("2d");                  // на context происходит рисование
  8     canvas.oncontextmenu = function (e) {return false;};    // блокировка контекстного меню
  9 
 10     var Pi = 3.1415926;                 // число "пи"
 11 
 12     var m0 = 1;                         // масштаб массы
 13     var t0 = 1;                         // масштаб времени (период колебаний исходной системы)
 14     var a0 = 1;                         // масштаб расстояния (диаметр шара)
 15 
 16     var g0 = a0 / t0 / t0;              // масштаб ускорения (ускорение, при котором за t0 будет пройдено расстояние a0)
 17     var k0 = 2 * Pi / t0;               // масштаб частоты
 18     var C0 = m0 * k0 * k0;              // масштаб жесткости
 19     var B0 = 2 * m0 * k0;               // масштаб вязкости
 20 
 21     // *** Задание физических параметров ***
 22 
 23     var Ny = 16;                         // число шаров, помещающихся по вертикали в окно (задает размер шара относительно размера окна)
 24     var m = 1 * m0;                     // масса
 25     var CWall = 10 * C0;                // жесткость стен
 26     var CBall = 0.1 * CWall;            // жесткость между частицами
 27     var BVisc = 0.008 * B0;             // вязкость среды
 28     var BWall = 0.03 * B0;              // вязкость на стенках
 29     
 30     var r = 0.5 * a0;                   // радиус частицы в расчетных координатах
 31     var K = 0.7;                        // все силы, зависящие от радиуса, ограничиваются значением, реализующимся при r/a = K
 32     var a = 2 * r;                      // равновесное расстояние между частицами
 33     var aCut = 2 * a;                   // радиус обрезания
 34 	var alfa = 2;                     // коэффициент для хрупкого вз. Лен-Дж
 35 
 36     // *** Задание вычислительных параметров ***
 37 
 38     var fps = 60;                       // frames per second - число кадров в секунду (качечтво отображения)
 39     var spf = 100;                      // steps per frame   - число шагов интегрирования между кадрами (скорость расчета)
 40     var dt  = 0.04 * t0 / fps;          // шаг интегрирования (качество расчета)
 41 	var mg = 0 * m * g0;             // сила тяжести
 42 
 43     // Выполнение программы
 44 	var sqrt3 = Math.sqrt(3);
 45     var r2 = r * r;                     // ___в целях оптимизации___
 46     var a2 = a * a;                     // ___в целях оптимизации___
 47     var D = a2 * CBall / 72;            // энергия связи между частицами
 48     var LJCoeff = 12 * D / a2;          // коэффициент для расчета потенциала Л-Дж
 49     var bet = Math.pow(13 / 7, 1/6) * a;    // коэффициент для SLJ потенциала
 50     var bet2 = bet * bet;                     // ___в целях оптимизации___
 51     var SLJDenominator = 1 / (aCut * aCut - bet2);    // знаменатель для расчета SLJ потенциала
 52 	var sqrtkoef = Math.sqrt(alfa/(1+alfa));  //___в целях оптимизации___
 53 
 54     var Ka = K * a;                     // ___в целях оптимизации___
 55     var K2a2 = K * K * a2;              // ___в целях оптимизации___
 56 
 57     var dNd = null;                     // ссылка на захваченный курсором шар (drag & drop)
 58     var SLJEnabled = document.getElementById('checkbox_01').checked;
 59 
 60     this.setSlider_01 = function(c) {mg = c * m * g0;}; // функция для слайдера гравитации; 
 61     this.setCheckbox_01 = function(bool) {SLJEnabled = bool;};
 62 	this.setCheckbox_01(SLJEnabled);
 63 
 64     // Настройка интерфейса
 65 
 66     slider_01.min = 0;               slider_01.max = 5;
 67     slider_01.step = 0.05;
 68     slider_01.value = mg / m / g0;          // начальное значение ползунка должно задаваться после min и max
 69     text_01.value = mg / m / g0;
 70 
 71     // Запуск новой системы
 72 
 73     // следующие переменные должны пересчитываться каждый раз, когда мы изменяем значение Ny
 74     var scale, w, h;
 75     var rScale13, rScaleShift;
 76     this.newSystem = function() {
 77         scale = canvas.height / Ny / a0;    // масштабный коэффициент для перехода от расчетных к экранным координатам
 78         w = canvas.width / scale;           // ширина окна в расчетных координатах
 79         h = canvas.height / scale;          // высота окна в расчетных координатах
 80 
 81         rScale13 = r * scale * 1.3;         // ___в целях оптимизации___
 82         rScaleShift = r * scale / 5;        // ___в целях оптимизации___
 83 
 84         this.setTriangularLattice(5);                   // сразу создаем конфигурацию
 85     };
 86 
 87     // Работа с мышью
 88 
 89     var mx_, my_;                               // буфер позиции мыши (для расчета скорости при отпускании шара)
 90 
 91     canvas.onmousedown = function(e) {          // функция при нажатии клавиши мыши
 92         var m = mouseCoords(e);                 // получаем расчетные координаты курсора мыши
 93         // цикл в обратную сторону, чтобы захватывать шар, нарисованный "сверху"
 94         // (т.к. цикл рисования идет в обычном порядке)
 95         for (var i = balls.length - 1; i >= 0; i--) {
 96             var b = balls[i];
 97             var rx = b.x - m.x;
 98             var ry = b.y - m.y;
 99             var rLen2 = rx * rx + ry * ry;              // квадрат расстояния между курсором и центром шара
100             if (rLen2 <= r2) {                          // курсор нажал на шар
101                 if (e.which == 1) {                     // нажата левая клавиша мыши
102                     dNd = b;
103                     dNd.xPlus = dNd.x - m.x;            // сдвиг курсора относительно центра шара по x
104                     dNd.yPlus = dNd.y - m.y;            // сдвиг курсора относительно центра шара по y
105                     mx_ = m.x;    my_ = m.y;
106                     canvas.onmousemove = mouseMove;     // пока клавиша нажата - работает функция перемещения
107                 } else if (e.which == 3)                // нажата правая клавиша мыши
108                     balls.splice(i, 1);                 // удалить шар
109                 return;
110             }
111         }
112 
113         // если не вышли по return из цикла - нажатие было вне шара, добавляем новый
114         if (e.which == 1) {
115             dNd = addNewBall(m.x, m.y, true);   // добавляем шар и сразу захватываем его курсором
116             if (dNd == null) return;            // если шар не добавился (из за стен или других шаров) - возвращаемся
117             dNd.xPlus = 0;  dNd.yPlus = 0;      // держим шар по центру
118             mx_ = m.x;    my_ = m.y;
119             canvas.onmousemove = mouseMove;     // пока клавиша нажата - работает функция перемещения
120         }
121     };
122 
123     document.onmouseup = function(e) {          // функция при отпускании клавиши мыши
124         canvas.onmousemove = null;              // когда клавиша отпущена - функции перемещения нету
125         dNd = null;                             // когда клавиша отпущена - захваченного курсором шара нету
126     };
127 
128     function mouseMove(e) {                     // функция при перемещении мыши, работает только с зажатой ЛКМ
129         var m = mouseCoords(e);                 // получаем расчетные координаты курсора мыши
130         dNd.x = m.x + dNd.xPlus;
131         dNd.y = m.y + dNd.yPlus;
132         dNd.vx = 0.6 * (m.x - mx_) / dt / fps;   dNd.vy = 0.6 * (m.y - my_) / dt / fps;
133         mx_ = m.x;    my_ = m.y;
134     }
135 
136     function mouseCoords(e) {                   // функция возвращает расчетные координаты курсора мыши
137         var m = [];
138         var rect = canvas.getBoundingClientRect();
139         m.x = (e.clientX - rect.left) / scale;
140         m.y = (e.clientY - rect.top) / scale;
141         return m;
142     }
143 
144     // Работа с массивом
145 
146     var balls = [];                             // массив шаров
147     var addNewBall =  function(x, y, check) {
148         // проверка - не пересекается ли новый шар со стенами или уже существующими шарами
149         if (check) {
150             if (x - r < 0 || x + r > w || y - r < 0 || y + r > h) return null;
151             for (var i = 0; i < balls.length; i++) {
152                 var rx = balls[i].x - x;
153                 var ry = balls[i].y - y;
154                 var rLen2 = rx * rx + ry * ry;
155                 if (rLen2 < 4 * r2) return null;
156             }
157         }
158 
159         var b = [];
160 
161         b.x = x;                b.y = y;        // расчетные координаты шара
162         b.fx = 0;               b.fy = mg;      // сила, действующая на шар
163         b.vx = 0;               b.vy = 0;       // скорость
164 
165         balls[balls.length] = b;                // добавить элемент в конец массива
166         return b;
167     };
168 	
169 
170 	
171 /*     this.setRose = function() {balls = [];       //розочка
172 		addNewBall(w/2, h/8);
173 			for (var i = 0; i< 5*Math.PI/3; i+= Math.PI/3){
174 				addNewBall(w/2+a*Math.cos(i), h/8+a*Math.sin(i)); 
175 			}
176 	}; 
177 
178     this.setQuad = function() {               // квадратная конфигурация
179         balls = [];
180         for (var i = 1; i < 4; i++)
181 			for(var j = 1; j < 4; j++)
182 				addNewBall(i *(a0)+7*w/16, j * (a0));
183     }; */
184 	
185     this.setTriangularLattice = function(lat) {            // задать на поле треугольную решетку
186         balls = [];
187         for (var j = 0; j < Math.floor(lat / (sqrt3 * r)); j++)
188         for (var j = 0; j < Math.floor(lat / (sqrt3 * r)); j++)
189             for (var i = 0; i < Math.floor(lat / r)-1; i++)
190                 if ((i + j) % 2 == 0) addNewBall(r * (i + 1) +3.2*w/8, r * (1 + sqrt3 * j), false);
191     };
192 	
193 	this.setEmpty = function() {balls = [];};
194 
195     // Основной цикл программы
196 
197     function control() {
198         physics();
199         draw();
200     }
201 
202     // Расчетная часть программы
203 
204     function physics() {                            // то, что происходит каждый шаг времени
205         for (var s = 1; s <= spf; s++) {
206 
207             var BViscTh = BVisc;
208             // пересчет сил идет отдельным массивом, т.к. далее будут добавляться силы взаимодействия между шарами
209             for (var i0 = 0; i0 < balls.length; i0++) {
210                 balls[i0].fx = - BViscTh * balls[i0].vx;
211                 balls[i0].fy = mg - BViscTh * balls[i0].vy;
212             }
213 
214             for (var i = 0; i < balls.length; i++) {
215                 // расчет взаимодействия производится со всеми следующими шарами в массиве,
216                 // чтобы не считать каждое взаимодействие дважды
217                 var b = balls[i];
218                 for (var j = i + 1; j < balls.length; j++) {
219                     var b2 = balls[j];
220                     var rx = b.x - b2.x;   var ry = b.y - b2.y;         // вектор смотрит на первый шар (b)
221                     var r2 = rx * rx + ry * ry;                         // квадрат расстояния между шарами
222                     var rLen = (Math.sqrt(r2));
223 
224 
225                     // сила взаимодействия
226                     var s2 = a2 / r2;         var s4 = s2 * s2;         // ___в целях оптимизации___
227                     var F = LJCoeff * s4 * s4 * (s4 * s2 - 1);          // сила взаимодействия Леннарда-Джонса
228                     if (SLJEnabled) {
229 					
230                         var kSLJ;                                           // k(r) - сглаживающий коэффициент SLJ потенциала
231                         if (rLen <= bet) kSLJ = 1;
232 						
233                         if (rLen <= aCut && rLen > bet) {
234                             var brackets = (r2 - bet2) * SLJDenominator;
235 							var brackets2=((1-(1+sqrtkoef)*brackets*brackets))*((1-(1+sqrtkoef)*brackets*brackets));
236                             kSLJ = (1+alfa)*(brackets2)-alfa;
237 							
238                         }                                                   
239 						if (rLen >=aCut) {
240 							kSLJ=0;
241 						}
242                         F *= kSLJ;
243                     }
244 
245                     // суммируем силы
246                     var Fx = F * rx;        var Fy = F * ry;
247 
248                     b.fx += Fx;             b.fy += Fy;
249                     b2.fx -= Fx;            b2.fy -= Fy;
250                 }
251 
252                 if (b == dNd) continue;  // если шар схвачен курсором - его вз. со стенами и перемещение не считаем
253 
254                 if (b.y + r > h) { b.fy += -CWall * (b.y + r - h) - BWall * b.vy; }
255                 if (b.y - r < 0) { b.fy += -CWall * (b.y - r) - BWall * b.vy;}
256                 if (b.x + r > w) { b.fx += -CWall * (b.x + r - w) - BWall * b.vx; }
257                 if (b.x - r < 0) { b.fx += -CWall * (b.x - r) - BWall * b.vx; }
258 
259                 b.vx += b.fx / m * dt;        b.vy += b.fy / m * dt;
260                 b.x += b.vx * dt;             b.y += b.vy * dt;
261             }
262         }
263     }
264 
265     // Рисование
266 	context.fillStyle = "#3070d0";
267     function draw() {
268         context.clearRect(0, 0, w * scale, h * scale);      // очистить экран
269         for (var i = 0; i < balls.length; i++){
270             var xS = balls[i].x * scale;           var yS = balls[i].y * scale;
271             context.beginPath();
272             context.arc(xS, yS, r * scale, 0, 2 * Math.PI, false);
273             context.closePath();
274             context.fill();
275         }
276     }
277 
278     // Запуск системы
279     this.newSystem();
280     setInterval(control, 1000 / fps);
281     // след. функция обновляет информацию о количестве частиц на поле
282     setInterval(function(){document.getElementById('ballsNum').innerHTML = balls.length;}, 1000 / 20);
283 }

Файл "Nano_kl.html"

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta charset="UTF-8" />
 5     <title>Balls</title>
 6     <script src="Nano_kl.js"></script>
 7 </head>
 8 <body>
 9     <canvas id="canvasBalls" width="800" height="600" style="border:1px solid #000000;"></canvas>
10     <br>
11     <div>Гравитация:
12         <input type="range" id="slider_01" style="width: 150px;" oninput="app.setSlider_01(this.value); document.getElementById('text_01').value = this.value;">
13         mg =
14         <input id="text_01" style="width: 5ex;" required pattern="[-+]?([0-9]*\.[0-9]+|[0-9]+)" oninput="
15             // если введено не число - строка не пройдет валидацию по паттерну выше, и checkValidity() вернет false
16             if (!this.checkValidity()) return;
17             app.setSlider_01(this.value);
18             document.getElementById('slider_01').value = this.value;
19         ">
20       m  g0</div><br>
21 
22     <div>Конфигурация:
23         <input type="button" name="" onclick="app.setTriangularLattice(5); return false;" value="Треугольная решетка[1]"/>
24         <input type="button" name="" onclick="app.setTriangularLattice(6); return false;" value="Треугольная решетка[2]"/>
25         <input type="button" name="" onclick="app.setTriangularLattice(8); return false;" value="Треугольная решетка[3]"/>
26     <input type="button" name="" onclick="app.setEmpty(); return false;" value="Пустое поле"/>
27     </div><br>
28 
29     <div>
30         <input type="checkbox" id="checkbox_01" name="" onchange="app.setCheckbox_01(this.checked);"/>
31         <a title="SLJ" class="mw-redirect">Хрупкое взаимодействие Леннарда-Джонса</a> 
32     </div><br>
33 
34     <div>Количество частиц: <span id="ballsNum"></span></div>
35 
36     <script type="text/javascript">var app = new MainBalls(
37             document.getElementById('canvasBalls'),
38             document.getElementById('slider_01'),
39             document.getElementById('text_01')
40     );</script>
41 </body>
42 </html>

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

Данная работа демонстрирует различия между хрупким и обычным потенциалами Леннард-Джонса. Видно, что при хрупком взаимодействии нанокластер фрагментируется, а при обычном взаимодействии наблюдается пластическая деформация.
Презентация: скачать
Отчет: скачать

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

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