線形弾性体の応力(ヤング率・ポアソン比)
応力とは外部からの力に対して弾性体に生じる力だよ。3次元弾性体中の任意の微小体積表面の法線ベクトルを$${\boldsymbol{n}}$$として、応力ベクトル$${\boldsymbol{p}}$$は
$$
\boldsymbol{p}= P\,\boldsymbol{n}
$$
と表されるよ。$${P}$$は応力テンソルと呼ばれ
$$
P=\left( \begin{matrix} P_{xx} &P_{xy} &P_{xz} \cr P_{yx} &P_{yy} &P_{yz} \cr P_{zx} &P_{zy} &P_{zz} \end{matrix} \right)
$$
と表されるね。この応力テンソルの意味を理解するために、法線ベクトルがx軸成分のみを持つ場合($${ \boldsymbol{n}=(1,0,0)^{T} }$$)を考えてみるね。この場合、応力ベクトルは
$$
\boldsymbol{p}= \left( \begin{matrix} P_{xx} &P_{xy} &P_{xz} \cr P_{yx} &P_{yy} &P_{yz} \cr P_{zx} &P_{zy} &P_{zz} \end{matrix} \right)\left( \begin{matrix}1 \cr 0 \cr 0 \end{matrix} \right)= \left( \begin{matrix}P_{xx} \cr P_{yx} \cr P_{zx} \end{matrix} \right)
$$
となり、法線方向であるx軸方向以外にも、水平方向であるy軸方向とz軸方向にも応力が生じていること表しているよ。このように弾性体中の任意の微小体積に働く応力はその微小体積の応力テンソルで一意に表現することができるね。微小体積ごとに応力テンソルが変化させることで応力が位置によって変化する弾性体も表現できるよ。
もともとこの応力は弾性体の変形(歪)によって生じるので、応力テンソルは歪テンソルと密接な関係があるね。応力の大きさが歪に比例する弾性体は線形弾性体って呼ばれ、次の関係式で定義されるね。
$$
P_{ij} =\sum\limits_{k}\sum\limits_{l} C_{ijkl} E_{kl}
$$
$${E_{ij}}$$は歪テンソルだよ。$${C_{ijkl}}$$は2階のテンソルである応力テンソルと歪テンソルをつなぐ比例定数となるテンソルで4階のテンソルだよ。歪と応力の関係は非常に複雑なのだけれども、弾性性が等方的であるという条件(等方弾性体)を課すと、なんと2つの独立なパラメータ$${ \lambda, \mu }$$を用いて
$$
P_{ij} = \lambda\, \delta_{ij}\sum\limits_{k} E_{kk} +2\mu E_{ij}
$$
と表すことができるよ。この2つのパラメータはラメの定数と呼ばれ、等方弾性体の様々な性質を表すことができるよ。ここで用いている等方性は着目する微小体積ごとに成り立てば、微小体積ごとにパラメータが変化すること自体は全く問題ないね。
一般に弾性体の性質を表す物質定数はヤング率$${Y}$$とポアッソン比$${\sigma}$$が用いられるね。この2つのパラメータはそれぞれ歪テンソルと応力テンソルを用いて次のように定義されるよ。
$$
Y=\frac{ P_{xx} }{ E_{xx} } \ , \ \sigma=-\frac{ E_{yy}}{ E_{xx}}=-\frac{ E_{zz}}{ E_{xx}}
$$
ヤング率は歪に対する応力の比例定数を表す量で、大きいほど硬いことを意味するね。ポアッソン比はある方向の歪の大きさに対するその垂直方向の歪の大きさの比を表す量で、大きいほど一方に伸ばしたときの垂直方向が縮むことを意味するね。ポアッソン比にマイナスがついているのは、通常、一方に伸ばしたら他方は縮むことが想定されているからだよ。この2つのパラメータは先のラメのパラメータと一対一の関係があって、
$$
\lambda=\frac{Y\sigma}{(1+\sigma)(1-2\sigma)} , \mu=\frac{Y}{2(1+\sigma)}
$$
となるよ。つまり、応力テンソルと歪テンソルの関係は
$$
P_{ij} = \frac{Y}{1+\sigma}\left( \frac{\sigma}{1-2\sigma}\, \delta_{ij}\sum\limits_{k} E_{kk} + E_{ij} \right)
$$
となるね。ちなみに応力テンソルと歪テンソルの反対の関係も逆に解くことで直ちに
$$
E_{ij} = -\frac{\sigma}{Y}\, \delta_{ij}\sum\limits_{k} P_{kk} +\frac{1+\sigma}{Y}\, P_{ij}
$$
となるよ。一番簡単な1方向に引き伸ばしたときにその他の方向は縮む変形する一軸伸長の場合で考えてみるね。z軸方向に張力$${T}$$を与えたとき、z軸方向にはヤング率を用いて$${T/Y}$$だけ変形すると同時に、x軸とy軸方向にはポアソン比を用いて$${-\sigma T /Y}$$だけ変形するね。対応するひずみテンソルと応力テンソルは次のとおりだよ。
$$
E=\left(\begin{matrix} - \frac {\sigma T}Y & 0 & 0\cr 0 & - \frac {\sigma T}Y & 0\cr 0 & 0 & \frac TY\end{matrix} \right) \ \leftrightarrow \ P=\left(\begin{matrix} 0 & 0 & 0\cr 0 & 0 & 0\cr 0 & 0 & T \end{matrix} \right)
$$
下図は最大張力$${T=1}$$として、$$Y=2.0, \sigma=0.4$$としたときの自重無し単純一軸伸長による単振動運動を可視化した結果だよ。伸びに対して細くなる感じが表現できてるね。
Javascriptプログラムソース
Javascriptプログラムソースを用意したよ。もし良かったら試してみてください。これからも応援よろしくお願いしまーす!
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>一軸伸長(自重無し)</title>
<script src="https://natural-science.or.jp/files/physics/UV_Grid_Sm.js"></script>
<script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<style>
*{padding:0px; margin:0px}
div#canvas-frame{
width: 900px; /* 横幅 */
height: 900px; /* 縦幅 */
overflow:hidden;
}
table.matrix input{
width: 30px;
}
section#field{
padding: 10px 20px;
border: 1px solid gray;
border-radius: 10px;
margin: 10px 10px;
width: 850px;
}
</style>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.168.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.168.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
//初期変位勾配テンソル
let D = [
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
]
//張力
let T_max = 1.0;
//ヤング率
let Y = 2;
//ポアソン比
let sigma = 0.4;
//
let Lz = 1.5;
function setD( r, T, D ){
let x = r[0], y = r[1], z = r[2];
D[0][0] = -sigma * T / Y;
D[0][1] = 0;
D[0][2] = 0;
D[1][0] = 0;
D[1][1] = -sigma * T / Y;
D[1][2] = 0;
D[2][0] = 0.0;
D[2][1] = 0.0;
D[2][2] = T/Y;
}
//変位勾配テンソルによる変位計算
function Deformation( D, r ){
let x = D[ 0 ][ 0 ] * r[ 0 ] + D[ 0 ][ 1 ] * r[ 1 ] + D[ 0 ][ 2 ] * r[ 2 ];
let y = D[ 1 ][ 0 ] * r[ 0 ] + D[ 1 ][ 1 ] * r[ 1 ] + D[ 1 ][ 2 ] * r[ 2 ];
let z = D[ 2 ][ 0 ] * r[ 0 ] + D[ 2 ][ 1 ] * r[ 1 ] + D[ 2 ][ 2 ] * r[ 2 ];
return [ x, y, z ];
}
//格子点座標の初期値
let initialPositionArray = [ ]
////////////////////////////////////////////////////////////////////
// windowイベントの定義
////////////////////////////////////////////////////////////////////
window.addEventListener("load", function () {
threeStart(); //Three.jsのスタート関数の実行
});
////////////////////////////////////////////////////////////////////
// Three.jsスタート関数の定義
////////////////////////////////////////////////////////////////////
function threeStart() {
initThree(); //Three.js初期化関数の実行
initLight(); //光源初期化関数の実行
initObject(); //オブジェクト初期化関数の実行
initCamera(); //カメラ初期化関数の実行
loop(); //無限ループ関数の実行
}
////////////////////////////////////////////////////////////////////
// Three.js初期化関数の定義
////////////////////////////////////////////////////////////////////
//グローバル変数の宣言
let renderer, //レンダラーオブジェクト
scene, //シーンオブジェクト
canvasFrame; //キャンバスフレームのDOM要素
function initThree() {
//キャンバスフレームDOM要素の取得
canvasFrame = document.getElementById('canvas-frame');
//レンダラーオブジェクトの生成
renderer = new THREE.WebGLRenderer({ antialias: true });
if (!renderer) alert('Three.js の初期化に失敗しました');
//レンダラーのサイズの設定
renderer.setSize(canvasFrame.clientWidth, canvasFrame.clientHeight);
//キャンバスフレームDOM要素にcanvas要素を追加
canvasFrame.appendChild(renderer.domElement);
//レンダラークリアーカラーの設定
renderer.setClearColor(0xEEEEEE, 1.0);
//シーンオブジェクトの生成
scene = new THREE.Scene();
}
////////////////////////////////////////////////////////////////////
// カメラ初期化関数の定義
////////////////////////////////////////////////////////////////////
//グローバル変数の宣言
let camera; //カメラオブジェクト
let trackball;
function initCamera() {
//カメラオブジェクトの生成
camera = new THREE.PerspectiveCamera(45, canvasFrame.clientWidth / canvasFrame.clientHeight, 1, 10000);
//カメラの位置の設定
camera.position.set(2.6, 2.6, 0.8);
//カメラの上ベクトルの設定
camera.up.set(0, 0, 1);
//カメラの中心位置ベクトルの設定
camera.lookAt(new THREE.Vector3(0,0,0)); //トラックボール利用時は自動的に無効
//トラックボールオブジェクトの宣言
trackball = new TrackballControls(camera, canvasFrame);
//トラックボール動作範囲のサイズとオフセットの設定
trackball.screen.width = canvasFrame.clientWidth; //横幅
trackball.screen.height = canvasFrame.clientHeight; //縦幅
trackball.screen.offsetLeft = canvasFrame.getBoundingClientRect().left; //左オフセット
trackball.screen.offsetTop = canvasFrame.getBoundingClientRect().top; //右オフセット
//トラックボールの回転無効化と回転速度の設定
trackball.noRotate = false;
trackball.rotateSpeed = 2.0;
//トラックボールの拡大無効化と拡大速度の設定
trackball.noZoom = false;
trackball.zoomSpeed = 4.0;
//トラックボールのカメラ中心移動の無効化と中心速度の設定
trackball.noPan = false;
trackball.panSpeed = 1.0;
trackball.target = new THREE.Vector3(0, 0, 0);
//トラックボールのスタティックムーブの有効化
trackball.staticMoving = true;
//トラックボールのダイナミックムーブ時の減衰定数
trackball.dynamicDampingFactor = 0.3;
}
////////////////////////////////////////////////////////////////////
// 光源初期化関数の定義
////////////////////////////////////////////////////////////////////
//グローバル変数の宣言
let directionalLight, //平行光源オブジェクト
ambientLight; //環境光オブジェクト
function initLight() {
//平行光源オブジェクトの生成
directionalLight = new THREE.DirectionalLight(0xffffff, 2.0, 0);
//平行光源オブジェクトの位置の設定
directionalLight.position.set(50, 50, 10);
//平行光源オブジェクトの影の生成元
directionalLight.castShadow = false;
//平行光源オブジェクトのシーンへの追加
scene.add(directionalLight);
//環境光オブジェクトの生成
ambientLight = new THREE.AmbientLight(0x666666);
//環境光オブジェクトのシーンへの追加
scene.add(ambientLight);
}
////////////////////////////////////////////////////////////////////
// オブジェクト初期化関数の定義
////////////////////////////////////////////////////////////////////
let box, sphere;
function initObject() {
//スカイドームの生成
let skydome = createSkydome();
//床オブジェクトをシーンへ追加
scene.add( skydome );
//img要素の生成
let img = new Image();
img.src = UV_Grid_Sm; //DataURL
let texture = new THREE.Texture( img );
texture.needsUpdate = true;
//カラースペースの指定
texture.colorSpace = THREE.SRGBColorSpace;
let L = 0.2;
//形状オブジェクトの宣言と生成
let geometry = new THREE.BoxGeometry(
L, //width:x軸方向の幅(デフォルト:1.0)
L, //height:y軸方向の幅(デフォルト:1.0)
Lz, //depth:z軸方向の幅(デフォルト:1.0)
100, //widthSegments:x軸方向の分割数(デフォルト:1)
100, //heightSegments:y軸方向の分割数(デフォルト:1)
100 //depthSegments:z軸方向の分割数(デフォルト:1)
);
//材質オブジェクトの宣言と生成
let material = new THREE.MeshPhongMaterial({ map: texture, color: 0xffffff, specular: 0xffffff, shininess: 200 });
//直方体オブジェクトの生成
box = new THREE.Mesh(geometry, material);
//直方体オブジェクトのシーンへの追加
scene.add(box);
//直方体オブジェクトの位置座標を設定
box.position.set(0, 0, Lz/5*3.8);
for(let i = 0; i < box.geometry.attributes.position.array.length/3; i++){
box.geometry.attributes.position.array[ 3 * i + 0 ] += 0;
box.geometry.attributes.position.array[ 3 * i + 1 ] += 0;
box.geometry.attributes.position.array[ 3 * i + 2 ] -= Lz/2;
}
for(let i = 0; i < box.geometry.attributes.position.array.length; i++){
initialPositionArray.push( box.geometry.attributes.position.array[i] );
}
let roof = new THREE.Mesh(
new THREE.BoxGeometry(1,1,0.1),
new THREE.MeshPhongMaterial({ color: 0x00ffff, specular: 0xffffff, shininess: 200 })
)
roof.position.set(0, 0, Lz/5*3.8+0.05);
scene.add( roof );
//球オブジェクトの生成
sphere = new THREE.Mesh(
new THREE.SphereGeometry(L*1.2,40,40),
new THREE.MeshPhongMaterial({ color: 0x00ffff, specular: 0xffffff, shininess: 200 })
);
//球オブジェクトのシーンへの追加
scene.add(sphere);
}
////////////////////////////////////////////////////////////////////
// 無限ループ関数の定義
////////////////////////////////////////////////////////////////////
//グローバル変数の宣言
let step = 0; //ステップ数
function loop() {
//トラックボールによるカメラオブジェクトのプロパティの更新
trackball.update();
let T = T_max * Math.cos( 2*Math.PI /120 * step%120 );
for(let i = 0; i < box.geometry.attributes.position.array.length/3; i++){
let x = initialPositionArray[ 3 * i + 0 ];
let y = initialPositionArray[ 3 * i + 1 ];
let z = initialPositionArray[ 3 * i + 2 ];
let dx = [x, y, z];
setD( dx, T, D )
let dr = Deformation( D, dx );
box.geometry.attributes.position.array[ 3 * i + 0 ] = dx[ 0 ] + dr[ 0 ];
box.geometry.attributes.position.array[ 3 * i + 1 ] = dx[ 1 ] + dr[ 1 ];
box.geometry.attributes.position.array[ 3 * i + 2 ] = dx[ 2 ] + dr[ 2 ];
}
box.geometry.attributes.position.needsUpdate = true;
box.geometry.computeVertexNormals();
//球オブジェクトの位置座標を設定
sphere.position.set(0, 0, -T/Y*Lz -Lz/5*3.8/2);
step ++;
//レンダリング
renderer.render(scene, camera);
//「loop()」関数の呼び出し
requestAnimationFrame(loop);
}
//スカイドーム生成関数
function createSkydome(){
let vertexShader = "//バーテックスシェーダー\n" +
"//頂点シェーダーからフラグメントシェーダーへの転送する変数\n" +
"varying vec3 vWorldPosition;\n" +
"void main( ) {\n" +
" //ワールド座標系における頂点座標\n" +
" vec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n" +
" vWorldPosition = worldPosition.xyz;\n" +
" gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n" +
"}\n";
let fragmentShader = "//フラグメントシェーダ―\n" +
"//カスタムuniform変数の取得\n" +
"uniform vec3 topColor; //ドーム頂点色\n" +
"uniform vec3 bottomColor; //ドーム底辺色\n" +
"uniform float exp; //減衰指数\n" +
"uniform float offset; //高さ基準点\n" +
"//バーテックスシェーダーから転送された変数\n" +
"varying vec3 vWorldPosition;\n" +
"void main( ) {\n" +
" //高さの取得\n" +
" float h = normalize( vWorldPosition + vec3(0, 0, offset) ).z;\n" +
" if( h < 0.0) h = 0.0;\n" +
" gl_FragColor = vec4( mix( bottomColor, topColor, pow(h, exp) ), 1.0 );\n" +
"}\n";
//形状オブジェクトの宣言と生成
let geometry = new THREE.SphereGeometry( 500, 100, 100);
let uniforms = {
topColor: { type: "c", value: new THREE.Color(0.0, 0.3, 1.0) },
bottomColor: { type: "c", value: new THREE.Color(1.0, 1.0, 1.0)},
exp:{ type: "f", value : 0.8},
offset:{ type: "f", value : 300}
};
//材質オブジェクトの宣言と生成
let material = new THREE.ShaderMaterial( {
vertexShader: vertexShader,
fragmentShader: fragmentShader,
uniforms : uniforms,
side: THREE.BackSide,
} );
return new THREE.Mesh( geometry, material);
}
</script>
</head>
<body>
<section id="field">
<div style="font-size: 20pt; padding: 10px 10px 0px 10px; float: left;">
\( E=\left(\matrix{ - \frac {\sigma T}Y & 0 & 0\cr 0 & - \frac {\sigma T}Y & 0\cr 0 & 0 & \frac TY} \right) \ \leftrightarrow \ P=\left(\matrix{ 0 & 0 & 0\cr 0 & 0 & 0\cr 0 & 0 & T } \right) \)
</div>
<br style="clear:both;">
</section>
<div id="canvas-frame"></div><!-- canvas要素を配置するdiv要素 -->
</body>
</html>