matlab...

61
December 22, 2008 12 MATLAB による有限要素プログラム 本章では,MATLAB 関数の使用法を一通り説明してから,線形代数のいくつ かの内容を MATLAB で取り扱う.その後,有限要素プログラムの説明を行うが, トラス構造の問題(2 章)からはじめて,汎用的な 1 次元問題(5 章),2 次元 熱伝導問題(8 章),2 次元弾性問題(9 章),はりの問題(10 章)の順で取り 上げる.なお,本章は,次にあげる理由により電子出版されることとなった. 1. 有限要素に関する新しい技術や MATLAB のバージョンアップに応じて, 有限要素プログラムを定期的に更新するため. 2. MATLAB やその他の言語による自作の有限要素プログラムを使用しても らうため. 3. フォーラムを設けて,学生と教員間で意見を交換するとともに,各自の有 限要素プログラムをアップロードするため.なお,フォーラムの URL 下記のとおりである. http://1coursefem.blogspot.com/ 12.1 有限要素法のための MATLAB 使用法 1 12.1.1 MATLAB 画面 MATLAB を起動すると,図 12.1 に示すような「カレントディレクトリ」, 「コマンド履歴」,「コマンドウィンドウ」の 3 画面が現れる.これらの 3 画面 が現れない場合には,メニューから「デスクトップ」→「デスクトップのレイア ウト」→「デフォルト」を選択する. 1 講義では,本節に割く時間がないことが多いので自習を勧める.

Upload: phungbao

Post on 25-Jun-2018

251 views

Category:

Documents


0 download

TRANSCRIPT

December 22, 2008

12 章 MATLAB による有限要素プログラム 本章では,MATLAB 関数の使用法を一通り説明してから,線形代数のいくつ

かの内容を MATLAB で取り扱う.その後,有限要素プログラムの説明を行うが,

トラス構造の問題(2 章)からはじめて,汎用的な 1 次元問題(5 章),2 次元

熱伝導問題(8 章),2 次元弾性問題(9 章),はりの問題(10 章)の順で取り

上げる.なお,本章は,次にあげる理由により電子出版されることとなった.

1. 有限要素に関する新しい技術や MATLAB のバージョンアップに応じて,

有限要素プログラムを定期的に更新するため. 2. MATLAB やその他の言語による自作の有限要素プログラムを使用しても

らうため. 3. フォーラムを設けて,学生と教員間で意見を交換するとともに,各自の有

限要素プログラムをアップロードするため.なお,フォーラムの URL は

下記のとおりである. http://1coursefem.blogspot.com/

12.1 有限要素法のための MATLAB 使用法1

12.1.1 MATLAB 画面 MATLAB を起動すると,図 12.1 に示すような「カレントディレクトリ」,

「コマンド履歴」,「コマンドウィンドウ」の 3 画面が現れる.これらの 3 画面

が現れない場合には,メニューから「デスクトップ」→「デスクトップのレイア

ウト」→「デフォルト」を選択する.

1 講義では,本節に割く時間がないことが多いので自習を勧める.

2

図 12.1 MATLAB 起動時の画面

12.1.2 コマンドウィンドウ コマンドウィンドウをクリックすると,プロンプト記号「>>」の後ろにカーソルが現

れ,命令を入力できる状態となる.

12.1.3 数式の入力 コマンドウィンドウをクリックしてから,計算したい数式を入力する.たとえば,

8+4 と入力してエンターキーを押すと,ans = 12 という答えが返される.

12.1.4 変数の宣言 変数は,MATLAB に命令を与えることで自動的に宣言される.その一般的な

書式は,(変数名) = (数式) である.たとえば,コマンドウィンドウに y = 1 と入

力してエンターキーを押すと,y = 1 が返される.この操作により,変数 y が宣

言され,その y に値 1 が割り当てられる.以降の計算では,この変数を値 1 とし

て参照できる.たとえば,コマンドウィンドウに y*y を入力してエンターキーを

押すと,ans = 1 が返される.MATLAB では大文字と小文字を区別するので,y = 1 と Y = 5 は別々の変数として取り扱われる.

3

12.1.5 MATLAB 関数 MATLAB には,MATLAB 関数として,三角関数(sin(x) や cos(x) など)のよ

うな標準的な数学関数のほかに,ツールボックスとよばれる特定の応用分野に特

化した多くの関数群が用意されている.

12.1.6 ヘルプの使用法と MATLAB 関数の見つけ方 MATLAB には以降で紹介する MATLAB 関数のほかにも便利な MATLAB 関数

が多く用意されているので,適切なものを素早く見つけることが,MATLAB プ

ログラミングの初心者にとって一番重要である. MATLAB 関数のヘルプを探すには,次に示す二つの方法がある.

• ウィンドウの 上部にある「?」記号をクリックする.そうすると,ヘルプ画

面が現れるので,適切なタブを選ぶことにより必要な情報を表示できる.

• コマンドウィンドウで「help」と入力してエンターキーを押す.そうすると, MATLAB関数に関する項目の一覧が返される.一覧の 後には,より詳しい

説明へのリンクがある.たとえば「help sqrt」と入力すると,平方根に関する

MATLAB関数の一覧が出力される.

12.1.7 MATLAB による線形代数の計算 MATLAB は,数値計算と可視化グラフィックスのためのインタラクティブな

ソフトウェアである.MATLAB(行列実験室;MATrix LABoratory)という名称

からも明らかなように,本ソフトウェアは行列計算に特化したものである.実は

それだけでなく,各種グラフィックスや計算結果の可視化にも優れているので,

プログラミングを行う際に様々な応用が可能である.本節では,行列計算を行う

ための必要 低限の事項と,有限要素プログラムを理解し開発するための基本的

なプログラミングについて説明する.

12.1.8 行列の定義とその MATLAB 表現 次のような m 行 n 列の行列は,m n× 行列ともよばれ,m n× の 2 次元数値配

列で表現される.

11 12 1

21 22

1

n

m mn

a a a

a a

a a

⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥= ⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

a

太字は行列であることを示し,行列 a の第 i 行 j 列目の成分を aijで表す.行の数

と列の数の順番,および下添字の順番は,行と列を区別するために行に関するほ

うを必ず先に書く. 3×3 行列の一例を次に示す.

4

1 2 3

4 5 6

7 8 0

⎡ ⎤⎢ ⎥⎢ ⎥

= ⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

a

行数と列数が等しい行列のことを正方行列(square matrix)とよぶが,この行列

a は正方行列の例でもある. この行列は,MATLAB のコマンドウィンドウから以下のように入力すること

により作成できる(>>はプロンプト記号).

>> a = [1 2 3; 4 5 6; 7 8 0]

a =

1 2 3

4 5 6

7 8 0

ここで,行列の1行毎にセミコロン「;」で,各行内の成分はスペースもしくは

カンマ「,」で区切っていることに注意.行列の大きさは次のようにして調べる

ことができる.

( )size a 行列の転置(transpose)は,行と列を入れ替えることで得られる.たとえば,aの転置は,

1 4 7

2 5 8

3 6 0

T

⎡ ⎤⎢ ⎥⎢ ⎥

= ⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

a

であるが,MATLAB では転置記号をアポストロフィ「 ’」で表す.

T =a aであ

る場合,行列aは対称行列(symmetric matrix)とよばれる. 特に n = 1 である場合,次のような行列を,列行列(column matrix)あるいは

列ベクトルとよぶ.

1

2

3

b

b

b

⎡ ⎤⎢ ⎥⎢ ⎥

= ⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

b

5

MATLAB では,下添字が一つだけの行列は行行列(row matrix)(あるいは行ベ

クトル)として扱われるので,列行列(列ベクトル)は次のように入力すればよ

い.

>> b = [1 2 3]'

b =

1

2

3

ここで,b を列行列として入力するために転置記号(アポストロフィ「’」)を

用いたことに注意.列行列 b の成分を 1 2 3, ,b b b とすると,b の転置は行行列であり,

1 2 3T b b b⎡ ⎤= ⎢ ⎥⎣ ⎦b

MATLAB では次のように入力する.

>> b = [1 2 3]

b =

1 2 3

対角成分のみが非ゼロ,すなわち 0,ija i j= ≠ である行列は,対角行列

(diagonal matrix)とよばれる.たとえば,次のような行列が対角行列である.

1 0 00 5 00 0 6

a⎡ ⎤⎢ ⎥= ⎢ ⎥⎢ ⎥⎣ ⎦

MATLAB で対角行列を作成する場合,次に示すように,まずは行行列 b = [1 5 6]を作成してから,MATLAB 関数 diag を用いる.この関数は,正方行列の対角位

置に行行列の成分を順に入れていくものである.

6

>> b = [1 5 6];

>> a = diag (b)

a =

1 0 0

0 5 0

0 0 6

すべての対角成分が 1 である対角行列は単位行列(identity or unit matrix)よば

れ,たとえば 2×2 の単位行列は次のとおりである.

1 0

0 1

⎡ ⎤⎢ ⎥= ⎢ ⎥⎢ ⎥⎣ ⎦

I

MATLAB では, n 次の単位行列は次のように表現される. ( )eye n 実際,MATLAB のコマンドウィンドウで (2)I eye= と入力すると,上記の単位

行列を作成できる. すべての成分がゼロの行列は零行列(zero matrix)とよばれ,0 と表記される.

MATLAB では B = zeros(m, n) と入力するとm n× の零行列 B が作成できる.また,

乱数により生成された成分をもつm n× 行列は rand (m,n) により作成できる. 有限要素法では,疎行列(sparse matrix),すなわちほとんどの成分がゼロで

ある行列を取り扱うことが多いが,MATLAB はこのような疎行列も取り扱うこ

とができる.疎行列では非ゼロ成分の値と位置だけを記憶しておくことから,

密行列(densed matrix)に比べて計算速度の向上と必要記憶量の減少が可能とな

るので,実際上の工学問題を解くにあたり非常に有用である.m n× の零行列を

疎行列形式で作成するには,sparse(m, n) と入力する. 非ゼロ成分は下記のよう

に一つずつ入力していくか,ループ内で入力する.

7

>> a = sparse (3,2)

a =

All zero sparse: 3-by-2

>> a(1,2)=1;

>> a(3,1)=4;

>> a(3,2)=-1;

>> a

a =

(3,1) 4

(1,2) 1

(3,2) -1

なお,MATLAB 命令の 後にセミコロン「;」を付けると,出力を抑制できる. 正方行列 a の逆行列(inverse matrix)a−1 は,次式で定義される.

1 1− −= =a a aa I 行列 aが特異でない場合,MATLAB では ( )inv a と入力することで逆行列が得ら

れる.なお,線形の代数方程式は,12.1.10 項で示すようにバックスラッシュ演

算子「\」を用いて解くことができる.この演算子により逆行列の計算が不要に

なるので,計算が速くなる. 行列aの行列式(デターミナント)がゼロでないとき行列 aは特異でない.た

とえば,2×2 行列の行列式は次式で定義される.

( )11 12

11 22 12 2122 22

deta a

a a a aa a⎡ ⎤⎢ ⎥= = −⎢ ⎥⎣ ⎦

a a

MATLAB では次のように表現される. det( )a 次に一例を示す.

>> a = [1 3; 4 2];

>> det (a)

ans =

-10

8

12.1.9 行列の演算

加減算

11 11 12 12 1 1

21 21 22 22

1 1

n n

m m mn mn

a b a b a b

a b a b

a b a b

⎡ ⎤± ± ±⎢ ⎥⎢ ⎥± ±⎢ ⎥

= ± = ⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥± ±⎢ ⎥⎣ ⎦

c ba

MATLAB による行列同士の加算例を次に示す.

>> a = [1 2 3;4 5 6;7 8 9];

>> a = [1 1 1;2 2 2;3 3 3];

>> c = [1 2;3 4;5 6];

>> a+b

ans =

2 3 4

6 7 8

10 11 12

>> a+c

??? Error using ==> +

Matrix dimensions must agree

乗算

1. 行列とスカラーの積

11 12 1 11 12 1

21 22 21 22

1 1

n n

m mn m mn

a a a ca ca ca

a a ca cac c

a a ca ca

⎡ ⎤ ⎡ ⎤⎢ ⎥ ⎢ ⎥⎢ ⎥ ⎢ ⎥⎢ ⎥ ⎢ ⎥= =⎢ ⎥ ⎢ ⎥⎢ ⎥ ⎢ ⎥⎢ ⎥ ⎢ ⎥⎢ ⎥ ⎢ ⎥⎣ ⎦ ⎣ ⎦

a

2. 列行列同士のスカラー積

9

1

2

1 21

nT

n i ii

n

b

ba a a a b

b

=

⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎡ ⎤= =⎢ ⎥⎢ ⎥⎣ ⎦ ⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

∑b …a

MATLAB では,上記のスカラー積は *a b′ もしくは ( , )dot a b で計算できる.

列ベクトル a の長さは|a|で表され,次のように定義される.

2 2 21 2 na a a= + + +a

列ベクトルの長さはノルム(norm)とよばれている.

3. 行列同士の積 ( )m k× の行列 a と( )k n× の行列 b の積は次式で定義される.

1 1 1 2 11 1 1

2 1 2 21 1

11 1

k k k

j j j j j jnj j j

k k

j j j jj j

k k

mj j mj jnj j

a b a b a b

a b a b

a b a b

= = =

= =

= =

⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥= = ⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

∑ ∑ ∑

∑ ∑

∑ ∑

c ab

あるいは,次のように書くこともできる.

1

n

ij ik kjk

c a b=

= ∑

ここで,c の第 i 行 j 列目成分は,a の第 i 行目の行行列と b の第 j 列目の

列行列のスカラー積であることに注意.行列 a と b の積 c は,a の列数と

b の行数が等しいときのみ定義される.換言すると,k を任意の正の整数

として,a が( )m k× 行列であるとき,b は( )k n× 行列でなければならない.

したがって,積 c の行数と列数はそれぞれ,a の行数と b の列数となるの

で,m n× 行列である.なお,行列同士の積は特殊な場合を除いて非可換,

すなわち ≠ab baであることにも注意. MATLAB では,行列同士の積は次のように表記される.

*c a b=

10

先ほどの例で用いた行列 a と c をそのまま用いて,MATLAB による行列

同士の積の計算結果を以下に示す.

>> a*c

ans =

22 28

49 64

76 100

>> c*c

??? Error using ==> *

Inner matrix dimensions must agree.

4. その他の行列計算

a) 行列同士の積の転置: ( )T T T=ab b a b) 単位行列との積: =aI a c) 零行列との積: =a0 0

12.1.10 連立 1 次方程式の求解 n 個の未知数 kd (k = 1, 2 ,… n)と n 本の線形代数方程式で構成される次の連立

1 次方程式を考える.

11 1 2 2 1 1

21 1 22 2 2 2

1 1 2 2

n n

n n

n n nn n n

K d K d K d f

K d K d K d f

K d K d K d f

⎧ + + + =⎪⎪⎪⎪ + + + =⎪⎪⎪⎨⎪⎪⎪⎪⎪ + + + =⎪⎪⎩

この連立 1 次方程式の行列表記は次式である.

=Kd f

ここで,

11

11 12 1 1 1

21 22 2 2

1

n

n nn n n

K K K f d

K K f d

K K f d

⎡ ⎤ ⎡ ⎤ ⎡ ⎤⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎢ ⎥ ⎢ ⎥ ⎢ ⎥

= = =⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎣ ⎦ ⎣ ⎦ ⎣ ⎦

K f d

この方程式の解は,K の逆行列を右から乗ずることにより,形式的には次のよ

うに求められる. 1−=d K f 連立 1 次方程式を解く MATLAB 命令を次に示す. \d K f= または ( )*d inv K f= MATLAB による連立 1 次方程式の求解例を次に示す.

>> A = rand (3,3)

A =

0.2190 0.6793 0.5194

0.0470 0.9347 0.8310

0.6789 0.3835 0.0346

>> b = rand (3,1)

b =

0.0535

0.5297

0.6711

>> x = A\b

x =

-159.3380

314.8625

-344.5078

なお,すでに述べたように,バックスラッシュ演算子「\」を用いたほうが計算

は速くなる.この理由は数値計算のアルゴリズムに関係しており,バックスラッ

12

シュ演算子では右辺について一度だけの求解で間に合うが,n×n 行列の逆行列を

作成するには,右辺について n 回の求解が必要となるためである.したがって,

大規模な連立 1 次方程式を解く際にはバックスラッシュ演算子を用いるほうがよ

い.

12.1.11 MATLAB における文字列の取扱い

MATLAB 変数を文字列型として定義することもできる.1 つの文字列は単一

引用符「’」で括られた文字の集合である.次に一例を示す.

>> str='hello world'

str =

hello world

次に示すように,配列の各行に文字列を割り当てることで,文字列の配列を作

ることもできるが,各行の文字列は同一の長さでなければならない.

>> str_mat = ['string A' ; 'string B']

str_mat =

string A

string B

文字列はファイル名や図のタイトル,データ書式を定義するために用いられ,

これらの文字列を操作するための特殊なMATLAB関数が用意されている.後ほ

ど説明するMATLABプログラムでは,関数を比較するために文字列を用いてい

る.たとえば,次に示すように「strcmpi」というMATLAB関数は2つの文字列を

比較するものである.

>> str = 'print output';

>> strcmpi(str,'PRINT OUTPUT')

ans =

1

なお,比較結果が真であれば 1 を,偽であれば 0 が返される.文字列操作に関す

るMATLAB関数は,次のように入力すると一覧できる.

>> help strfun

13

もう一つ,後ほど説明するMATLABプログラムで用いる関数は,「fprintf」で

ある.この関数は文字列や数値を書式付きでコマンドウィンドウやファイルに出

力するものである.一例を以下に示す.

>>fprintf(1,'The number of nodes in the mesh is %d \n',10)

The number of nodes in the mesh is 10

この関数の第1引数はファイル識別子であり,この場合はコマンドウィンドウに

出力される.第2引数は文字列である.「%d」は数値を10進表記文字に変換する

指定子なので,この場合は10が出力される.また,「\n」は改行指定である.よ

り詳しい説明は,以下のように入力してヘルプを参照すること.

>> help fprintf

12.1.11 MATLAB を用いたプログラミング MATLAB は,条件分岐や反復というような標準的な制御命令と,ユーザが独

自に定義できる関数を備えており,単純な有限要素プログラムを書くために非常

に便利なプログラム言語である.これらの制御命令は,単純な繰返し作業を減ら

すためにインタラクティブに使用できるだけでなく,「m-file」とよばれるプロ

グラムソース(拡張子が.m のテキストファイル)中にも記述できる.

12.1.11.1 条件分岐と反復の構文 条件分岐の MATLAB 構文は標準的なものであり,これを以下に示す.

一般形 例 if 条件式 1 実行文 1 elseif 条件式 2 実行文 2 … … … else 実行文 End

>> t = 0.76; >> if t > 0.75 s = 0; elseif t < 0.25 s = 1; else s = 1-2*(t-0.25); end >> s s = 0

反復の MATLAB 構文には,for ループ(Fortran の do ループ,または C の for

ループに相当)と,while ループの 2 種類がある.for ループは,指定された行行

列の成分の値を制御変数に順に割り当てつつ,ループ内の実行文を繰り返す.一

14

方,while ループは,指定された条件式が真(非ゼロ)である限りループ内の実

行文を繰り返す. 一般形 例

for 制御変数 = 開始値:増分:終了値 実行文 end

>> for i=1:1:3 disp(i^2) end 1 4 9

while 条件式 実行文 end

>> x=1; >> while 1+x > 1 x = x/2; end >> x x = 1.1102e-16

12.1.11.2 関数の構文 ユーザが独自の MATLAB 関数を定義することにより,新しい命令を

MATLAB に追加できる.MATLAB 関数を新たに定義するには,m-file を作成し

たうえで,次に示すような関数の定義行から書きはじめる.

function [output1, output2,...] = cmd_name ( input1, input2,...) ここで,cmd_name は関数名であり,output1 等は出力引数,input1 等は入力引数

である.m-file 中で関数の定義行以降は通常の MATLAB 命令であり,計算内容

や実行させたい内容を自由に書くことができる.次に簡単な例を示す.この関数

は,ある値が与えられたときに 2 次関数 2( ) 3 1f x x x= − − を評価して返すもので

ある.以下に示す命令の上から 2 行は,あらかじめファイル「fcm.m」に保存し

ておくべきものである(MATLAB では,関数名に拡張子 m を付けたものがファ

イル名となる).

function y = fcn( x )

y=x^2-3*x-1;

Then type command:

>> fcn(0.1)

ans =

-1.2900

15

12.1.12 基本的なグラフィクス MATLAB はプログラミングだけでなく,結果の可視化も行える優れたツール

である.たとえば,次のように x 座標の行行列と y 座標の行行列を作成2して,

そのグラフを描いてみると,図 12.2 のようになる.

>> x=[0:0.01:1];

>> y=x.^2;

>> plot(x,y);

図 12.2 plot(x,y) による可視化の例

plot 命令で色・記号・線種を変更するためには,plot ( x,y,s ) のように第 3 引数 sとして,次に示す一覧の各列から 1 文字ずつ選んで 大 3 文字で指定する.

色 記号 線種 b 青 . 点 - 実線 g 緑 o 丸 : 点線 r 赤 x × -. 1 点鎖線 c シアン + プラス -- 破線 m マゼンタ * 星 (none) 線なし y イエロー s 四角 k ブラック d ダイアモンド

グラフにタイトルや x 軸と y 軸に名前を付けたり,グリッドを表示したりする

には次のように MATLAB 関数を使う.

2 訳注:べき乗演算子「^」の前のドット「.」は,その演算子を行列ではなく行列の各要素に対

して作用させることを意味する.

16

>> title('circle');

>> xlabel('x');

>> ylabel('y');

>> grid

ここで,関数の引数は文字列であることに注意. 後ほど説明する有限要素コードでは,「plot」に加えて「patch」と「quiver」

による可視化を行うので,ここで先に説明しておく.patch 命令は,2 次元のポ

リゴンをインデックスカラーで塗りつぶすために用いる.ポリゴン内部の塗りつ

ぶしカラーは,ポリゴンの頂点におけるインデックス値を用いて補間される.次

の例は正方形の塗りつぶし(図 12.3)である.x 軸に沿って色は変化しないが,

y 軸に沿って塗りつぶし色はインデックス値 [0,1]の補間に対応してグラディエー

ションとなっている.後ほど patch 命令を用いて,有限要素法により求解された

温度や応力,その他の値を可視化する.

>> x = [0 1 1 0];

>> y = [0 0 1 1];

>> c = [0 0 1 1];

>> patch(x,y,c)

図 12.3 patch(x,y,c)による可視化の例

続いて,quiver 命令であるが,この命令は場の勾配を矢印により可視化するた

めに用いる.図 12.4 に,関数 y=x2 で表現された場の勾配を可視化した例を示す.

17

>> x=0:0.1:1; y=x.^2;

>> cx=ones(1,11); cy=2*x;

>> plot(x,y); hold on

>> quiver(x,y,cx,cy)

図 12.4 quiver(x,y,cx,cy) による可視化の例

なお,上記の「hold on」命令は,現在の図を消去して新たに図を描くのではな

く,軸の設定はそのままに現在の図に上描きするための命令である. 「text」命令を用いると,図に文字列を描くことができる.たとえば,次のよ

うに入力する.

text(1,1,'flux') 第 1,第 2 引数は図中における文字列の位置であり,第 3 引数が描画する文字列

である.

12.1.13 注意点 a) 実際上,連立 1 次方程式の元数 n は非常に大きい.有限要素法で得ら

れるような,元数が数千で疎な連立 1 次方程式であれば,今日の PCでは数分で求解できる.しかし,航空機の機体や複雑な構造物の全体

モデルのように元数が数百万になると,並列計算機が必要である. b) ある程度の規模の問題を解くためには,有限要素方程式の疎行列性や

その他の特性を活かした,連立 1 次方程式の効率的な解法が必須であ

る.しかし本書ではこれについては述べない.

18

c) 本書で述べたように,境界条件が考慮された有限要素方程式の全体行

列(KFFで表記)には,移流拡散問題を除いて次の特性がある. • 適切に定式化がなされ,境界条件が正しく与えられているなら

ば,K は非特異(正則ともよばれる)なので, 1−K が存在する.

さらに,性質が良い問題であれば普通は良条件である.良条件

とは,解が数値の丸め誤差に敏感でないということである. • K は対称行列,すなわち T =K K である. • K は正定値行列,すなわち 0 T > ∀x Kx x である.換言すると,

「すべての固有値が正であれば K は正定値行列である」という

ことである.ここで,固有値とは次式を満たす数値λのことで

あり,固有値λに対応する非ゼロの固有ベクトル yを見いだす

問題とあわせて固有値問題とよばれている.

λ=Ky y 固有値問題を MATLAB で解くには次の例のようにすればよい.

>> K=[2 -2;-2 4];

>> [y, lamda]=eig(K)

y =

0.8507 -0.5257

-0.5257 0.8507

lamda =

0.7639 0

0 5.2361

12.2 MATLAB によるトラス構造の有限要素プログラミング トラス構造に対する有限要素法の基本的な枠組みはすでに 2 章で述べているの

で,本節では MATLAB 言語による単純な有限要素法プログラムについて説明す

る.MATLAB は行列や列ベクトルの取扱いが容易なので,有限要素法のアルゴ

リズム的な詳細よりもその基本的な概念の理解に集中できる. 以下に示すプログラムは 2 章の定式化にしたがってコーディングされているが,

プログラムの流れがより良く分かるように,ここでは図 2.8 と例 2.2 を実際に解

くことにする.このような方針に基づくコーディングと例題を通して,本プログ

ラムをより効果的に学習できるであろう. 本有限要素法プログラムを構成する主な m-file(拡張子が m のファイル)は,

次のとおりである. 1. プリプロセスとしてデータを入力し,配列を適切に割り付ける関数

19

2. 要素剛性行列と要素外力行列(列ベクトル)を評価する関数 3. 「直接的な組立」により,要素行列から全体行列を作成する関数 4. 分割解法により変位を求解する関数 5. ポストプロセスとして,副次的な値を評価する関数.

なお,各 m-file の詳細な説明は,プログラムのコメントとして書き込んである.

12.2.1 変数の説明

ユーザが値を指定しなければならない変数 nsd: 空間の次元数(1次元では1)(number of space dimension) ndof: 節点あたりの自由度数(number of degrees-of-freedom per node) nnp: 節点数nnp(number of nodal points) nel: 要素数nel(number of elements) nen: 要素節点数nen(今回は2)(number of element nodes) nd: 変位に関して既定の自由度数(number of prescribed displacement degrees-

of-freedom )

CArea: 断面積(cross-sectional area)用の1次元配列 用法:(断面積) = CArea((要素番号e)) E: ヤング率(Young’s modulus)E 用の1次元配列 用法:(ヤング率)= E((要素番号e)) leng: 要素長さ(element length)用の1次元配列 用法:(長さ) = leng((要素番号e)) phi: x ′軸(局所座標系:常に局所的な節点1から2の向きが正)とx 軸(全体

座標系)とがなす角度φ (phi)用の1次元配列 用法:(角度) = phi((要素番号e)) IEN: 要素に関する局所的な節点番号を全体系の節点番号に変換するための 2

次元配列(connectivity information of element nodes) 用法:(全体系の節点番号) = IEN ((局所的な節点番号) , ( 要素番号e)) d_bar: 既定(既知)の変位d用の1次元配列 f_hat: 既定(既知)の外力 f̂ 用の1次元配列 plot_truss: 出力制御用の文字列: ‘yes’のときトラス要素を描画 plot_nod: 〃 : ‘yes’のとき全体系の節点番号を描画 plot_stress: 〃 : ‘yes’のとき応力を可視化

プログラム中で計算に使用する変数 neq: 方程式の本数(number of equations) K: 全体剛性行列K(global stiffness matrix)

20

d: 次の形式の全体変位行列d(global displacement column matrix) 1次元問題 2次元問題

1

n

u

u

⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

= d

1

1

x

y

ny

u

u

u

⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

= d

f: 次の形式の全体外力行列f(global force column matrix)(反力を除く) 1次元問題 2次元問題

1

n

f

f

⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

= f

1

1

x

y

ny

f

f

f

⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

= f

e: 要素番号e(element number) ke: 要素剛性行列Ke(element stiffness matrix) de: 次の形式の要素変位行列de(element nodal displacement column matrix) 1次元問題 2次元問題

1

2

u

u⎡ ⎤⎢ ⎥⎢ ⎥⎣ ⎦

=de

1

1

2

2

ex

ey

ex

ey

u

u

u

u

⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

= de

LM: 要素に関する局所的な自由度番号を全体系の自由度番号に変換するための2次元配列(location matrix)(収集行列Le(gather matrix)と等価な情報を持

ち,「収集」と「分配」および「直接的な組立」のために用いる). 用法:(全体系の自由度番号) =LM ((局所的な自由度番号) , (要素番号e)) 注)LM とIENの関係

両方の2次元配列について,要素を列方向に,局所的な自由度を行方向に

並べて全体系の自由度番号を一覧表にすると次のようになる. ・節点あたりの自由度数がndof = 1のとき同一(図2.8の例を参照)

21

1 2

2 3

ee ==⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

= IEN

21

1 2

2 3

ee ==⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

= LM

・節点あたりの自由度数が ndof = 2のとき異なる (例2.2を参照)

21

21

1 2

3 3

ee ==⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

= IEN

1 3

2 4

5 5

6 6

⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

= LM

K_E: 全体剛性行列をE節点(未知自由度)に対応して分割した部分行列 [式

(2.29)を参照] K_EF: 全体剛性行列をE節点(未知自由度)とF節点(既知自由度)の連成に対

応して分割した部分行列 [式(2.29)を参照] K_F: 全体剛性行列をF節点(既知自由度)に対応して分割した部分行列 [式

(2.29)を参照] d_F: 全体変位行列d をF節点(既知自由度)に対応して分割した部分列行列

d_E: 全体変位行列d をE節点(既知自由度)に対応して分割した部分列行列 f_E: 未知の反力 行列 stress: 応力用の1次元配列 注)本書では,変位既定(既知)の節点から優先して全体系の節点番号を付けな

ければならない.

12.2.1 トラス構造の MATLAB 有限要素プログラム

truss.m %%%%%%%%%%%%%%%%%%%%%%%%%%%% % 2次元トラス構造の有限要素プログラム (第2章) % % Haim Waisman, Rensselaer % %%%%%%%%%%%%%%%%%%%%%%%%%%%% clear all; % すべての変数のクリア close all; % すべてのファイルをクローズ % グローバル変数のインクルード include_flags; % プリプロセス [K,f,d] = preprocessor; % 要素剛性行列の計算と全体剛性行列の組立 for e = 1:nel ke = trusselem(e); K = assembly(K,e,ke); end % 連立1次方程式の求解 [d,f_E] = solvedr(K,f,d);

22

% ポストプロセス postprocessor(d)

include_flags.m3 % グローバル変数の宣言 global nsd ndof nnp nel nen neq nd global CArea E leng phi global plot_truss plot_nod plot_stress global LM IEN x y stress

preprocessor.m % プリプロセス ― 計算に必要な入力データと要素分割の設定 function [K,f,d] = preprocessor; include_flags; % 入力データのインクルード input_file_example2_2; %input_file_example2_8; % LM配列の作成 for e = 1:nel for j = 1:nen for m = 1:ndof ind = (j-1)*ndof + m; LM(ind,e) = ndof*IEN(j,e) - ndof + m; end end end

input_file_example2_2.m3 % 例2.2の入力データを設定するスクリプト nsd = 2; % 空間の次元数(Number of space dimensions ) ndof = 2; % 節点あたりの自由度数(Number of degrees-of-freedom per node) nnp = 3; % 節点数(Number of nodal points) nel = 2; % 要素数(Number of elements) nen = 2; % 要素節点数(Number of element nodes) neq = ndof*nnp; % 方程式の本数(Number of equations) f = zeros(neq,1); % 全体外力行列の宣言 d = zeros(neq,1); % 全体変位行列の宣言 3 訳注:これらの m-file は 12.1.11 項で説明した MATLAB 関数ではなく,単にインクルードされ

る外部ファイル(MATLAB スクリプトとよばれる)である.スクリプト内で宣言された変数は,

MATLAB 関数の場合と異なり,それをインクルードした側からも見える(スコープ内).以降

すべての include_flags.m と input_*.m は MATLAB スクリプトであることに注意.

23

K = zeros(neq); % 全体剛性行列の宣言 % 要素特性 CArea = [1 1 ]; % 断面積 (Elements cross-sectional area) leng = [1 sqrt(2)]; % 要素長さ(Elements length) phi = [90 45 ]; % x ′軸(局所座標系)とx 軸(全体座標系)とがなす角度 E = [1 1 ]; % ヤング率 % 既定の変位 % d1x d1y d2x d2y d = [0 0 0 0]'; nd = 4; % 既定の自由度数(Number of prescribed displacement degrees-of-freedom) % 既定の外力 f(5) = 10; % 節点3の x方向力 f(6) = 0; % 節点3のy方向力 % 計算結果の可視化フラグ plot_truss = 'yes'; plot_nod = 'yes'; % 要素分割 truss_mesh_2_2;

truss_mesh_2_2.m % 要素分割(例2.2)の定義 function truss_mesh_2_2 include_flags; % 節点座標(節点2が原点) x = [1.0 0.0 1.0 ]; % x座標 y = [0.0 0.0 1.0 ]; % y座標 % 要素に関する局所的な節点番号を全体系の節点番号に変換するための2次元配列 IEN = [1 2 3 3]; % トラスの描画 plottruss;

input_file_example2_8.m % 図2.8の入力データを設定するスクリプト nsd = 1; % 空間の次元数(Number of spatial dimensions ) ndof = 1; % 節点あたりの自由度数(Number of degrees-of-freedom per node) nnp = 3; % 節点数(Number of nodal points) nel = 2; % 要素数(Number of elements)

24

nen = 2; % 要素節点数(Number of element nodes) neq = ndof*nnp; % 方程式の本数(Number of equations) f = zeros(neq,1); % 全体外力行列の宣言 d = zeros(neq,1); % 全体変位行列の宣言 K = zeros(neq); % 全体剛性行列の宣言 % 要素特性 CArea = [.5 1]; % 断面積(Elements cross-sectional area) leng = [2 2]; % 要素長さ(Elements length) E = [1 1]; % ヤング率 % 既定の変位 d(1) = 0; nd = 1; % 既定の自由度数(Number of prescribed displacement degrees of freedom) % 既定の外力 f(3) = 10; % 節点3のx方向力 % 計算結果の可視化フラグ plot_truss = 'yes'; plot_nod = 'yes'; % 要素分割 truss_mesh_2_8;

truss_mesh_2_8.m % 要素分割(図2.8)の定義 function truss_mesh_2_8; include_flags; % 要素座標 (節点1が原点) x = [0.0 1.0 2.0 ]; % x座標 y = [0.0 0.0 0.0 ]; % y座標 % 要素に関する局所的な節点番号を全体系の節点番号に変換するための2次元配列 IEN = [1 2 2 3]; % トラスの描画 plottruss; plottruss.m % トラス要素と全体系の節点番号の描画,メッシュパラメータの出力 function plottruss; include_flags;

25

% plot_trussフラグが’yes’ならばトラス要素を描画 if strcmpi(plot_truss,'yes')==1; for i = 1:nel XX = [x(IEN(1,i)) x(IEN(2,i)) x(IEN(1,i)) ]; YY = [y(IEN(1,i)) y(IEN(2,i)) y(IEN(1,i)) ]; line(XX,YY);hold on; % plot_nodフラグが’yes’ならば全体系の節点番号を表示 if strcmpi(plot_nod,'yes')==1; text(XX(1),YY(1),sprintf('%0.5g',IEN(1,i))); text(XX(2),YY(2),sprintf('%0.5g',IEN(2,i))); end end title('Truss Plot'); end % メッシュパラメータの出力 fprintf(1,'\tTruss Params \n'); fprintf(1,'No. of Elements %d \n',nel); fprintf(1,'No. of Nodes %d \n',nnp); fprintf(1,'No. of Equations %d \n\n',neq); trusselem.m % トラス要素の要素剛性行列を作成 function ke = trusselem(e) include_flags; const = CArea(e)*E(e)/leng(e); % 要素剛性行列の成分 if ndof == 1 ke = const * [1 -1 ; % 棒要素(1次元)の要素剛性行列 -1 1]; elseif ndof == 2 p = phi(e)*pi/180; % 角度(degree)を弧度(radian)に変換 s = sin(p); c = cos(p); s2 = s^2; c2 = c^2; ke = const*[c2 c*s -c2 -c*s; % トラス要素(2次元)の要素剛制行列 c*s s2 -c*s -s2; -c2 -c*s c2 c*s; -c*s -s2 c*s s2]; end assembly.m % 「直接的な組立」により要素剛性行列から全体剛性行列をアセンブリ function K = assembly(K,e,ke)

26

include_flags; for loop1 = 1:nen*ndof i = LM(loop1,e); for loop2 = 1:nen*ndof j = LM(loop2,e); K(i,j) = K(i,j) + ke(loop1,loop2); end end solvedr.m % 分割法による連立1次方程式の求解 function [d,f_E] = solvedr(K,f,d) include_flags; % 行列Kと列ベクトルf, dの分割 K_E = K(1:nd,1:nd); % 部分行列K_E の抽出 K_F = K(nd+1:neq,nd+1:neq); % 〃 K_F 〃 K_EF = K(1:nd,nd+1:neq); % 〃 K_EF 〃 f_F = f(nd+1:neq); % 部分列行列f_F の抽出 d_E = d(1:nd); % 〃 d_E 〃 % d_F について解く d_F =K_F\( f_F - K_EF'* d_E); % 全体変位行列d の再構成 d = [d_E d_F]; % 反力r の算出 f_E = K_E*d_E+K_EF*d_F; postprocessor.m % ポストプロセス― 計算結果の後処理 function postprocesser(d) include_flags; % 要素ごとの応力をコマンドウィンドウに出力 fprintf(1,'element\t\t\tstress\n'); % 応力の算出 for e=1:nel de = d(LM(:,e)); %要素番号eの節点変位を「収集」して要素変位行列に const = E(e)/leng(e); % 応力の成分 if ndof == 1 % 棒要素(1次元)のとき stress(e) = const*([-1 1]*de); end if ndof == 2 % トラス要素(2次元)のとき

27

p = phi(e)*pi/180; %角度(degree)を弧度(radian)に変換 c = cos(p); s = sin(p); stress(e) = const*[-c -s c s]*de; % 応力の算出 end fprintf(1,'%d\t\t\t%f\n',e,stress(e)); end

12.3 MATLAB による 1 次元の要素形状関数とガウス積分 本節では,1 次元の物理座標系における要素形状関数行列とその微分である B

マトリクスを作成して返す関数を取り上げる.

12.3.1 変数の説明 xe: 要素節点1, 2 の x 座標(element nodal x-coordinates)用の1次元配列 xt: 関数を評価する x 座標の値 N: 要素形状関数行列Ne(element shape function matrix) B: BマトリクスBe(derivative of element shape function matrix) gp: 親座標系[-1,1] におけるガウス積分点 1 2 ngpξ ξ ξ⎡ ⎤

⎢ ⎥⎣ ⎦ (position of

Gauss points in the parent element domain )用の1次元配列 W: 積分点に対応する重み 1 2 ngpW W W⎡ ⎤

⎢ ⎥⎣ ⎦ (weights)用の1次元配列

12.3.2 要素形状関数行列と B マトリクスを評価して返す MATLAB 関数

Nmatrix1D.m % 要素形状関数行列を物理座標xt で評価 function N = Nmatrix1D(xt,xe) include_flags; if nen == 2 % 形状関数が1次のとき N(1) = (xt-xe(2))/(xe(1)-xe(2)); N(2) = (xt-xe(1))/(xe(2)-xe(1)); elseif nen == 3 % 形状関数が2次のとき N(1)=(xt-xe(2))*(xt-xe(3))/((xe(1)-xe(2))*(xe(1)-xe(3))); N(2)=(xt-xe(1))*(xt-xe(3))/((xe(2)-xe(1))*(xe(2)-xe(3))); N(3)=(xt-xe(1))*(xt-xe(2))/((xe(3)-xe(1))*(xe(3)-xe(2))); end

Bmatrix1D.m % Bマトリクス(形状関数の微分)を物理座標xt で評価

28

function B = Bmatrix1D(xt,xe) include_flags; if nen == 2 % 1次形状関数の微分(定数値) B = 1/(xe(1)-xe(2))*[-1 1]; elseif nen == 3 % 2次形状関数の微分 B(1)=(2*xt-xe(2)-xe(3))/((xe(1)-xe(2))*(xe(1)-xe(3))); B(2)=(2*xt-xe(1)-xe(3))/((xe(2)-xe(1))*(xe(2)-xe(3))); B(3)=(2*xt-xe(1)-xe(2))/((xe(3)-xe(1))*(xe(3)-xe(2))); end

12.3.3 ガウス積分点とそれに対応する重みを返す MATLAB 関数

gauss.m % 親座標系 [-1, 1] におけるガウス積分点とそれに対応する重み function [w,gp] = gauss(ngp) if ngp == 1 gp = 0; w = 2; elseif ngp == 2 gp = [-0.57735027, 0.57735027]; w = [1, 1]; elseif ngp == 3 gp = [-0.7745966692, 0.7745966692, 0.0]; w = [0.5555555556, 0.5555555556, 0.8888888889]; end

12.4 MATLAB による 1 次元問題の有限要素プログラミング 12.2 節で 1 次元棒の問題と 2 次元トラス構造の解析に対する有限要素プログラ

ムの基本構造を示し,続く 12.3 節で 1 次元問題における要素形状関数行列とそ

の微分である B マトリクスを評価して返す関数,およびガウス積分のためのデ

ータを返す関数を示した.本節では 1 次元問題に対する汎用的な有限要素プログ

ラムについて説明し,例 5.2 の問題(2 次要素で 2 要素分割)を解く.このプロ

グラムは 2 次元定常熱伝導問題に対する有限要素プログラム(12.5 節)や,2 次

元弾性問題に対する有限要素プログラム(12.6 節)と本質的に同一である. 境界条件を課す各種の方法を 2 章で述べたが,分割法による場合には説明を簡

単にするため,変位が既知である E 節点に全体系の節点番号を優先的に付ける

規則を設けた.しかしながら,メッシュ生成プログラム(mesh genetator)には全体

系の節点番号や要素番号のつけ方にこのような規則がないばかりでなく,連立 1次方程式を 大限に効率よく解くための番号づけを別に行うことが普通である.

そこで,以降で示すプログラムでは自然境界(natural boundary)上の F 節点

(Free nodes)に flag=1,基本境界上(essesntial boundary)の E 節点(Essential nodes)に flag=2 として両者を区別したうえで,setup_ID_LM という関数を用い

29

て,改めて E 節点から優先的に全体系の節点番号を付ける.この結果を 2 次元

配列 ID と LM に記憶しておく.なお,本節で示す 1 次元弾性問題の有限要素プ

ログラムは,わずかの修正で定常熱伝導問題の有限要素プログラムへと変更でき

る. 各 m-file の詳細な説明は,プログラムへのコメントとして書き込んである.ま

た,前節までと定義が異なる変数のみ次に説明する.m-file のほとんどは,12.2節のものと同一であるか非常に似たものである.

12.4.1 変数の説明

ユーザが値を指定しなければならない変数

nd: 基本境界上の節点(E節点)数 ngp: ガウス積分点数(number of Gauss points) body: 節点における体積力(body force)用の1次元配列 ― 要素内の体積力は要

素形状関数を用いて節点における体積力で補間される. E: 節点におけるヤング率(Young’s modulus)E 用の1次元配列 CArea: 節点における断面積(cross-sectional area)用の1次元配列 flags: 基本境界上の節点と自然境界上の節点を判別するための1次元配列 用法:(フラグ値) = flags((付替え前の全体系の節点番号)) フラグ値:自然境界上のとき 1,基本境界上のとき2 x: 節点のx座標値(nodal x-coordinates)用の1次元配列 y: 節点のy座標値(nodal y-coordinates)用の1次元配列(可視化用) e_bc: 基本境界条件(essential boundary conditions )の節点変位(既知)もしく

は節点温度(既知)用の1次元配列 n_bc: 自然境界条件(natural boundary conditions)の節点外力(既知)もしくは

点熱源(既知)用の1次元配列 P: 要素内の点荷重もしくは点熱源(point forces (point sources))用の1次元配列 xp: 点荷重を作用させるx座標値(x-coordinates for point force)用の1次元配列

np: 点荷重もしくは点熱源の数(number of point forces (point sources)) nplot: 変位と応力もしくは温度と熱流束を描画するための標本点数 IEN: 要素に関する局所的な節点番号を付替え前の全体系の節点番号に変換する

ための2次元配列(information of element nodes)(のちほど,setup_ID_LM を用いてE節点から優先して全体系の節点番号を付け直す)

用法:(付替え前の全体系の自由度番号) = LM ((局所的な自由度番号) , (要素番号e))

プログラム中で計算に使用する変数

ID: 全体系の節手番号について付替え前の番号から付替え後の番号に変換する

ための1次元配列(information of destinations) 用法:(付替え後の全体系の節点番号) =

30

ID((付替え前の全体系の節点番号)) LM: 要素に関する局所的な節点番号を付替え後の全体系の節点番号に変換する

ための2次元配列(location matrix) 用法:(付替え後の全体系の節点番号) = LM ((局所的な節点番号) , (要素番号e))

注)LMとIENの関係 LM( I, e ) = ID( IEN( I, e ) )

12.4.2 1 次元問題の MATLAB 有限要素プログラム

bar1D.m %%%%%%%%%%%%%%%%%%%%%%%%% % 1次元棒問題の有限要素プログラム (5章) % % Haim Waisman, Rensselaer % %%%%%%%%%%%%%%%%%%%%%%%%% clear all; close all; % グローバル変数のインクルード include_flags; % プリプロセス [K,f,d] = preprocessor; % 要素剛性行列と要素体積力行列の計算と,全体剛性行列と全体外力行列の組立 for e = 1:nel [ke,fe] = barelem(e); [K, f] = assembly(K,f,e,ke,fe); end % 節点外力を全体外力行列に考慮 f = NaturalBC(f); % 連立1次方程式の求解 [d,f_E] = solvedr(K,f,d); % ポストプロセス postprocessor(d); % 厳密解の描画 ExactSolution; include_flags.m % グローバル変数の宣言 global nsd ndof nnp nel nen neq nd CArea E

31

global flags ID IEN LM body x y global xp P ngp xplot n_bc e_bc np global plot_bar plot_nod nplot preprocessor.m % プリプロセス ― 計算に必要な入力データと要素分割の設定 function [K,f,d] = preprocessor; include_flags; % 入力データのインクルード input_file5_2_2ele; %input_file5_2_1ele; %input_file5_2_4ele; % ID配列とLM配列の作成 d = setup_ID_LM(d);

input_file5_2_2ele.m % 例5.2(2要素)の入力データを設定するスクリプト nsd = 1; % 空間の次元数(number of space dimensions ) ndof = 1; % 節点あたりの自由度数(number of degrees-of-freedom per node) nnp = 5; % 節点数(number of nodal points) nel = 2; % 要素数(number of elements) nen = 3; % 要素節点数(number of element nodes) neq = ndof*nnp; % 方程式の本数(number of equations) f = zeros(neq,1); % 全体外力行列の宣言 d = zeros(neq,1); % 全体変位行列の宣言 K = zeros(neq); % 全体剛性行列の宣言 flags = zeros(neq,1); % 節点に課される境界条件を区別するためのフラグの宣言 e_bc = zeros(neq,1); % 基本境界(essential B.C.)上の既知の節点変位用配列の宣言 n_bc = zeros(neq,1); % 自然境界(natural B.C.)上の既知の節点外力用配列の宣言 % 要素特性(要素節点で定義されることに注意) E = 8*ones(nnp,1); % ヤング率の節点値 body = 8*ones(nnp,1); % 体積力(body force)の節点値 CArea = [4 7 10 11 12]'; % 断面積(cross-sectional area)の節点値 % ガウス積分 ngp = 2; % ガウス積分点数 % 基本境界条件 flags(1) = 2; % 全体系の節点1が基本境界上にあることのフラグ

32

e_bc(1) = 0; % 基本境界条件の値(既知の変位) nd = 1; % 基本境界上のE節点の数 % 自然境界条件 flags(5) = 1; % 全体系の節点5が自然境界上にあることのフラグ n_bc(5) = 0; % 自然境界条件の値(既知の外力) % 要素内の点荷重 P = 24; % 点荷重(point forces) xp = 5; % 点荷重を作用させるx座標値(x-coordinates for point forces) np = 1; % 点荷重の数(number of point forces) % 計算結果の可視化フラグ plot_bar = 'yes'; plot_nod = 'yes'; nplot = nnp*10; % 変位と応力の分布を描画するための標本点数 % 要素分割 bar_mesh5_2_2ele;

bar_mesh5_2_2ele.m function bar_mesh5_2_2ele include_flags; % 節点: 1 2 3 4 5 x = [2.0 3.5 5.0 5.5 6.0 ]; % x 座標 y = 2*x; % y 座標(計算ではなくMATLAB関数のbarplotによる可視化用) % 要素に関する局所的な節点番号を付替え前の全体系の節点番号に変換するための2次元配列 IEN = [ 1 3 2 4 3 5]; plotbar;

setup_ID_LM.m % ID 配列とLM 配列の作成 function d = setup_ID_LM(d); include_flags; count = 0; count1 = 0; for i = 1:neq if flags(i) == 2 % 基本境界条件のとき count = count + 1; ID(i) = count; % 基本境界上のE節点から優先的に全体系の節点番号を付与 d(count)= e_bc(i); % 基本境界条件の値(既知の変位)を全体変位行列に格納 else

33

count1 = count1 + 1; ID(i) = nd + count1; end end for i = 1:nel for j = 1:nen LM(j,i)=ID(IEN(j,i)); % LM配列の作成 end end

barelem.m % 要素剛性行列と要素体積力行列を作成 function [ke, fe] = barelem(e); include_flags; IENe = IEN(:,e); % 要素eが接続する全体系の節点番号を準備 xe = x(IENe); % 要素節点のx座標を「収集」 J = (xe(nen) - xe(1))/2; % ヤコビ行列(Jacobian matrix)の行列式の計算 [w , gp] = gauss(ngp); % ガウス積分点(親座標系)と重みを 準備 ke = zeros(nen,nen); % 要素剛性行列の初期化 fe = zeros(nen,1); % 要素体積力行列の初期化 for i = 1:ngp xt = 0.5*(xe(1)+xe(nen))+J*gp(i); % ガウス積分点を物理座標系に変換 N = Nmatrix1D(xt,xe); % 要素形状関数行列をガウス積分点で評価 B = Bmatrix1D(xt,xe); % Bマトリクス 〃 Ae = N*CArea(IENe); % ガウス積分点における断面積 Ee = N*E(IENe); % 〃 ヤング率 be = N*body(IENe); % 〃 体積力 ke = ke + w(i)*(B'*Ae*Ee*B); % 積分点における評価値に重みを乗じて加算 fe = fe + w(i)*N'*be; % 〃 end ke = J*ke; fe = J*fe; % 要素内に点荷重がある場合の処理 for i=1:np % 点荷重の数だけループ Pi = P(i); % 点荷重を準備 xpi = xp(i); % 点荷重の位置を準備 if xe(1)<=xpi & xpi<xe(nen) % 点荷重が要素内部に位置するとき fe = fe + Pi*[Nmatrix1D(xpi,xe)]'; % 点荷重Piを考慮して要素体積力行列に加算 end end

34

assembly.m % 「直接的な組立」により要素行列から全体行列をアセンブリ function [K,f] = assembly(K,f,e,ke,fe) include_flags; for loop1 = 1:nen i = LM(loop1,e); f(i) = f(i) + fe(loop1); % 要素体積力行列feの各成分を全体外力行列の対応位置に加算 for loop2 = 1:nen j = LM(loop2,e); K(i,j) = K(i,j) + ke(loop1,loop2); % 要素剛性行列Keの各成分を全体剛性行列の対応位置に加算 end end

naturalBC.m % 節点外力を全体外力行列に考慮 function f = naturalBC(f); include_flags; for i = 1:nnp if flags(i) == 1 node = ID(i); f(node) = f(node) + CArea(node)*n_bc(node); end end

postprocessor.m % ポストプロセス function postprocessor(d) include_flags; fprintf(1,'\n Print stresses at the Gauss points \n') fprintf(1,'Element\t\t x(gauss1) \t\t x(gauss2) \t\t stress(gauss1) \t\t stress(gauss2)\n') fprintf(1,'--------------------------------------------------------------------------------- \n') % 要素ごとの変位と応力を算出して出力 for e = 1:nel disp_and_stress(e,d); end disp_and_stress.m % 要素の変位と応力を評価 function disp_and_stress(e,d) include_flags; de = d(LM(:,e)); % 全体変位行列dから要素変位行列deを「収集」 IENe = IEN(:,e); % 要素eが接続する全体系の節点番号を準備 xe = x(IENe); % 要素節点のx座標を「収集」

35

J = (xe(nen) - xe(1))/2; % ヤコビ行列(Jacobian matrix)の行列式の計算 [w , gp] = gauss(ngp); % ガウス積分点(親座標系)と重みを準備 % ガウス積分点で応力を評価 for i = 1:ngp xt = 0.5*(xe(1)+xe(nen))+J*gp(i); % ガウス積分点を物理座標系に変換 gauss_pt(i) = xt; % ガウス積分点を格納 N = Nmatrix1D(xt,xe); % 要素形状関数行列をガウス積分点で評価 B = Bmatrix1D(xt,xe); % Bマトリクス 〃 Ee = N*E(IENe); % ガウス積分点におけるヤング率 stress_gauss(i) = Ee*B*de; % 〃 応力 end % 要素内のガウス積分点における応力をコマンドウィンドウに出力fprintf(1,'%d\t\t\t%f\t\t\t%f\t\t\t%f\t\t\t%f\n',e,gauss_pt(1),gauss_pt(2),stress_gauss(1),stress_gauss(2)); % 要素内の標本点で変位と応力を評価 xplot = linspace(xe(1),xe(nen),nplot); % linspace命令により要素内で等間隔な点列を作成 for i = 1:nplot xi = xplot(i); % x座標点 N = Nmatrix1D(xi,xe); % 要素形状関数行列をこの点xiで評価 B = Bmatrix1D(xi,xe); % Bマトリクス 〃 Ee = N*E(IENe); % ヤング率 displacement(i) = N*de; %変位を計算し格納 stress(i) = Ee*B*de; %応力 〃 end % 変位と応力の分布を描画 figure(2) subplot(2,1,1); plot(xplot,displacement); legend('sdf'); hold on; ylabel('displacement'); title('FE analysis of 1D bar'); subplot(2,1,2); plot(xplot,stress); hold on; ylabel('stress'); xlabel('x'); legend('FE');

ExactSolution.m % 厳密解による変位と応力の分布を描画 function ExactSolution include_flags; % 問題領域をxaとxbの2区間に分割 xa = 2:0.01:5; xb = 5:0.01:6;

36

subplot(2,1,1); % 区間xaにおける厳密解(変位) c1 = 72; c2 = 1 - (c1/16)*log(2); u1 = -.5*xa + (c1/16)*log(xa) + c2; % 区間xbにおける厳密解(変位) c3 = 48; c4 = log(5)/16*(c1-c3) + c2; u2 = -.5*xb + (c3/16)*log(xb) + c4; % 変位の描画 h = plot([xa xb],[u1 u2], '--r' ); legend(h,'exact'); subplot(2,1,2); % 区間xaにおける厳密解(応力) ya = (36-4*xa)./xa; % 区間xbにおける厳密解(応力) yb = (24-4*xb)./xb; % 応力の描画 plot([xa xb],[ya yb], '--r' ); 既出の関数 ・4 章:Nmatrix1D.m, Bmatrix1D.m, gauss.m ・2 章:solvedr.m

12.5 MATLAB による 2 次元定常熱伝導問題の有限要素プログラミング

これまでにトラス問題の問題と汎用的な 1 次元問題に対する有限要素プログラ

ムを示したが,本節では定常熱伝導を例とした 2 次元スカラー変数場問題に対す

る有限要素プログラムについて説明する.このプログラムは前節の 1 次元問題に

対するプログラムとほぼ同じであるので,各 m-file の説明は簡略化する. 主プログラム: heat2D.m 有限要素プログラム heat2D.m は次のステップから構成されている.

- プリプロセス - 要素熱伝導行列と要素熱源流束行列の計算と,全体熱伝導行列と全体

流束行列の組立 - 節点への点熱源と境界熱流束を全体流束行列に考慮 - 連立 1 次方程式の求解 - ポストプロセス

heat2d.m %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 2次元定常熱伝導問題の有限要素プログラム(8章) % % Haim Waisman, Rensselaer % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

37

clear all; close all; % グローバル変数のインクルード include_flags; % プリプロセス [K,f,d] = preprocessor; % 要素熱伝導行列と要素熱源流束行列の計算と,全体熱伝導行列と全体流束行列の組立 for e = 1:nel [ke, fe] = heat2Delem(e); [K,f] = assembly(K,f,e,ke,fe); end % 節点への点熱源と境界熱流束を全体流束行列に考慮 f = src_and_flux(f); % 連立1次方程式の求解 [d,f_E] = solvedr(K,f,d); % ポストプロセス postprocessor(d); プリプロセス: preprocessor.m プリプロセス部の下位にある入力スクリプト input_file_*.m はユーザが変数の

値を指定するものであり,材料特性,要素分割,行列の初期化,基本境界条件と

自然境界条件,点熱源,出力すべき値の指定が必要である.今回のプログラムで

は,境界熱流束の値を要素節点で指定することにより,要素形状関数を用いてメ

ッシュ境界に沿って補間できる.具体的には 2 次元配列 n_bc を用いてこれを行

う.たとえば,図 8.9 に示す例 8.1(16 個の 2 次要素)では n_bc を次のように指

定する.

21 22 23 2422 23 24 25

_20.0 20.0 20.0 20.020.0 20.0 20.0 20.0

n bc

⎡ ⎤⎢ ⎥⎢ ⎥=⎢ ⎥⎢ ⎥⎣ ⎦

この配列の各列はメッシュの自然境界上の 1 辺に対応する.各列の 1 行目と 2 行

目にそれぞれ辺の第 1 節点と第 2 節点が接続している全体系の節点番号を指定す

る.また,3 行目と 4 行目にそれぞれの節点における境界熱流束の値を指定する.

このような仕様のため,要素境界において不連続な境界熱流束も指定できる.こ

の例では,境界熱流束を既定するメッシュ辺の数(nbe とする)は nbe=4 である.

38

なお,1 要素の場合と 64 要素の場合の入力スクリプトファイルは web からダウ

ンロードできる. また,要素分割で IEN を指定してから作業配列 ID, LM を作成する.要素分割

を行うユーザ定義の MATLAB 関数 mesh2d.m では MATLAB の linspace 命令によ

り具体的に要素分割を行う.

preprocessor.m function [K,f,d] = preprocessor; include_flags; % 入力データのインクルード %input_file_1ele; input_file_16ele; %input_file_64ele; % ID 配列とLM 配列の作成 d = setup_ID_LM(d);

input_file_16ele.m % 例8.1(16要素)の入力データを設定するスクリプト % 材料特性 k = 5; % 熱伝導率κ(thermal conductivity) D = k*eye(2); % 熱伝導行列D(conductivity matrix) % メッシュに関して nsd = 2; % 空間の次元数(number of space dimensions) nnp = 25; % 節点数(number of nodes) nel = 16; % 要素数(number of elements) nen = 4; % 要素節点数(number of element nodes ) ndof = 1; % 節点あたりの自由度数(number of degrees-of-freedom per node) neq = nnp*ndof; % 方程式の本数(number of equations) f = zeros(neq,1); % 全体流束行列の初期化 d = zeros(neq,1); % 全体温度行列の初期化 K = zeros(neq); % 全体熱伝導行列の初期化 flags = zeros(neq,1); % 節点に課される境界条件を区別するためのフラグの宣言 e_bc = zeros(neq,1); % 基本境界(essential B.C)上の既知の節点温度用配列の宣言 n_bc = zeros(neq,1); % 自然境界(natural B.C)上の既知の熱流束(節点値)用配列の宣言 P = zeros(neq,1); % 節点への点熱源用配列の宣言 s = 6*ones(nen,nel); % 熱源(heat source)の節点値 ngp = 2; % 次元あたりのガウス積分点数 % 基本境界条件

39

flags(1:5) = 2; e_bc(1:5) = 0.0; flags(6:5:21) = 2; e_bc(6:5:21) = 0.0; nd = 9; % 基本境界上のE節点の数 % 計算結果の可視化フラグ compute_flux = 'yes'; plot_mesh = 'yes'; plot_nod = 'yes'; plot_temp = 'yes'; plot_flux = 'yes'; % 自然境界条件 ― 自然境界上のF節点で定義 n_bc = [ 21 22 23 24 % メッシュ辺の第1節点が接続する全体系の節点番号 22 23 24 25 % 〃 2 〃 20 20 20 20 % 第1節点における熱流束の節点値 20 20 20 20 ]; % 2 〃 nbe = 4; % 自然境界条件を既定するメッシュ辺の数 % 要素分割 mesh2d;

mesh2d.m function mesh2d; include_flags; lp = sqrt(nnp); % x, y方向の節点数(次元あたりの節点数が同じ場合に限定) x0 = linspace(0,2,lp); % 等分割のx座標 y0 = 0.5*x0/2; %底辺のx0に対応するy座標 x = []; for i = 1:lp x = [x x0]; % x座標の再帰的な定義 y1 = linspace(y0(i),1,lp); y(i:lp:lp*(lp-1)+i) = y1; end % 要素に関する局所的な節点番号を付替え前の全体系の節点番号に変換するための2次元配列 rowcount = 0; for elementcount = 1:nel IEN(1,elementcount) = elementcount + rowcount; IEN(2,elementcount) = elementcount + 1 + rowcount; IEN(3,elementcount) = elementcount + (lp + 1) + rowcount; IEN(4,elementcount) = elementcount + (lp) + rowcount; If mod(elementcount,lp-1) == 0 rowcount = rowcount + 1; end end % 要素分割と自然境界の描画 plotmesh;

40

plotmesh.m function plotmesh; include_flags; if strcmpi(plot_mesh,'yes')==1; % 自然境界の描画 for i=1:nbe node1 = n_bc(1,i); % 第1節点 node2 = n_bc(2,i); % 第2節点 x1 = x(node1); y1=y(node1); % 第1節点の(x,y)座標 x2 = x(node2); y2=y(node2); % 第2節点の(x,y)座標 plot([x1 x2],[y1 y2],'r','LineWidth',4); hold on end legend('natural B.C. (flux)'); for i = 1:nel XX = [x(IEN(1,i)) x(IEN(2,i)) x(IEN(3,i)) x(IEN(4,i)) x(IEN(1,i))]; YY = [y(IEN(1,i)) y(IEN(2,i)) y(IEN(3,i)) y(IEN(4,i)) y(IEN(1,i))]; plot(XX,YY);hold on; if strcmpi(plot_nod,'yes')==1; text(XX(1),YY(1),sprintf('%0.5g',IEN(1,i))); text(XX(2),YY(2),sprintf('%0.5g',IEN(2,i))); text(XX(3),YY(3),sprintf('%0.5g',IEN(3,i))); text(XX(4),YY(4),sprintf('%0.5g',IEN(4,i))); end end end fprintf(1,' Mesh Params \n'); fprintf(1,'No. of Elements %d \n',nel); fprintf(1,'No. of Nodes %d \n',nnp); fprintf(1,'No. of Equations %d \n\n',neq);

include_flags.m % グローバル変数の宣言 global ndof nnp nel nen nsd neq ngp nee neq global nd e_bc s P D global LM ID IEN flags n_bc global x y nbe global compute_flux plot_mesh plot_temp plot_flux plot_nod

要素熱伝導行列と要素熱源流束行列の計算: heat2Delem.m この MATLAB 関数は,親領域でガウス積分することにより 4 節点四辺形要素

に対する要素熱伝導行列と要素境界流束行列を計算する.要素形状関数行列は

41

Nmatheat2D.m で,対応する B マトリクスはヤコビ行列とその行列式を含めて

Bmatheat2D.m で評価する.また,熱源は要素節点における値を指定することに

より要素内で補間される.

heat2Delem.m % 4節点四辺形要素に対する要素熱伝導行列と要素熱源流束行列の計算 function [ke, fe] = heat2Delem(e) include_flags; ke = zeros(nen,nen); % 要素熱伝導行列の初期化 fe = zeros(nen,1); % 要素熱源流束行列の初期化 % 要素節点座標の「収集」 je = IEN(:,e); C = [x(je); y(je)]'; [w,gp] = gauss(ngp); % ガウス積分点(親座標系)と重みを準備 % 要素熱伝導行列と要素熱源流束行列の計算 for i=1:ngp for j=1:ngp eta = gp(i); psi = gp(j); N = NmatHeat2D(eta,psi); % 要素形状関数行列をガウス積分点(親座標系)で評価 [B, detJ] = BmatHeat2D(eta,psi,C); % Bマトリクス 〃 ke = ke + w(i)*w(j)*B'*D*B*detJ; % 積分点における評価値に重みを乗じて加算 se = N*s(:,e); % 熱源s(x)の補間 fe = fe + w(i)*w(j)*N'*se*detJ; % 積分点における評価値に重みを乗じて加算 end end

NmatHeat2D.m % 要素形状関数行列を親座標系で評価 function N = NmatHeat2D(eta,psi) N = 0.25 * [(1-psi)*(1-eta) (1+psi)*(1-eta) (1+psi)*(1+eta) (1-psi)*(1+eta)];

BmatHeat2D.m % Bマトリクス(形状関数の微分)を親座標系で評価 function [B, detJ] = BmatHeat2D(eta,psi,C) % 勾配行列の計算 GN = 0.25 * [eta-1 1-eta 1+eta -eta-1; psi-1 -psi-1 1+psi 1-psi];

42

J = GN*C; % ヤコビ行列 detJ = det(J); % その行列値 B = J\GN; % Bマトリクスの算出 節点への点熱源と境界熱流束の考慮: src_and_flux.m この MATLAB 関数は,節点への点熱源 P と境界熱流束による分を計算して全

体流束行列の該当成分に加算する.境界熱流束による熱流束行列を計算するには,

境界熱流束を設定したメッシュ辺(辺数は nbe)についてループを回して,各辺

でその両端における境界熱流束の値(2 次元配列 n_bc に格納)を用いて辺上で

補間し 1 次元のガウス積分を行う.なお,ガウス積分を行うときには,各辺を親

座標で考える.各辺の熱流束行列は,配列 ID を用いて全体系の節点番号を付替

え前の番号から付替え後の番号に変換することで,全体流束行列にアセンブリで

きる.本書では,式(8.11)に示すように fΓにはマイナス符号が付くので注意する

こと.

src_and_flux.m % 節点への点熱源と各辺の境界熱流束行列を計算し,全体流束行列を組立 function f = src_and_flux(f); include_flags; % 節点への点熱源を全体流束行列の該当成分に加算 f(ID) = f(ID) + P(ID); % 各辺の境界熱流束行列を計算 for i = 1:nbe fq = [0 0]'; % 各辺の境界熱流束行列の初期化 node1 = n_bc(1,i); % 辺の第1節点を準備 node2 = n_bc(2,i); % 〃 2 〃 n_bce = n_bc(3:4,i); % 両節点における境界熱流束の値を準備 x1 = x(node1); y1 = y(node1); % 第1節点の(x,y)座標 x2 = x(node2); y2 = y(node2); % 第2節点 〃 leng = sqrt((x2-x1)^2 + (y2-y1)^2); % 辺長(length of an edge) J = leng/2; % ヤコビ行列の行列式 [w,gp] = gauss(ngp); % ガウス積分点(親座標系)と重みを準備 for i=1:ngp % 辺上で1次元のガウス積分 psi = gp(i); % 積分点(親座標系) N = 0.5*[1-psi 1+psi]; % 〃 における1次元の形状関数行列の値 flux = N * n_bce; % 形状関数を用いて境界熱流束を補間 fq = fq + w(i)*N' *flux*J; % 積分点における評価値に重みを乗じて加算

43

end fq = -fq; % 境界熱流束行列の定義により符号を反転 % 各辺の境界熱流束行列を全体流束行列の該当成分に加算 f(ID(node1)) = f(ID(node1)) + fq(1) ; f(ID(node2)) = f(ID(node2)) + fq(2); end ポストプロセス: postprocessor.m この関数は有限要素プログラムの 後に実行され,図 8.10 から 8.12 に示す図

を描画する.

postprocess.m % 温度と熱流束の可視化 function postprocess(d); include_flags % 温度場を描画 if strcmpi(plot_temp,'yes') == 1; d1 = d(ID); figure(2); for e = 1:nel XX = [x(IEN(1,e)) x(IEN(2,e)) x(IEN(3,e)) x(IEN(4,e)) x(IEN(1,e))]; YY = [y(IEN(1,e)) y(IEN(2,e)) y(IEN(3,e)) y(IEN(4,e)) y(IEN(1,e))]; dd = [d1(IEN(1,e)) d1(IEN(2,e)) d1(IEN(3,e)) d1(IEN(4,e)) d1(IEN(1,e))]; patch(XX,YY,dd);hold on; end title('Temperature distribution'); xlabel('X'); ylabel('Y'); colorbar; end % ガウス積分点における熱流束を評価し,コマンドウィンドウに出力するとともに描画 if strcmpi(compute_flux,'yes')==1; fprintf(1,'\n Heat Flux at Gauss Points \n') fprintf(1,'----------------------------------------------------------------------------- \n') for e = 1:nel fprintf(1,'Element %d \n',e) fprintf(1,'-------------\n') get_flux(d,e); end end

get_flux.m function get_flux(d,e); include_flags; de = d(LM(:,e)); % 要素節点における温度(要素温度行列)を「収集」

44

% 要素節点の座標を準備 je = IEN(:,e); C = [x(je); y(je)]'; [w,gp] = gauss(ngp); % ガウス積分点(親座標系)と重みを準備 % 熱流束ベクトルの計算 ind = 1; for i=1:ngp for j=1:ngp eta = gp(i); psi = gp(j); N = NmatHeat2D(eta,psi); [B, detJ] = BmatHeat2D(eta,psi,C); X(ind,:) = N*C; % ガウス積分点を物理座標系に変換 q(:,ind) = -D*B*de; % 〃 における熱流束ベクトルの計算 ind = ind + 1; end end q_x = q(1,:); q_y = q(2,:); % #x-coord y-coord q_x(eta,psi) q_y(eta,psi) flux_e1 = [X(:,1) X(:,2) q_x' q_y']; fprintf(1,'\t\t\tx-coord\t\t\t\ty-coord\t\t\t\tq_x\t\t\t\t\tq_y\n'); fprintf(1,'\t\t\t%f\t\t\t%f\t\t\t%f\t\t\t%f\n',flux_e1'); if strcmpi(plot_flux,'yes')==1 & strcmpi(plot_mesh,'yes') ==1; figure(1); quiver(X(:,1),X(:,2),q_x',q_y','k'); plot(X(:,1),X(:,2),'rx'); title('Heat Flux'); xlabel('X'); ylabel('Y'); end 既出の関数 ・5 章: setup_ID_LM.m, assembly.m, solvedr.m

12.6 MATLAB による 2 次元弾性問題の有限要素プログラミング 本節では,2 次元線形弾性体に対する有限要素プログラムについて説明する.

ここでは 4 節点四辺形要素についてのみプログラムを示すので,問題 9.6 と 9.7の 3 節点三角形要素と 6 節点三角形要素については各自でプログラムを作成する

こと. 主プログラム: elasticity2D.m 有限要素プログラム elasticity2D.m は次のステップから構成されている.

45

- プリプロセス - 要素剛性行列と要素体積力行列の計算と,全体剛性行列と全体外力行

列の組立 - 節点外力(点荷重)と表面力を全体外力行列に考慮 - 連立 1 次方程式の求解 - ポストプロセス

elasticity2D.m %%%%%%%%%%%%%%%%%%%%%%%%%%% % 2次元弾性問題の有限要素プログラム (9章) % % Haim Waisman, Rensselaer % %%%%%%%%%%%%%%%%%%%%%%%%%%% clear all; close all; % グローバル変数のインクルード include_flags; % プリプロセス(上位関数は8章と同一で,下位は8章と類似) [K,f,d] = preprocessor; % 要素剛性行列と要素体積行列の計算と,全体剛性行列と全体外力行列の組立 for e = 1:nel [ke, fe] = elast2Delem(e); [K,f] = assembly(K,f,e,ke,fe); % (8章と同一) end % 節点外力(点荷重)と表面力を全体外力行列に考慮 f = point_and_trac(f); % 連立1次方程式の求解(8章と同一) [d,r] = solvedr(K,f,d); % ポストプロセス(8章と類似) postprocessor(d); プリプロセス中の入力データ: input_file.m

2 次元配列 n_bc に自然境界条件のデータを格納するが,たとえば例 9.3(16 要

素)の場合では n_bc を次のように指定する.

46

21 22 23 2422 23 24 250.0 0.0 0.0 0.0

_20.0 20.0 20.0 20.00.0 0.0 0.0 0.020.0 20.0 20.0 20.0

n bc

⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥

= ⎢ ⎥− − − −⎢ ⎥⎢ ⎥⎢ ⎥− − − −⎢ ⎥⎣ ⎦

前節と同様,この配列の各列はメッシュの自然境界上の 1 辺に対応し,各列の第

1 行目と 2 行目にそれぞれ辺の第 1 節点と第 2 節点が接続している全体系の節手

番号を指定する.第 3 行目と第 4 行目に第 1 節点における表面力の x 成分と y 成

分を,第 5 行目と第 6 行目に第 2 節点における表面力の x 成分と y 成分を指定す

る.この例では,表面力を既定するメッシュ辺の数(nbe)は再び nbe=4 である.

なお,1 要素と 64 要素の場合の入力スクリプトファイルは web からダウンロー

ドできる.

input_file_16ele.m % 例9.3(16要素)の入力データを設定するスクリプト % 材料特性 E = 30e6; % ヤング率(Young’s modulus ) ne = 0.3; % ポアソン比(Poisson’s ratio ) D = E/(1-ne^2) * [ 1 ne 0 % 平面応力状態の弾性行列(Hooke’s law) ne 1 0 0 0 (1-ne)/2]; % メッシュに関して nsd = 2; % 空間の次元数(number of space dimensions) nnp = 25; % 節点数(number of nodal nodes) nel = 16; % 要素数(number of elements) nen = 4; % 要素節点数(number of element nodes ) ndof = 2; % 節点あたりの自由度数(degrees-of-freedom per node) neq = nnp*ndof; % 方程式の本数(number of equations)or 全体系の自由度数 f = zeros(neq,1); % 全体外力行列の初期化 d = zeros(neq,1); % 全体変位行列の初期化 K = zeros(neq); % 全体剛性行列の初期化 counter = zeros(nnp,1); % 節点における応力を評価するための節点数カウンタ nodestress = zeros(nnp,3); % 〃 節点値 [sxx syy sxy] flags = zeros(neq,1); % 自由度に課される境界条件を区別するためのフラグの宣言 e_bc = zeros(neq,1); % 基本境界(essential B.C)上の既知の節点変位用配列の宣言 n_bc = zeros(neq,1); % 自然境界(natural B.C)上の表面力(節点値)用配列の宣言 P = zeros(neq,1); % 節点外力(点荷重)

47

b = zeros(nen*ndof,nel); % 体積力(body force)の節点値 ngp = 2; % 次元あたりのガウス積分点数 nd = 10; % 基本境界上の自由度の数( 節点あたりx とyの2自由度) % 基本境界条件 ― 基本境界上のE節点で定義 ind1 = 1:10:(21-1)*ndof+1; % y=0 線上の全x自由度 ind2 = 2:10:(21-1)*ndof+2; % x=0 〃 y 〃 flags(ind1) = 2; e_bc(ind1) = 0.0; flags(ind2) = 2; e_bc(ind2) = 0.0; % 計算結果の可視化フラグ compute_stress = 'yes'; plot_mesh = 'yes'; % (8章と同一) plot_nod = 'yes'; plot_disp = 'yes'; plot_stress = 'yes'; plot_stress_xx = 'yes'; plot_mises = 'yes'; fact = 9.221e3; % 変位を描画するための変位の誇張倍率 % 自然境界条件 ― 自然境界上のF節点で定義 n_bc = [ 21 22 23 24 % メッシュ辺の第1節点が接続する全体系の節点番号 22 23 24 25 % 〃 2 〃 0 0 0 0 % 節点1における表面力のx成分(節点値 ) -20 -20 -20 -20 % 〃 y 〃 0 0 0 0 % 節点2における表面力のx成分(節点値 ) -20 -20 -20 -20]; % 〃 y 〃 nbe = 4; % 自然境界条件を既定するメッシュ辺の数 % 要素分割 mesh2d;

include_flags.m % グローバル変数の宣言 global ndof nnp nel nen nsd neq ngp nee neq global nd e_bc P b D global LM ID IEN flags n_bc global x y nbe counter nodestress global compute_stress plot_mesh plot_disp plot_nod global plot_stress_xx plot_mises fact プリプロセス中の節点番号の付替え: setup_ID_LM.m

ID 配列の作成は,nd が基本境界上の自由度数を表していることを除けば,定

常熱伝導問題の場合と同じである.LM 配列は全体系の自由度番号について付替

え前の番号から付替え後の番号に変換するものである.このため,各節点を 2 自

48

由度のブロックとして取扱う.各ブロックの開始位置を blk で指定して,そのブ

ロック内で各自由度についてループを回す.

setup_ID_LM.m function d=setup_ID_LM(d); include_flags; count = 0; count1 = 0; for i = 1:neq if flags(i) == 2 % 基本境界条件のとき count = count + 1; ID(i) = count; % 基本境界上の自由度から優先的に全体系の自由度番号を付与 d(count)= e_bc(i); % 基本境界条件の値(既知の変位 (x or y方向) を全体変位行列に格納) else count1 = count1 + 1; ID(i) = nd + count1; end end for i = 1:nel n = 1; for j = 1:nen blk = ndof*(IEN(j,i)-1); for k = 1:ndof LM(n,i) = ID( blk + k ); % LM配列の作成 n = n + 1; end end end 要素剛性行列と要素体積力行列の計算: elast2Delem.m この MATLAB 関数は,要素剛性行列と要素体積力行列をガウス積分により数

値的に評価するものであり,要素形状関数行列を評価する関数 NmatElast2D.m と

B マトリクスを評価する関数 BmatElast2D.m を除けば,2 次元定常熱伝導の場合

と同じである.

elast2Delem.m function [ke, fe] = elast2Delem(e) include_flags; ke = zeros(nen*ndof,nen*ndof); % 要素剛性行列の初期化 fe = zeros(nen*ndof,1); % 要素体積力行列の初期化 % 要素節点座標の「収集」 je = IEN(:,e); C = [x(je); y(je)]'; [w,gp] = gauss(ngp); % ガウス積分点(親座標系)と重みを準備

49

% 要素剛性行列と要素体積力行列の計算 for i=1:ngp for j=1:ngp eta = gp(i); psi = gp(j); N = NmatElast2D(eta,psi); % 要素形状関数行列をガウス点(親座標系)で評価 [B, detJ] = BmatElast2D(eta,psi,C); % Bマトリクス 〃 ke = ke + w(i)*w(j)*B'*D*B*detJ; % 積分点における評価値に重みを乗じて加算 be = N*b(:,e); % 体積力の補間 fe = fe + w(i)*w(j)*N'*be*detJ; %積分点における評価値に重みを乗じて加算 end end

NmatElas2D.m % 2次元弾性問題用の要素形状関数行列を親座標系で評価 function N = NmatElast2D(eta,psi) N1 = 0.25*(1-psi)*(1-eta); N2 = 0.25*(1+psi)*(1-eta); N3 = 0.25*(1+psi)*(1+eta); N4 = 0.25*(1-psi)*(1+eta); N = [N1 0 N2 0 N3 0 N4 0; % 要素形状関数行列 0 N1 0 N2 0 N3 0 N4];

BmatElas2D.m % 2次元弾性問題用のBマトリクスを親座標系で評価 function [B, detJ] = BmatElast2D(eta,psi,C) % 勾配行列の計算 GN = 0.25 * [eta-1 1-eta 1+eta -eta-1; psi-1 -psi-1 1+psi 1-psi]; J = GN*C; % ヤコビ行列 detJ = det(J); % その行列値 BB = J\GN; % 親座標系で要素形状関数の物理座標系における微分値を計算 B1x = BB(1,1); B2x = BB(1,2); B3x = BB(1,3); B4x = BB(1,4); B1y = BB(2,1); B2y = BB(2,2); B3y = BB(2,3); B4y = BB(2,4); B = [ B1x 0 B2x 0 B3x 0 B4x 0 ;

50

0 B1y 0 B2y 0 B3y 0 B4y; B1y B1x B2y B2x B3y B3x B4y B4x]; 節点外力(点荷重)と表面力の考慮: point_and_trac.m この MATLAB 関数は,節点外力(点荷重)と表面力による外力行列を計算し

て,全体外力行列の該当成分に加算する.メッシュ辺の外力行列を計算するには,

表面力を設定したメッシュ辺(辺数は nbe)についてループを回して,各辺でそ

の両端における表面力の値(2 次元配列 n_bc に格納)を用いて辺上で補間し,

親座標系にて 1 次元のガウス積分を行う.節点外力とメッシュ辺の外力行列は,

配列 ID を用いて全体系の自由度番号を付替え前の番号から付替え後の番号に変

換することで,全体外力行列にアセンブリできる.

point_and_trac.m % 節点外力(点荷重)と表面力による各辺の外力ベクトルを計算し,全体外力行列を組立 function f = point_and_trac(f); include_flags; % 節点外力(点荷重)を全体外力行列の該当成分に加算 f(ID) = f(ID) + P(ID); % 表面力による各辺の外力行列を計算 for i = 1:nbe ft = [0 0 0 0]'; % 各辺の外力行列の初期化 node1 = n_bc(1,i); % 辺の第1節点を準備 node2 = n_bc(2,i); % 〃 2 〃 n_bce = n_bc(3:6,i); % 両節点における表面力を準備 x1 = x(node1); y1=y(node1); % 第1節点の(x,y)座標 x2 = x(node2); y2=y(node2); % 第2節点 〃 leng = sqrt((x2-x1)^2 + (y2-y1)^2); % 辺長(edge length) J = leng/2; %ヤコビ行列(1次)の行列式 [w,gp] = gauss(ngp); % ガウス積分点(親座標系)と重みを準備 for i=1:ngp % 辺上で1次元のガウス積分 psi = gp(i); % 積分点(親座標系) N = 0.5*[1-psi 0 1+psi 0; % 〃 における1次元の形状関数行列の値 0 1-psi 0 1+psi]; % (表面力の補間にはx方向 とy 方向が必要) T = N * n_bce; % 形状関数を用いて表面力を補間 ft = ft + w(i)*N' *T *J; % 積分点による評価値に重みを乗じて加算 end % 表面力による各辺の外力行列を全体外力行列の該当成分に加算 ind1 = ndof*(node1-1)+1; % 辺の第1節点に対応する全体系の自由度番号 ind2 = ndof*(node2-1)+1; % 〃 2 〃 f(ID(ind1)) = f(ID(ind1)) + ft(1) ;

51

f(ID(ind1+1)) = f(ID(ind1+1)) + ft(2) ; f(ID(ind2)) = f(ID(ind2)) + ft(3) ; f(ID(ind2+1)) = f(ID(ind2+1)) + ft(4); end ポストプロセス: postprocessor.m この MATLAB 関数は,まず関数 displacements をよぶことで節点変位を用いて

変形図を描画する. input_file_*.m で変形の誇張倍率 fact をあらかじめ指定する

ことで,図 9.13 のような図が描画される. 続いて応力場を描画するために節点における応力値が必要となるが,これはガ

ウス積分点における応力値( も正確な値)を計算してから,要素内で平均する.

あるいは,積分点における応力値から要素節点における値を外挿し,その要素節

点が接続している全体系の節点ごとに平均化する.また,各応力成分だけでなく,

ミーゼス応力 σY のような応力も計算できて,平面応力状態の場合,2 21 2 1 22Yσ σ σ σ σ= + − で与えられる.ここに,σ1 と σ2 は主応力であり,

22

1,2 2 2x y x y

xy

σ σ σ σσ τ

+ −⎛ ⎞= ± +⎜ ⎟

⎝ ⎠で与えられる.なお,図 9.14 は 64 要素の場合の

xxσ 分布である.

postprocessor.m % 変位と応力の可視化 function postprocess(d); include_flags % 変形図を描画 displacements(d); % ガウス積分点におけるひずみと応力を評価しコマンドウィンドウに出力.また,応力場を描画 s = zeros(neq,1); if strcmpi(compute_stress,'yes')==1; fprintf(1,'\n Stress at Gauss Points \n') fprintf(1,'----------------------------------------------------------------------------- \n') for e=1:nel fprintf(1,'Element %d \n',e) fprintf(1,'-------------\n') get_stress(d,e); nodal_stress(d,e); end stress_contours; end

52

displacement.m % 変形を誇張して描画 function displacements(d); include_flags; if strcmpi(plot_disp,'yes')==1; displacement = d(ID)*fact; % 変形を誇張 % 誇張した変形の座標を計算 j = 1; for i = 1:ndof:nnp*ndof xnew(j) = x(j) + displacement(i); ynew(j) = y(j) + displacement(i+1); j = j + 1; end % 初期状態に重ねて変形を誇張して描画 for e = 1:nel XXnew = [xnew(IEN(1,e)) xnew(IEN(2,e)) xnew(IEN(3,e)) xnew(IEN(4,e)) xnew(IEN(1,e))]; YYnew = [ynew(IEN(1,e)) ynew(IEN(2,e)) ynew(IEN(3,e)) ynew(IEN(4,e)) ynew(IEN(1,e))]; plot(XXnew,YYnew,'k');hold on; end title('Initial and deformed structure'); xlabel('X'); ylabel('Y'); end

get_stress.m % ガウス積分点におけるひずみと応力を評価 function get_stress(d,e); include_flags; de = d(LM(:,e)); % 要素節点における変位(要素変位行列)の「収集」 % 要素節点座標の「収集」 je = IEN(:,e); C = [x(je); y(je)]'; [w,gp] = gauss(ngp); % ガウス積分点(親座標系)と重みを準備 % ガウス積分点におけるひずみと応力を計算 ind = 1; for i=1:ngp for j=1:ngp eta = gp(i); psi = gp(j); N = NmatElast2D(eta,psi); [B, detJ] = BmatElast2D(eta,psi,C); Na = [N(1,1) N(1,3) N(1,5) N(1,7)]; X(ind,:) = Na*C; % ガウス積分点を物理座標系に変換 strain(:,ind) = B*de; stress(:,ind) = D*strain(:,ind); % ガウス積分点における応力の成分 [s_xx s_yy s_xy]を計算

53

ind = ind + 1; end end e_xx = strain(1,:); e_yy = strain(2,:); e_xy = strain(3,:); % ガウス積分点のひずみ s_xx = stress(1,:); s_yy = stress(2,:); s_xy = stress(3,:); % 〃 応力 % Print x-coord y-coord sigma_xx sigma_yy sigma_xy stress_gauss = [X(:,1) X(:,2) s_xx' s_yy' s_xy' ]; fprintf(1,'\tx-coord\t\t\ty-coord\t\t\ts_xx\t\t\ts_yy\t\t\ts_xy\n'); fprintf(1,'\t%f\t\t%f\t\t%f\t\t%f\t\t%f\n',stress_gauss');

nodal_stress.m % 節点における応力(の合計値)を評価 function nodal_stress(d,e); include_flags; de = d(LM(:,e)); % 要素節点における変位を「収集」 % 要素節点座標の「収集」 je = IEN(:,e); C = [x(je); y(je)]'; psi_val = [-1 1 1 -1]; % 要素節点のφ(psi)値(外挿点) eta_val = [-1 -1 1 1]; % 〃 η(eta)値 〃 % 要素節点におけるひずみと応力を,外挿により計算 ind = 1; for i=1:nen eta = eta_val(i); psi = psi_val(i); [B, detJ] = BmatElast2D(eta,psi,C); strain(:,ind) = B*de; stress(:,ind)= D*strain(:,ind); % 応力の成分 [s_xx s_yy s_xy]を計算 ind = ind + 1; end e_xx = strain(1,:); e_yy = strain(2,:); e_xy = strain(3,:); % 要素節点のひずみ s_xx = stress(1,:); s_yy = stress(2,:); s_xy = stress(3,:); % 〃 応力 counter(je) = counter(je) + ones(nen,1); % その節点に接続している要素の数 % nodestress(je,:) = [s_xx' s_yy' s_xy' ]; % 要素節点の応力を格納(原著はバグのはず)

nodestress(je,:) = nodestress(je,:) + [s_xx' s_yy' s_xy' ]; % 要素節点の応力に加算(修正済み)

Stress_contours.m function stress_contours; include_flags; if strcmpi(plot_stress_xx,'yes')==1;

54

figure(2); for e=1:nel XX = [x(IEN(1,e)) x(IEN(2,e)) x(IEN(3,e)) x(IEN(4,e)) x(IEN(1,e))]; YY = [y(IEN(1,e)) y(IEN(2,e)) y(IEN(3,e)) y(IEN(4,e)) y(IEN(1,e))]; sxx = nodestress(IEN(:,e),1)./counter(IEN(:,e)); dd = [sxx' sxx(1)]; patch(XX,YY,dd);hold on; end title('\sigma_x_x contours'); xlabel('X'); ylabel('Y'); colorbar end if strcmpi(plot_mises,'yes')==1; for e=1:nel XX = [x(IEN(1,e)) x(IEN(2,e)) x(IEN(3,e)) x(IEN(4,e)) x(IEN(1,e))]; YY = [y(IEN(1,e)) y(IEN(2,e)) y(IEN(3,e)) y(IEN(4,e)) y(IEN(1,e))]; sxx = nodestress(IEN(:,e),1)./counter(IEN(:,e)); syy = nodestress(IEN(:,e),2)./counter(IEN(:,e)); sxy = nodestress(IEN(:,e),3)./counter(IEN(:,e)); S1 = 0.5*(sxx+syy) + sqrt( (0.5*(sxx-syy)).^2 + sxy.^2); % 第1主応力 S2 = 0.5*(sxx+syy) - sqrt( (0.5*(sxx-syy)).^2 + sxy.^2); % 第2主応力 mises = sqrt( S1.^2 + S2.^2 - S1.*S2 ); % 平面応力状態のミーゼス応力 dd = [mises' mises(1)]; figure(3); patch(XX,YY,dd);hold on; end title('Von Mises \sigma contours'); xlabel('X'); ylabel('Y'); colorbar end 既出の関数 ・8 章: preprocessor.m, mesh2d.m, plotmesh.m, assembly.m, solvedr.m

12.6 MATLAB によるはりの有限要素プログラミング 本節では,はりに対する有限要素プログラムについて説明する.このプログラ

ムは,節点あたりの自由度数が 2 であることを除けば,12.4 節で述べた 1 次元問

題に対する汎用的な有限要素プログラムと非常に似ているので,各 m-file の説明

は簡略化する. beam.m 12.4 節の主プログラムとほとんど同じである. %%%%%%%%%%%%%%%%%%%% % 梁の有限要素プログラム(10 章) % % Suleiman M. BaniHani, Rensselaer %

55

%%%%%%%%%%%%%%%%%%%% clear all; close all; % グローバル変数のインクルード include_flags; % プリプロセス [K,f,d] = preprocessor; % 要素剛性行列と要素体積力行列の計算と,全体剛性行列と全体外力行列の組立 for e = 1:nel [ke,fe] = beamelem(e); [K, f] = assembly(K,f,e,ke,fe); end % 節点外力と境界力を全体外力行列に考慮 f = NaturalBC(f); % 連立 1 次方程式の求解 [d,f_E] = solvedr(K,f,d); % ポストプロセス postprocessor(d) include_flags.m % グローバル変数の宣言 global nsd ndof nnp nel nen neq nd ngp global CArea E leng phi xp P global plot_beam plot_nod plot_stress global LM IEN x y stress body global flags ID xplot n_bc e_bc np nplot neqe preprocessor.m このMATLAB関数では,インクルードされる入力スクリプトinput_file_example10_1.m にて変数

の値を指定し,ID配列とLM配列を作成する.ID配列は12.4節で述べた1次元問題の場合と同一で

あるが,LM配列には要素の自由度が接続する全体系の自由度番号(並替え後)を列ごとに指定

する.たとえば,例10.1では次のように指定する.

1 3

2 4

3 5

4 6

LM =

⎡ ⎤⎢ ⎥⎢ ⎥⎢ ⎥⎢ ⎥⎣ ⎦

% プリプロセス ― 計算に必要な入力データと要素分割の設定 function [K,f,d] = preprocessor; include_flags; % 入力データのインクルード input_file_example10_1;

56

% LM配列の作成 count = 0; count1 = 0; for i = 1:neq if flags(i) == 2 % 基本境界条件のとき count = count + 1; ID(i) = count; % 基本境界上の自由度から優先的に全体系の自由度番号を付与 d(count)= e_bc(i); % 基本境界条件の値を全体変位行列に格納 else count1 = count1 + 1; ID(i) = nd + count1; end end for e = 1:nel for j = 1:nen for m = 1:ndof ind = (j-1)*ndof + m; LM(ind,e) = ID(ndof*IEN(j,e) - ndof + m) ; % LM配列の作成 end end end input_file_example10_1.m 断面積は,節点における値を指定して 1 次形状関数により補間する.ヤング率と体積力は,各要

素における値を指定して要素内では一定値とする.基本境界条件と自然境界条件は,境界上の自

由度に対してそれぞれ指定する. % 例10.1の入力データを設定するスクリプト nsd = 2; % 空間の次元数(number of spatial dimensions ) ndof = 2; % 節点あたりの自由度数(number of degrees-of-freedom per node) nnp = 3; % 節点数(number of global nodes) nel = 2; % 要素数(number of elements) nen = 2; % 要素節点数(number of nodes in each element) neq = ndof*nnp; % 方程式の本数(number of equations)or 全体系の自由度数 neqe = ndof*nen; % 要素方程式の本数(number of equations per element)or 局所的な自由度数 f = zeros(neq,1); % 全体外力行列の初期化 d = zeros(neq,1); % 全体変位行列の初期化 K = zeros(neq); % 全体剛性行列の初期化 flags = zeros(neq,1); % 自由度に課される境界条件を区別するためのフラグの宣言 e_bc = zeros(neq,1); % 基本境界(essential B.C)上の既知の節点変位用配列の宣言 n_bc = zeros(neq,1); % 自然境界(natural B.C)上の既知の境界力用配列の宣言 % 材料特性 CArea = [1 1 1]'; % 節点における断面積(cross-sectional area) leng = [8 4 ]; % 要素長さ(elements length) body = [-1 0 ]'; % 体積力(body forces)― 各要素内で一定値 E = [1e4 1e4]'; % ヤング率 ― 各要素内で一定値 % ガウス積分 ngp = 2; % ガウス積分点数

57

% 基本境界条件 % 奇数番は節点の垂直方向変位,偶数番は節点の回転 flags(1) = 2; % 全体系の自由度が基本境界上にあることのフラグ flags(2) = 2; % 〃 e_bc(1) = 0; % 基本境界条件の値(既知の垂直方向変位) e_bc(2) = 0; % 〃 (既知の回転(radian)) nd = 2; % 基本境界上の自由度数 % 自然境界条件 % 奇数番は節点におけるせん断力(外力),偶数番は節点におけるモーメント(外力) flags(5) = 1; % 全体系の自由度が自然境界上にあることのフラグ flags(6) = 1; % 〃 n_bc(5) = -20; % 自然境界条件の値(既知のせん断力) n_bc(6) = 20; % 〃 (既知のモーメント) % 要素内の点荷重 P = [-10 5]'; % 点荷重(point forces) xp = [4 8]' ; % 点荷重を作用させるx座標値(x-coordinates for point force) np = 2; % 点荷重の数(number of point forces) % 計算結果の可視化フラグ plot_beam = 'yes'; plot_nod = 'yes'; % 要素分割 beam_mesh_10_1; nplot=300; % 変位,せん断力,モーメントの分布を描画するための標本点数 beam_mesh_10_1.m function beam_mesh_10_1 include_flags; % 節点: 1 2 3 (節点1が原点) x = [0.0 8.0 12.0 ]; % x 座標 y = [0.0 0.0 0.0 ]; % y 座標 % 要素に関する局所的な節点番号を全体系の節点番号に変換するための2次元配列 IEN = [1 2 2 3]; % はりの描画 % plotbeam; % 本ファイルに未収録

beamelem.m % 要素剛性行列と要素体積力行列の作成 function [ke, fe] = beamelem(e) include_flags; IENe = IEN(:,e); % 要素eが接続する全体系の節点番号を準備

58

xe = x(IENe); % 要素節点のx座標を「収集」 J = (xe(nen) - xe(1))/2; % ヤコビ行列(Jacobian matrix)の行列式を計算 [w , gp] = gauss(ngp); % ガウス積分点(親座標系)と重みを準備 ke = zeros(neqe,neqe); % 要素剛性行列の初期化 fe = zeros(neqe,1); % 要素体積力行列の初期化 for i = 1:ngp N = NmatrixBeam(gp(i),xe); % 要素形状関数行列をガウス積分点で評価 B = BmatrixBeam(gp(i),xe) *1/J^2; % Bマトリクスを 〃 Ae = [N(1) N(3)]*CArea(IENe); % ガウス積分点における断面積 Ee = E(e); % ヤング率(要素内で一定値) be = body(e); % 体積力 ( 〃 ) ke = ke + w(i)*(B'*Ae*Ee*B); % 積分点における評価値に重みを乗じて加算 fe = fe + w(i)*N'*be; % 〃 end ke = J*ke; fe = J*fe; % 要素内に点荷重がある場合の処理 for i=1:np % 点荷重の数だけループ Pi = P(i); % 点荷重を準備 xpi = xp(i); % 点荷重の位置を準備 if xe(1)<=xpi & xpi<xe(nen) % 点荷重が要素内部に位置するとき

fe = fe + Pi*[NmatrixBeam( ( (2*xpi-xe(1)-xe(nen))/(xe(nen) - xe(1)) ) ,xe)]'; % 等価な体積力行列 end end

NmatrixBeam.m % 要素形状関数行列を親座標系の点sで評価 function N = NmatrixBeam(s,xe) L=xe(2)-xe(1); N(1)=1/4*(1-s)^2*(2+s); N(2)=L/8*(1-s)^2*(1+s); N(3)=1/4*(1+s)^2*(2-s); N(4)=L/8*(1+s)^2*(s-1);

BmatrixBeam.m % Bマトリクス(形状関数の微分)を親座標系の点sで評価 function B = BmatrixBeam(s,xe) L=xe(2)-xe(1); B(1)=3/2*s; B(2)=L*(3/4*s-1/4); B(3)=-3/2*s; B(4)= L*(3/4*s+1/4);

SmatrixBeam.m % 形状関数の2回微分を親座標系の点sで評価 function S = SmatrixBeam(s,xe) L=xe(2)-xe(1); S(1)=3/2;

59

S(2)=3/4*L; S(3)=-3/2; S(4)= 3/4*L;

naturalBC.m % 節点外力を全体外力行列に考慮 function f = naturalBC(f); include_flags; for i = 1:neq if flags(i) == 1 dof = ID(i); f(dof) = f(dof) + n_bc(dof); end end

postprocessor.m % ポストプロセス function postprocessor(d) include_flags; % 要素ごとに変位,モーメント(内力),せん断力(内力)の分布を描画するためのループ for e = 1:nel de = d(LM(:,e)); % 要素節点における変位(要素変位行列)を「収集」 IENe = IEN(:,e); % 要素eが接続する全体系の節点番号を準備 xe = x(IENe); % 要素節点のx座標を「収集」

J = (xe(nen) - xe(1))/2; % ヤコビ行列(Jacobian matrix)の行列式を計算 [w , gp] = gauss(ngp); % ガウス積分点(親座標系)と重みを準備 % 要素内の標本点で変位,モーメント,せん断力を評価 xplot = linspace(xe(1),xe(nen),nplot); % linspace命令により要素内で等間隔な点列を作成 xplotgauss = (2*xplot-xe(1)-xe(nen))/(xe(nen) - xe(1)); for i = 1:nplot xi = xplotgauss(i); % x座標点 N = NmatrixBeam(xi,xe); % 要素形状関数行列を この点xiで評価 B = BmatrixBeam(xi,xe)*1/J^2; % 形状関数の1階微分を 〃 S = SmatrixBeam(xi,xe)*1/J^3; % 〃 2 〃 Ee = E(e); % ヤング率 displacement(i) = N*de ; % 変位 を計算し格納 moment(i) = Ee*B*de; % モーメント 〃 shear(i) = Ee*S*de; % せん断力 〃 end % 変位,モーメント,せん断力の分布を描画 [x_plot,S_ex,M_ex,w_ex]=exact; % 厳密解の計算(関数exactは本ファイルに未収録) figure(2) plot(xplot,displacement,'-.r'); hold on; plot(x_plot,w_ex,'-k'); legend('FE','Exact Solution'); hold on; ylabel('displacement'); title('Displacements: FE versus analytical beam solutions');

60

figure(3) plot(xplot,moment,'-.r'); hold on; plot(x_plot,M_ex,'-k'); legend('FE','Exact Solution'); hold on; ylabel('moment'); xlabel('x'); title('Moments: FE versus analytical beam solutions'); figure(4) plot(xplot,shear,'-.r'); hold on; plot(x_plot,S_ex,'-k'); legend('FE','Exact Solution'); hold on; ylabel('shear'); xlabel('x'); title('Shear: FE versus analytical beam solutions'); end

既出の関数

・5 章:assembly.m, solvedr.m, gauss.m

線形代数に関する問題 問 12.1

次の n n× の行列A を作成する MATLAB プログラムを作成せよ.

20

ij

-1 if i j 1 or i j 1A if i j

otherwise

= − = +⎧⎪= =⎨⎪⎩

n 5,10,1000= 等に対して1−=B A A を計算し,その結果と I との誤差を確認せよ.な

お,誤差は次の評価式により計算すること.

( )2

21 1

1 n n

ij iji j

err B In = =

= −∑∑

次の行列 A について, n 3,4,5,6,7...= として,上の評価式の値 err が 1 よりも大きく

なるまで,上記の計算を繰り返せ. 1

ijAi j

=+

1 つ目の行列 A はある有限要素方程式の剛性行列であり,2 つ目の行列 A はヒルベル

ト行列(Hilbert matrix)とよばれるものである.1 つ目の場合は大きな元数でも十分精確

に計算できるので,数値の丸め誤差による影響はほとんどない.このような行列は良条

件な行列(well-conditioned matrix)とよばれている.一方で 2 つ目の行列は,極端に悪

条件な行列(ill-conditioned matrix)の例である. 問 12.2

次の連立 1 次方程式について以下の問いに答えよ.

61

1 2 3

1 2 3

1 2 3

8 6 7.5

3 5 7 4

4 9 2 12

x x x

x x x

x x x

⎧⎪ + + =⎪⎪⎪⎪ + + =⎨⎪⎪⎪ + + =⎪⎪⎩

a) この方程式を Ax b= とするとき,MATLAB を用いてxについて解け. b) xに制約条件 ( ) 1 2 1 0g x x x= + + − =x を課す.この制約条件を厳密に満たし

誤差 ( ) ( ) ( )Tnew new newerr = − −x Ax b Ax b を 小にする解newx を MATLAB を用

いて求めよ.

問 12.3 次の対称行列Kに関して以下の問いに答えよ.ここで, 1 2, ,k k k は正値である.

1 1

1 2 2

1 1 2 22 2

2 2

00

; ; ;0

0

k kk k k k

k k k kk k k

k k

⎡ ⎤−⎢ ⎥⎡ ⎤ ⎡ ⎤+ − ⎢ ⎥⎢ ⎥ ⎢ ⎥ − + −⎢ ⎥⎢ ⎥ ⎢ ⎥− ⎢ ⎥⎢ ⎥ ⎢ ⎥⎣ ⎦ ⎣ ⎦ ⎢ ⎥−⎢ ⎥⎣ ⎦

a) これらの行列が正定値対称行列(Symmetric Positive Definite; SPD)であるか否かを確

認せよ.なお,Kが正定値対称行列であるとは,任意の列行列 0≠x に対して

0T >x Kx であることをいう.一方,任意の列行列 0≠x に対して 0T ≥x Kx で

あるとき,Kは半正定値対称行列(symmetric semi-positive definite)であるという.

上記の行列から半正定値対称行列を 1 つ選びだし,どのような右辺 f に対しても連

立 1 次方程式 =Kd f の解が唯一でないことを示せ. b) これらの行列の固有値を計算することで前問を検証せよ.