Текущая версия |
Ваш текст |
Строка 10: |
Строка 10: |
| | | |
| | | |
− | == Описание == | + | == Формулировка задачи == |
| | | |
− | Проводятся эксперименты сжатия и растяжения плоского тела на примере [https://ru.wikipedia.org/wiki/Поликристалл поликристалла]. Поликристалл моделируется множеством материальных точек, разделённых на области с разной жёсткостью связи (используется потенциал Леннард-Джонса с конечным радиусом обрезания). На плоскости строится [https://ru.wikipedia.org/wiki/Диаграмма_Вороного диаграмма Вороного], каждая точка тела попадает в одну из областей и получает соответствующий коэффициент (различный для разных областей). При расчёте силы взаимодействия между двумя точками их коэффициенты складываются, получившиеся значение есть жёсткость связи в потенциале. Диаграмма напряжений строится вплоть до момента потери устойчивости.
| |
| | | |
− | В рамках эксперимента скорость деформации и ширина образца постоянны. Поликристалл может содержать до 17 областей. Уравнения динамики решаются с помощью метода интегрирования Верле.
| + | == Общие сведения == |
| + | |
| | | |
− | Решение задачи и визуализация написаны нa JavaScript, диаграмма Вороного получается POST запросом к серверу (расчёты производятся программой на C++ с помощью алгоритма Форчуна, парсер написан на PHP).
| |
| | | |
| == Результат == | | == Результат == |
Строка 24: |
Строка 23: |
| <big>[//ailurus.ru/stands/cern/ Страница полного решения]</big> | | <big>[//ailurus.ru/stands/cern/ Страница полного решения]</big> |
| </center> | | </center> |
− |
| |
− |
| |
− | <div class="mw-collapsible mw-collapsed">
| |
− | '''Исходный код для одной из конфиграций [JavaScript]:''' <div class="mw-collapsible-content">
| |
− | <syntaxhighlight lang="javascript" line start="1" enclose="div">
| |
− | var points = [{'x': 591, 'y':474},
| |
− | {'x': 94, 'y':587},
| |
− | {'x': 200, 'y':540},
| |
− | {'x': 577, 'y':71},
| |
− | {'x': 415, 'y':584},
| |
− | {'x': 225, 'y':302},
| |
− | {'x': 93, 'y':154},
| |
− | {'x': 127, 'y':123},
| |
− | {'x': 209, 'y':313},
| |
− | {'x': 32, 'y':290}];
| |
− | var pressureSign = 1;
| |
− | var fragmentation = false;
| |
− | var animationSpeed = 40;
| |
− | var strainRate = 10;
| |
− |
| |
− | var integrator = VerletIntegrator;
| |
− | var t = 0;
| |
− | var dt = 0.005;
| |
− | var timeValue = document.getElementById('timeValue');
| |
− |
| |
− | var particleRadius = 6;
| |
− | var numberOfColumns = 29;
| |
− | var numberOfRows = 29;
| |
− | var cm = [ 0.754335746098413,
| |
− | 0.8107304103877537,
| |
− | 0.9306594025241637,
| |
− | 0.9667586023289361,
| |
− | 0.7504112576761824,
| |
− | 0.828054551661692,
| |
− | 0.9496843639510728,
| |
− | 0.9562931712096583,
| |
− | 0.8953204544716538,
| |
− | 0.7549681403247804,
| |
− | 0.892707460881279,
| |
− | 0.7946054751314912,
| |
− | 0.9651534693380119,
| |
− | 0.9753409489560376,
| |
− | 0.828824739204054,
| |
− | 0.7564226662369037,
| |
− | 0.8476944814390296];
| |
− |
| |
− | var colors = ["Turquoise",
| |
− | "Yellow",
| |
− | "YellowGreen",
| |
− | "Teal",
| |
− | "White",
| |
− | "BlueViolet",
| |
− | "Tomato",
| |
− | "Silver",
| |
− | "Gray",
| |
− | "Orange",
| |
− | "SpringGreen",
| |
− | "WhiteSmoke",
| |
− | "Linen",
| |
− | "PaleGreen",
| |
− | "FireBrick",
| |
− | "SlateGray",
| |
− | "Bisque"];
| |
− |
| |
− | function indexOfTheNearestPoint(x, y){
| |
− | var squareLength = [];
| |
− | for(var i = 0; i < points.length; ++i){
| |
− | squareLength[i] = Math.pow(points[i].x - x, 2) + Math.pow(points[i].y - y, 2);
| |
− | }
| |
− | return squareLength.indexOf(Math.min.apply(null, squareLength));
| |
− | }
| |
− | var particles = [];
| |
− |
| |
− | var stepBetweenColumns = (canvas.width / numberOfColumns);
| |
− | var stepBetweenRows = stepBetweenColumns * Math.sin(Math.PI/3);
| |
− | numberOfRows = Math.ceil(canvas.width / stepBetweenRows);
| |
− | if(!(numberOfRows % 2)){
| |
− | --numberOfRows;
| |
− | }
| |
− | canvas.height = numberOfRows * stepBetweenRows;
| |
− | var halfOfStepBetweenColumns = 0.5 * stepBetweenColumns;
| |
− | var halfOfStepBetweenRows = 0.5 * stepBetweenRows;
| |
− |
| |
− | for(var k = 0, l = 0; k < numberOfRows; ++k){
| |
− | if(k % 2){
| |
− | for(var i = 0, j = halfOfStepBetweenColumns; i < numberOfColumns - 1; ++i){
| |
− | var x = halfOfStepBetweenColumns + j;
| |
− | var y = halfOfStepBetweenRows + l;
| |
− | j += stepBetweenColumns;
| |
− |
| |
− | var index = indexOfTheNearestPoint(x, y);
| |
− | var particle = createVerletElement([x, y], null, 1, 'circle', [particleRadius], colors[index]);
| |
− | particle.c = cm[index];
| |
− | particles.push(particle);
| |
− | }
| |
− | }else{
| |
− | for(var i = 0, j = 0; i < numberOfColumns; ++i){
| |
− | var x = halfOfStepBetweenColumns + j;
| |
− | var y = halfOfStepBetweenRows + l;
| |
− | j += stepBetweenColumns;
| |
− |
| |
− | var index = indexOfTheNearestPoint(x, y);
| |
− | var particle = createVerletElement([x, y], null, 1, 'circle', [particleRadius], colors[index]);
| |
− | particle.c = cm[index];
| |
− | particles.push(particle);
| |
− | }
| |
− | }
| |
− | l += stepBetweenRows;
| |
− | }
| |
− | var helper2 = [];
| |
− | for(var i = 0; i < particles.length; i += 2 * numberOfColumns - 1){
| |
− | helper2.push(i);
| |
− | helper2.push(i - 1 + numberOfColumns);
| |
− | helper2.push(i + numberOfColumns);
| |
− | helper2.push(i - 2 + 2 * numberOfColumns);
| |
− | }
| |
− | for(var i = 0; i < particles.length; ++i){
| |
− | if(helper2.indexOf(i) >= 0){
| |
− | particles[i].color = 'rgb(255, 200, 40)';
| |
− | }
| |
− | }
| |
− | function applyInitionalConditions(){
| |
− | for(var i = 0; i < numberOfColumns; ++i){
| |
− | particles[i].previousPosition.y = particles[i].position.y - strainRate * dt * pressureSign;
| |
− | particles[particles.length - i - 1].previousPosition.y = particles[particles.length - i - 1].position.y + strainRate * dt * pressureSign;
| |
− | particles[i].color = 'crimson';
| |
− | particles[particles.length - i - 1].color = 'crimson';
| |
− | }
| |
− | }
| |
− | applyInitionalConditions();
| |
− | draw();
| |
− | drawLine(460.258514, 276.798706, 600.000000, 271.944183,4, 'dodgerblue');
| |
− | drawLine(410.950745, 381.721161, 547.375000, 600.000000,4, 'dodgerblue');
| |
− | drawLine(254.635513, 600.000000, 254.635513, 600.000000,4, 'dodgerblue');
| |
− | drawLine(0.000000, 451.651520, 89.154579, 433.040131,4, 'dodgerblue');
| |
− | drawLine(0.000000, 193.966919, 127.067291, 250.960342,4, 'dodgerblue');
| |
− | drawLine(0.000000, 17.854839, 176.980927, 211.962967,4, 'dodgerblue');
| |
− | drawLine(340.791107, 0.000000, 354.080383, 115.003471,4, 'dodgerblue');
| |
− | drawLine(333.749329, 433.736267, 299.723267, 600.000000,4, 'dodgerblue');
| |
− | drawLine(89.154556, 433.040070, 163.183975, 600.000000,4, 'dodgerblue');
| |
− | drawLine(333.749329, 433.736267, 410.950745, 381.721130,4, 'dodgerblue');
| |
− | drawLine(301.455261, 430.344025, 333.749329, 433.736267,4, 'dodgerblue');
| |
− | drawLine(89.154579, 433.040131, 104.770851, 422.545990,4, 'dodgerblue');
| |
− | drawLine(460.258545, 276.798706, 410.950745, 381.721161,4, 'dodgerblue');
| |
− | drawLine(161.072784, 226.151321, 301.455261, 430.344025,4, 'dodgerblue');
| |
− | drawLine(104.770851, 422.545959, 301.455261, 430.344025,4, 'dodgerblue');
| |
− | drawLine(127.067291, 250.960342, 104.770859, 422.545959,4, 'dodgerblue');
| |
− | drawLine(354.080414, 115.003471, 460.258545, 276.798706,4, 'dodgerblue');
| |
− | drawLine(127.067291, 250.960327, 161.072784, 226.151306,4, 'dodgerblue');
| |
− | drawLine(176.980927, 211.962967, 354.080383, 115.003494,4, 'dodgerblue');
| |
− | drawLine(161.072784, 226.151306, 176.980927, 211.962967,4, 'dodgerblue');
| |
− | var textColor = 'rgb(255, 255, 255)';var D = 100;
| |
− | if(-1 == pressureSign){
| |
− | D *= 100;
| |
− | }
| |
− | var a = stepBetweenColumns;//23.131737698273685;// 1*32;
| |
− | var cutLength = 1.5 * canvas.height;//Math.sqrt(2130);
| |
− |
| |
− | var squareA = Math.pow(a, 2);
| |
− | var squareCutLength = Math.pow(cutLength, 2);
| |
− |
| |
− | var diagramData = {'x': [], 'y': []};
| |
− | var diagramCanvas = document.getElementById('diagram');
| |
− | var stepFromBoard = 7;
| |
− | var step = 0;
| |
− |
| |
− | function applyPhysics(){
| |
− | var forces = [];
| |
− | for(var j = 0; j < particles.length; ++j){
| |
− | var forceX = 0;
| |
− | var forceY = 0;
| |
− | for(var i = 0; i < particles.length; ++i){
| |
− | if(i == j){
| |
− | continue;
| |
− | }
| |
− | var diffX = particles[j].position.x - particles[i].position.x;
| |
− | var diffY = particles[j].position.y - particles[i].position.y;
| |
− | var squareDiff = Math.pow(diffX, 2) + Math.pow(diffY, 2);
| |
− | if(squareDiff > squareCutLength){
| |
− | fragmentation = true;
| |
− | continue;
| |
− | }
| |
− |
| |
− | var tmp = squareA / squareDiff;
| |
− | var force = 0.5 * (particles[j].c + particles[i].c) * (12 * D / squareA) * (Math.pow(tmp, 7) - Math.pow(tmp, 4));
| |
− | //-(particles[j].c + particles[i].c) * D * squareDiff / 100000;
| |
− | forceX += force * diffX;
| |
− | forceY += force * diffY;
| |
− | }
| |
− | forces[j] = {'x': 0, 'y': forceY};
| |
− | }
| |
− | var sigma = 0;
| |
− | for(var i = 0; i < numberOfColumns; ++i){
| |
− | sigma -= forces[i].y;// + forces[particles.length - i - 1].y;
| |
− | forces[i] = {'x': 0, 'y': 0};
| |
− | forces[particles.length - i - 1] = {'x': 0, 'y': 0};
| |
− | }
| |
− | if(!fragmentation){
| |
− | var epsilon = pressureSign * (particles[1].position.y - halfOfStepBetweenRows) / (canvas.height - 2 * halfOfStepBetweenRows);
| |
− | diagramData.x.push(epsilon);
| |
− | diagramData.y.push(sigma / (numberOfColumns * 1));
| |
− | plotFromData(diagramCanvas, diagramData, 'Stress-deformation diagram', 'rgb(56, 195, 237)', 2, textColor);
| |
− | }
| |
− | for(var j = 0; j < particles.length; ++ j){
| |
− | integrator(particles[j], forces[j], dt);
| |
− | }
| |
− | timeValue.textContent = t.toFixed(2);
| |
− | ++step;
| |
− | }
| |
− | function draw(){
| |
− | ctx.clearRect(0, 0, canvas.width, canvas.height);
| |
− | for(var i = 0; i < particles.length; ++i){
| |
− | particles[i].draw();
| |
− | }
| |
− | }
| |
− | document.getElementById('play').onclick = function(){
| |
− | this.className = 'inprogress';
| |
− | document.getElementById('conditions').className = 'hide';
| |
− | document.getElementById('diagram').className = '';
| |
− | animate(animationSpeed);
| |
− | }
| |
− | document.getElementById('strainRate').onchange = function(){
| |
− | document.getElementById('strainRateValue').textContent = (+this.value).toFixed(1);
| |
− | strainRate = (+this.value).toFixed(1);
| |
− | applyInitionalConditions();
| |
− | }
| |
− | document.getElementById('animationSpeed').onchange = function(){
| |
− | document.getElementById('animationSpeedValue').textContent = (+this.value).toFixed(0);
| |
− | animationSpeed = (+this.value).toFixed(0);
| |
− | }
| |
− | </syntaxhighlight>
| |
− | </div>
| |
− | </div>
| |