Испытания на разрыв и сжатие плоского тела — различия между версиями

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск
(Новая страница: « Курсовые работы 2016-2017 учебного года > '''Испытания на ра…»)
 
м (Описание)
 
(не показаны 3 промежуточные версии этого же участника)
Строка 10: Строка 10:
  
  
== Формулировка задачи ==
+
== Описание ==
  
 +
Проводятся эксперименты сжатия и растяжения плоского тела на примере [https://ru.wikipedia.org/wiki/Поликристалл поликристалла]. Поликристалл моделируется множеством материальных точек, разделённых на области с разной жёсткостью связи (используется потенциал Леннард-Джонса с конечным радиусом обрезания). На плоскости строится [https://ru.wikipedia.org/wiki/Диаграмма_Вороного диаграмма Вороного], каждая точка тела попадает в одну из областей и получает соответствующий коэффициент (различный для разных областей). При расчёте силы взаимодействия между двумя точками их коэффициенты складываются, получившиеся значение есть жёсткость связи в потенциале. Диаграмма напряжений строится вплоть до момента потери устойчивости.
  
== Общие сведения ==
+
В рамках эксперимента скорость деформации и ширина образца постоянны. Поликристалл может содержать до 17 областей. Уравнения динамики решаются с помощью метода интегрирования Верле.
 
 
  
 +
Решение задачи и визуализация написаны нa JavaScript, диаграмма Вороного получается POST запросом к серверу (расчёты производятся программой на C++ с помощью алгоритма Форчуна, парсер написан на PHP).
  
 
== Результат ==
 
== Результат ==
 
<center>
 
<center>
{{#widget:Iframe|url=https://ailurus.ru/stands/cern/?test=compression&regions=12&iframe|width=660|height=760|border=0}}
+
{{#widget:Iframe|url=https://ailurus.ru/stands/cern/?test=tensile&regions=12&iframe|width=660|height=760|border=0}}
  
 
<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>

Текущая версия на 23:41, 9 мая 2017

Курсовые работы 2016-2017 учебного года > Испытания на разрыв и сжатие плоского тела

Курсовой проект по Механике дискретных сред

Исполнитель: Старобинский Егор

Группа: 09 (43604/1)

Семестр: осень 2016


Описание[править]

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

В рамках эксперимента скорость деформации и ширина образца постоянны. Поликристалл может содержать до 17 областей. Уравнения динамики решаются с помощью метода интегрирования Верле.

Решение задачи и визуализация написаны нa JavaScript, диаграмма Вороного получается POST запросом к серверу (расчёты производятся программой на C++ с помощью алгоритма Форчуна, парсер написан на PHP).

Результат[править]

Страница полного решения


Исходный код для одной из конфиграций [JavaScript]:
  1 var points = [{'x': 591, 'y':474},
  2 {'x': 94, 'y':587},
  3 {'x': 200, 'y':540},
  4 {'x': 577, 'y':71},
  5 {'x': 415, 'y':584},
  6 {'x': 225, 'y':302},
  7 {'x': 93, 'y':154},
  8 {'x': 127, 'y':123},
  9 {'x': 209, 'y':313},
 10 {'x': 32, 'y':290}];
 11 var pressureSign = 1;
 12 var fragmentation = false;
 13 var animationSpeed = 40;
 14 var strainRate = 10;
 15   
 16 var integrator = VerletIntegrator;
 17 var t = 0;
 18 var dt = 0.005;
 19 var timeValue = document.getElementById('timeValue');
 20   
 21 var particleRadius = 6;
 22 var numberOfColumns = 29;
 23 var numberOfRows = 29;
 24 var cm = [ 0.754335746098413,
 25 0.8107304103877537,
 26 0.9306594025241637,
 27 0.9667586023289361,
 28 0.7504112576761824,
 29 0.828054551661692,
 30 0.9496843639510728,
 31 0.9562931712096583,
 32 0.8953204544716538,
 33 0.7549681403247804,
 34 0.892707460881279,
 35 0.7946054751314912,
 36 0.9651534693380119,
 37 0.9753409489560376,
 38 0.828824739204054,
 39 0.7564226662369037,
 40 0.8476944814390296];
 41 
 42 var colors = ["Turquoise",
 43 "Yellow",
 44 "YellowGreen",
 45 "Teal",
 46 "White",
 47 "BlueViolet",
 48 "Tomato",
 49 "Silver",
 50 "Gray",
 51 "Orange",
 52 "SpringGreen",
 53 "WhiteSmoke",
 54 "Linen",
 55 "PaleGreen",
 56 "FireBrick",
 57 "SlateGray",
 58 "Bisque"];
 59 
 60 function indexOfTheNearestPoint(x, y){
 61     var squareLength = [];
 62     for(var i = 0; i < points.length; ++i){
 63         squareLength[i] = Math.pow(points[i].x - x, 2) + Math.pow(points[i].y - y, 2); 
 64     }
 65     return squareLength.indexOf(Math.min.apply(null, squareLength));
 66 }
 67 var particles = [];
 68 
 69 var stepBetweenColumns = (canvas.width / numberOfColumns);
 70 var stepBetweenRows = stepBetweenColumns * Math.sin(Math.PI/3);
 71 numberOfRows = Math.ceil(canvas.width / stepBetweenRows);
 72 if(!(numberOfRows % 2)){
 73 	--numberOfRows;
 74 }
 75 canvas.height = numberOfRows * stepBetweenRows;
 76 var halfOfStepBetweenColumns = 0.5 * stepBetweenColumns;
 77 var halfOfStepBetweenRows = 0.5 * stepBetweenRows;
 78 
 79 for(var k = 0, l = 0; k < numberOfRows; ++k){
 80     if(k % 2){
 81         for(var i = 0, j = halfOfStepBetweenColumns; i < numberOfColumns - 1; ++i){
 82             var x = halfOfStepBetweenColumns + j;
 83             var y = halfOfStepBetweenRows + l;
 84             j += stepBetweenColumns;
 85           
 86             var index = indexOfTheNearestPoint(x, y);
 87             var particle = createVerletElement([x, y], null, 1, 'circle', [particleRadius], colors[index]);
 88             particle.c = cm[index]; 
 89             particles.push(particle);
 90         }
 91     }else{
 92         for(var i = 0, j = 0; i < numberOfColumns; ++i){
 93             var x = halfOfStepBetweenColumns + j;
 94             var y = halfOfStepBetweenRows + l;
 95             j += stepBetweenColumns;
 96           
 97             var index = indexOfTheNearestPoint(x, y);
 98             var particle = createVerletElement([x, y], null, 1, 'circle', [particleRadius], colors[index]);
 99             particle.c = cm[index]; 
100             particles.push(particle);
101         }
102     }
103     l += stepBetweenRows;
104 }
105 var helper2 = [];
106 for(var i = 0; i < particles.length; i += 2 * numberOfColumns - 1){
107 	helper2.push(i);
108   	helper2.push(i - 1 + numberOfColumns);
109   	helper2.push(i + numberOfColumns);
110   	helper2.push(i - 2 + 2 * numberOfColumns);
111 }
112 for(var i = 0; i < particles.length; ++i){
113 	if(helper2.indexOf(i) >= 0){
114 		particles[i].color = 'rgb(255, 200, 40)';
115 	}
116 }
117 function applyInitionalConditions(){
118     for(var i = 0; i < numberOfColumns; ++i){
119         particles[i].previousPosition.y = particles[i].position.y - strainRate * dt * pressureSign;
120         particles[particles.length - i - 1].previousPosition.y = particles[particles.length - i - 1].position.y + strainRate * dt * pressureSign;
121         particles[i].color = 'crimson';
122         particles[particles.length - i - 1].color = 'crimson';
123     }
124 }
125 applyInitionalConditions();
126 draw();
127 drawLine(460.258514, 276.798706, 600.000000, 271.944183,4, 'dodgerblue');
128 drawLine(410.950745, 381.721161, 547.375000, 600.000000,4, 'dodgerblue');
129 drawLine(254.635513, 600.000000, 254.635513, 600.000000,4, 'dodgerblue');
130 drawLine(0.000000, 451.651520, 89.154579, 433.040131,4, 'dodgerblue');
131 drawLine(0.000000, 193.966919, 127.067291, 250.960342,4, 'dodgerblue');
132 drawLine(0.000000, 17.854839, 176.980927, 211.962967,4, 'dodgerblue');
133 drawLine(340.791107, 0.000000, 354.080383, 115.003471,4, 'dodgerblue');
134 drawLine(333.749329, 433.736267, 299.723267, 600.000000,4, 'dodgerblue');
135 drawLine(89.154556, 433.040070, 163.183975, 600.000000,4, 'dodgerblue');
136 drawLine(333.749329, 433.736267, 410.950745, 381.721130,4, 'dodgerblue');
137 drawLine(301.455261, 430.344025, 333.749329, 433.736267,4, 'dodgerblue');
138 drawLine(89.154579, 433.040131, 104.770851, 422.545990,4, 'dodgerblue');
139 drawLine(460.258545, 276.798706, 410.950745, 381.721161,4, 'dodgerblue');
140 drawLine(161.072784, 226.151321, 301.455261, 430.344025,4, 'dodgerblue');
141 drawLine(104.770851, 422.545959, 301.455261, 430.344025,4, 'dodgerblue');
142 drawLine(127.067291, 250.960342, 104.770859, 422.545959,4, 'dodgerblue');
143 drawLine(354.080414, 115.003471, 460.258545, 276.798706,4, 'dodgerblue');
144 drawLine(127.067291, 250.960327, 161.072784, 226.151306,4, 'dodgerblue');
145 drawLine(176.980927, 211.962967, 354.080383, 115.003494,4, 'dodgerblue');
146 drawLine(161.072784, 226.151306, 176.980927, 211.962967,4, 'dodgerblue');
147 var textColor = 'rgb(255, 255, 255)';var D = 100;
148 if(-1 == pressureSign){
149 	D *= 100;
150 }
151 var a = stepBetweenColumns;//23.131737698273685;// 1*32;
152 var cutLength = 1.5 * canvas.height;//Math.sqrt(2130);
153 
154 var squareA = Math.pow(a, 2);
155 var squareCutLength = Math.pow(cutLength, 2);
156   
157 var diagramData = {'x': [], 'y': []};
158 var diagramCanvas = document.getElementById('diagram');
159 var stepFromBoard = 7;
160 var step = 0;
161   
162 function applyPhysics(){
163   	var forces = [];
164     for(var j = 0; j < particles.length; ++j){
165         var forceX = 0;
166         var forceY = 0;
167         for(var i = 0; i < particles.length; ++i){
168           	if(i == j){
169             	continue;
170             }
171             var diffX = particles[j].position.x - particles[i].position.x;
172             var diffY = particles[j].position.y - particles[i].position.y;
173             var squareDiff = Math.pow(diffX, 2) + Math.pow(diffY, 2);
174           	if(squareDiff > squareCutLength){
175 				fragmentation = true;
176             	continue;
177             }
178           
179             var tmp = squareA / squareDiff;
180           	var force = 0.5 * (particles[j].c + particles[i].c) * (12 * D / squareA) * (Math.pow(tmp, 7) - Math.pow(tmp, 4));
181           //-(particles[j].c + particles[i].c) * D * squareDiff / 100000;
182             forceX += force * diffX;
183             forceY += force * diffY;
184         }
185       	forces[j] = {'x': 0, 'y': forceY};
186     }
187   	var sigma = 0;
188   	for(var i = 0; i < numberOfColumns; ++i){
189       	sigma -= forces[i].y;// + forces[particles.length - i - 1].y;
190       	forces[i] = {'x': 0, 'y': 0};
191       	forces[particles.length - i - 1] = {'x': 0, 'y': 0};
192     }
193   	if(!fragmentation){
194 		var epsilon = pressureSign * (particles[1].position.y - halfOfStepBetweenRows) / (canvas.height - 2 * halfOfStepBetweenRows);
195       	diagramData.x.push(epsilon);
196       	diagramData.y.push(sigma / (numberOfColumns * 1));
197 		plotFromData(diagramCanvas, diagramData, 'Stress-deformation diagram', 'rgb(56, 195, 237)', 2, textColor); 
198   	}
199   	for(var j = 0; j < particles.length; ++ j){ 
200   		integrator(particles[j], forces[j], dt);
201 	}
202   	timeValue.textContent = t.toFixed(2);
203   	++step;
204 }
205 function draw(){
206     ctx.clearRect(0, 0, canvas.width, canvas.height);
207     for(var i = 0; i < particles.length; ++i){
208         particles[i].draw();
209     }
210 }
211 document.getElementById('play').onclick = function(){
212     this.className = 'inprogress';
213 	document.getElementById('conditions').className = 'hide';
214   	document.getElementById('diagram').className = '';
215     animate(animationSpeed);
216 }
217 document.getElementById('strainRate').onchange = function(){
218     document.getElementById('strainRateValue').textContent = (+this.value).toFixed(1);
219   	strainRate = (+this.value).toFixed(1);
220     applyInitionalConditions();
221 }
222 document.getElementById('animationSpeed').onchange = function(){
223     document.getElementById('animationSpeedValue').textContent = (+this.value).toFixed(0);
224     animationSpeed = (+this.value).toFixed(0);
225 }