[境界要素法プログラムを設計する(境界積分サブルーティン:事前調査編)] [境界要素法]
[境界要素法プログラムを設計する(境界積分サブルーティン:事前調査編)]
1.再利用性を考える
トップダウンでやってくると(やって来たつもりです(^^;))、サブルーティンの具体化の際には、その全体仕様として考えるべきところはもう、前回の3)再利用性くらいしか残らないはずです。どういうケースで使い回される可能性があるか?。
一要素の境界積分値は、特異点座標と要素端の節点座標で決まりました。また境界積分は境界方程式と、いまだ未考慮の内点方程式で使われます。境界方程式のケースでは、特異点座標と要素節点座標が一致する場合としない場合があり、それに応じて処理を変える必要がありました。一方、内点方程式のケースでは特異点と節点は必ず一致しません。よって境界方程式のケースで考えとけば、内点方程式のケースをカバーできると思われます。
他に境界積分値が使われる場面はあるでしょうか?。ないと思われます。従って再利用性を考慮した結果は、境界方程式用の境界積分サブルーティンだけで良い、となります。
2.具体的使用法を考える
サブルーティンとは小さくても自作ライブラリです。なのでその覚悟でやるべきと自分は思ってます(オブジェクト指向採用の場合はもっとそう)。最初に考えるのは、その呼び出し方(←トップダウン,トップダウンとお呪い(^^))。それが使われるのは、[境界要素法プログラムを設計する(計算部と出力部の実装)]の「境界要素番号kで境界積分を行うLoop」の中の、
REM (x0,y0),(x1,y1),(x2,y2)から、要素kの境界積分値を計算
REM ψj1に関する結果をB1,qj1に関する結果をH1で表す
REM ψj2に関する結果をB2,qj2に関する結果をH2で表す
という部分でした。要するに境界積分サブルーティンは、上記の値:B1,B2,H1,H2を与えるものです。そうするとサブルーティン形式より関数の方がスマートです。
B1 = B_Inte_B1(x0,y0,x1,y1,x2,y2)
B2 = B_Inte_B2(x0,y0,x1,y1,x2,y2)
H1 = B_Inte_H1(x0,y0,x1,y1,x2,y2)
H2 = B_Inte_H2(x0,y0,x1,y1,x2,y2)
といった感じでしょうか?。
ここで関数を4つも用意するなら、一つのサブルーティンで、
Call B_Inte(x0,y0,x1,y1,x2,y2, B1, B2, H1, H2)
とやった方がスマートでは?、という意見もあると思いますが、引数が10個もあるので嫌なのだ。(x0,y0),(x1,y1),(x2,y2)の部分は配列にして渡せばいいじゃん、という意見もあるが、新しい配列宣言とそれへの値代入がメインに増えるから嫌なのだ。
だったら、節点座標は[入力部]で最初から配列として与えられるんだから、
Call B_Inte(BN(i, 1),BN(j1, 1),BN(j2, 1), B1, B2, H1, H2)
とすれば良いじゃん!。後で見たとき配列BNの構成を勘違いしそうなので、やっぱり嫌なのだ。だいたいこっちの方が、引数並びの字数も多いじゃねぇ~か。それにメインの作業は、やる事を明示的にコード化したいのだ。だから関数名くらいケチケチしないのだ。
※これはプログラマーの趣味です。まぁ~、こんなもんです(^^;)。
ところが境界積分は、次図のパラメータを定義すると便利なのでした。
境界要素kの外法線方向βkはBeta_kで、r1とr2の方向γ1,γ2はGamm_1,Gamm_2で表します。
Lk = Length(x1,y1,x2,y2)
Beta_k = Angle(x2 - x1, y2 - y1, Lk)
r1 = Length(x0,y0,x1,y1)
r2 = Length(x0,y0,x2,y2)
Gamm_1 = Angle(x1 - x0, y1 - y0, r1)
Gamm_2 = Angle(x2 - x0, y2 - y0, r2)
h = Normal_Length(x2 - x1, y2 - y1, x0,y0)
s = Normal_Foot(x2 - x1, y2 - y1, x0,y0, h)
という関数で積分パラメータは計算できそうです。関数でやると決めたので、関数名はケチりません。また関数Length,Angle,Normal_Length,Normal_Footの引数並びから判断し、内部で重複した計算はほぼ起こらないと思われるので、とりあえずこれらでOKとします。従って、
B1 = B_Inte_B1(Lk, r1, r2, Beta_k, Gamm_1, Gamm_2, h, s)
B2 = B_Inte_B2(Lk, r1, r2, Beta_k, Gamm_1, Gamm_2, h, s)
H1 = B_Inte_H1(Lk, r1, r2, Beta_k, Gamm_1, Gamm_2, h, s)
H2 = B_Inte_H2(Lk, r1, r2, Beta_k, Gamm_1, Gamm_2, h, s)
です。
とここで・・・。
B1,B2,H1,H2を与える関数の引数は結局ずいぶん長いじゃないか!。それに関数を8行もメインに追加しやがって、今まで長い引数並びは嫌だのメインの行数は増やしたくないだの、さんざん言いやがったくせに、いいのかよ?。
そうなんですが、ここは「いいんです!」とシレっと言います(^^;)。メインの作業を明示的にコード化し、明確にしたからです。図-1と関数Length~Normal_Footの意図を理解できれば、ほぼ間違う事はないからです(←嘘です。けっこう気軽に間違います(^^;))。
本当は図-1も、関数Length~Normal_Footの関数定義も、その意図とともに[メモ欄]に突っ込んでおきたいところなんです。だから本当は、そういう設計思想をまとめたものを独立した文書として持つべきなんですよ。それを常に参照しつつプログラミングを行い、必要に応じて文書の加筆・修訂正も行う。そうすれば開発が終わった暁には、製品と仕様書が同時にあがっています。理想的に上手く行けば取説も(^^)。
それが本当の意味でのスパイラルでありアジャイル開発だと思います。そういうのを自分は、アプリケーション構造設計書と勝手に呼んでます。最初からここまで書いてきた事は(およびこの先も含めて)、口語体で書かれたアプリケーション構造設計書だと自分は思ってます。
ところで具体的実装(具体的調査含む)をちょっとやってみると、ここでの想定の不味さがあっさりと発覚します。それは境界要素法の数学的特異性(危うさ?)に由来するものなので、今回はここでやめます。
コメント 0