OpenSees Blog 日本語 目次

最初に「このブログをみるためのガイド」をご覧ください。

Update中OpenSees コマンド 日本語解説 の 目次 OpenSeesコマンド はじめての方は「ここから
このblogで使用しているOpenSeesコマンド集は「ここ」 Update中
OpenSees のソースコード 解析に挑戦してみる 目次最初のページは「ソースコードのダウンロードとビルド」
Appendix:C言語での 「有限要素法における平面トラスの解析」目次最初のページは「Microsoft Visual Studioの導入方法」







目次の中で、更新したページにはNewがついています

このブログ内の単語を検索したい場合は、左上OpenSeesロゴの上に検索窓から検索できます。


2015年1月27日火曜日

OpenSees Developer :構造計算(静的・線形解析)1

C:\OpenSees-work\OpenSees5621\OpenSees\SRC\tcl\commands.cpp

または
tclプロジェクトのcommands.cpp
の中の

int analyzeModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv)

で実行される

result = theStaticAnalysis->analyze(numIncr);

で、構造計算が始まります。(下図参照)





が、その前に構造計算で使用する連立方程式を解くための、クラスをアロケートする必要があります。

ここ で説明がありますとおり、構造計算で使用する線形連立方程式などには、解析するものによって、使用する方程式の解法が違ってきます。どの解法を使うかは、tcl スクリプトによって指定されています。

今回は この tcl スクリプトを使用しています。 その中で、連立方程式の解法に関するコマンドは下記になります。


# Create the system of equation, a SPD using a band storage scheme
system BandSPD

# Create the DOF numberer, the reverse Cuthill-McKee algorithm
numberer RCM

# Create the constraint handler, a Plain handler is used as homo constraints
constraints Plain

# Create the integration scheme, the LoadControl scheme using steps of 1.0
integrator LoadControl 1.0

# Create the solution algorithm, a Linear algorithm is created
algorithm Linear


たとえば、
system BandSPD
の場合、

system のコマンドが実行されるとき、流れるプログラムは、

tclプロジェクトのcommands.cpp
の中の

specifySOE(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv)
です。




今回は、LAPACKライブラリ(DPBSV)の実対称正定値帯連立一次方程式の解放を使用します。
そのため、
system では、BandSPDが指定されているので、上記の図、オレンジで囲まれた部分にあるとおり、
BandSPDLinLapackSolver

BandSPDLinSOE
のクラスをアロケートしています。

ちなみに、
このクラス領域を使って、実際に実対称正定値帯連立一次方程式を解いているところが、最初に書きました
result = theStaticAnalysis->analyze(numIncr);
です。


次のページ →
OpenSees Developer :構造計算(静的・線形解析)2

ここまでのページの説明は、(静的・線形解析)をもとにして書いてありますが、(静的・非線形解析)の場合でも、同じ流れになります。次の「2」の説明から、プログラムは分かれてきます。
OpenSees Developer : 構造計算(静的・非線形解析) 2 


OpenSees のソースコード解析に挑戦してみる : 目次

2015年1月20日火曜日

C言語での特徴 - memory handling

 C言語での特徴 1) memory handling について

Cの大きな特徴として、ポインタによるメモリハンドルが可能ということがあります




簡単のため 1列のDimensionでのメモリのallocate, freeについて解説します。
下記は5の大きさを持った1列のDimensionでのCプログラムでです。

#include <malloc.h>
#include <stdlib.h>

double  *double_dimension_sample;
int      dimension_size = 5;

double_dimension_sample = (double *)malloc(sizeof(double) * dimension_size);

double_dimension_sample[0] = 1.0;
for (int i = 0; i < dimension_size; i++)
double_dimension_sample[i] = double_dimension_sample[i-1] + 0.5;

if (double_dimension_sample)
free(double_dimension_sample);





次に23列を持った行列(Dimension)の場合での、メモリのallocate, freeについて説明します。
2次元の行列の場合のCプログラムは以下の通りです。

#include <malloc.h>
#include <stdlib.h>
#define DIM_ROW 2
#define DIM_COL 3

double **A;

A =  (double **)(malloc (sizeof(double*) * DIM_ROW));
for (int i = 0; i < DIM_ROW; i++)
              A[i] = (double *)malloc(sizeof(double) * DIM_COL);

// omitted…

if (A)      {
for (int i = 0; i < DIM_ROW; i++)   {
                            if (A[i])  free(A[i]);
              }

}





メモリを解放(free)する場合は、この定義の逆の順番で解放すること。

malloc () について詳細に知りたい場合は、下記MSDN(Microsoft Developer Network)で参照できる



なぜメモリ ハンドリンングが必要なのでしょうか? メモリは有限で、アクセススピードがCPUと比べて遅いからです。
















参照) http://www.cms-initiative.jp/ja/events/CMSI_events/2013-haishin-docs/0530-nakata


ちなみにC++言語では、以下のようになります。





次のページ →
 C言語での特徴 - dimension

「有限要素法における平面トラスの解析」プログラムをC言語で書いてみる : 目次

2015年1月14日水曜日

<有限要素法> C言語でのフローチャート と 使用するヘッダーファイルなどの定義

このブログでのC言語による有限要素法プログラムの流れ(フローチャート)は以下のようになります。
次の投稿から順番に説明が始まります。













































また、使用するヘッダーファイル、ファンクション定義、定数定義は以下の通りです。

最初に
使用する関数(sin(), cos(), malloc()など)が定義されているヘッダーファイルを設定

次に
メインプログラムが呼ぶサブルーチンを定義

各サブルーチンについては後述
MxM() : 行列の積の計算
MxW() : 逆行列と行列の積の計算
MxV() : 行列とベクトルの積の計算
LEQ() : 連立一次方程式の解法

最後に
定数として使用するものも(大文字で)定義
しています。























ここでESmatrix_EK(要素剛性マトリックス)も tranGtoE(行列変換マトリックス)も、要素の成分を追加した3次元構成になっています。





<有限要素法> 節点数、要素数など、データをcsvファイルから読み込む


「有限要素法における平面トラスの解析」プログラムをC言語で書いてみる : 目次

2015年1月13日火曜日

OpenSees Developer : 静的・線形解析の構造計算用のファンクション


Basic exampleの中の 基本的なトラス解析 で使用したOpenSeesのtcl スクリプトファイルを使用して どのように静的・線形解析の場合の構造計算がされているか、をたどっていきます。

使用するtcl スクリプトファイルは ここ にあります。

tcl スクリプトに書かれている通り、

セットしたデータをつかっての構造計算は、

# create the analysis object
analysis Static
analyze 1


で、行います。

まず、
analysis Static
は、
C:\OpenSees-work\OpenSees5621\OpenSees\SRC\tcl\commands.cpp
または
tclプロジェクトのcommands.cpp
の中の

int  specifyAnalysis(ClientData clientData, Tcl_Interp *interp, int argc,  TCL_Char **argv)

で実行されます。

この中で、
構造計算に必要となるデータについての、クラス単位のメモリの準備が行われます。
その時、
ここ で 説明しましたOpenSeesのコマンド"analysis"で、

さらに呼ばれるファンクションが変わっていきます。

"analysis"では、以下の3つが引数として指定できます。


  • Static
  • Transient
  • VariableTransient 


が、この「基本的なトラス解析」では、Staticな解析を指定していますので、

theStaticAnalysis = new StaticAnalysis(theDomain,
      *theHandler,
      *theNumberer,
      *theAnalysisModel,
      *theAlgorithm,
      *theSOE,
      *theStaticIntegrator,
      theTest);


により、Staticな解析の指定が行われます。

なお、このfunctionの中で

theAnalysisModel
theTest
theAlgorithm
theHandler
theNumberer
theStaticIntegrator
theSOE
は、解析を行う中で出力される、データの構造体(=出力データ)。

theDomain
は、
tcl スクリプトファイルの中で、定義されていたNodeやElementなどのデータが入っている構造体(
=入力データ)です。



余談ですが、
OpenSees UserのWebSiteには、まだ記載がありませんが、プログラムの中を見る限り、ここでの"analysis"の方法は、他にも増えてきているようです。



次に、
analyze 1
は、

C:\OpenSees-work\OpenSees5621\OpenSees\SRC\tcl\commands.cpp
または
tclプロジェクトのcommands.cpp
の中の

int analyzeModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv)

で実行されます。

ここでも、

ここ で 説明しましたOpenSeesのコマンド"analysis"で、

さらに呼ばれるファンクションが変わっていきます。


この基本的なトラス解析では、Staticな解析を指定していますので、

 result = theStaticAnalysis->analyze(numIncr);

により、Staticな構造計算が行われます。
なお、このfunctionの中で
numIncr
は、解析する回数(ここでは、analyze 1 なので、1回)が入ります。

構造計算の結果は、
theStaticAnalysis
構造体の中に格納されます。



OpenSees のソースコード解析に挑戦してみる : 目次

2015年1月12日月曜日

C言語での特徴

<有限要素法> FORTRAN77言語とC言語の基本的な相違点(2)で大まかなFORTRANとCの違いを、マトリクスの掛け算nxnを使ってあげましたが、その中で特に重要なC言語の特徴は以下の4つです

  1. memory handling
  2. dimension
  3. function
  4. structure















































「有限要素法における平面トラスの解析」プログラムをC言語で書いてみる : 目次

2015年1月8日木曜日

OpenSees Developer : プログラムの全体的な流れ


全体的な、OpenSeesプログラムの流れとしては、

 Tcl_CreateCommand
で、OpenSeesとして使用するなコマンド(たとえば、Node,Element,wipeなど)が
実行するときに、どのファンクションを動作させるかを定義します。

次に
Tcl_EvalFile
で、tcl スクリプトファイルを読み込み、書いてある順に、
Tcl_CreateCommand でセットされたファンクションが一気に実行されます。


Tcl_CreateCommand は、以下の通りです。

 Tcl_CreateCommand
(interp, "<Openseesコマンド>", 
<OpenSeesコマンドを読み込むファンクション>,
 (xxxxx)NULL, (xxxxxx)NULL);


たとえば
Tcl_CreateCommand(interp, "node", TclCommand_addNode,  (ClientData)NULL, NULL);

は、 OpenSeesコマンドのとしてtclファイルに書かれているnodeの行を、プログラムの中にデータととして格納する時、ファンクション TclCommand_addNode( ) を使用してデータの格納を行います。
つまり、 TclCommand_addNode( )の中で、
Nodeクラスに OpenSeesコマンドのNodeのデータをセットしている、ということになります。


そして、最終的に実行する
Tcl_EvalFile
は、

OpenSees\SRC\tcl\tclmain.cpp
または
OpenSeesプロジェクトのtclmain.cpp
にあります。(緑丸部分)

Tcl_EvalFile(interp, tclStartupScriptFileName);
tclStartupScriptFileName には、OpenSeesをDOSコマンドプロンプトから動作させるときにセットして引数の、ファイル名が入っています。




ここで注意しなければいけないのは、以下の通りです。

OpenSeesのプログラムは、基本的にtcl スクリプトファイルに書かれている順に動作する、ということ。

Tcl_CreateCommand( )で定義されているコマンドは、OpenSees用のコマンドで、クラスとして定義されている、ということ。

もし、OpenSeesの計算結果などに対して、簡単な追加計算を行いたいならば、tcl スクリプトファイルに、tcl でプログラムを記載できる、ということ。
(tcl 言語についての説明は、ここのサイト が良くまとまっています)

もし、OpenSeesの計算結果などに対して、複雑な追加計算を行いたいならば、自分で新しいOpenSeesのコマンドをTcl_CreateCommand( )で定義できる、ということ。
ただし、C++ として正しくクラスを設計する必要があります。


次のページ → 

OpenSees のソースコード解析に挑戦してみる : 目次

FORTRAN77言語とC言語の基本的な相違点 (2)

FORTRAN77言語とC言語の基本的な相違点 (1) の各行についての解説です。


# Fortran C
1 bool MxM(double** M1, double** M2, double** Mout, int n);
Cでは、使うサブルーチンの宣言をあらかじめ行う必要があります。
もしこのサブルーチンが、複数のファイル(cpp)で使用される場合は、この宣言をヘッダーファイルとして作成します。そして
#include <xxxxx.h>
を、各ファイルの先頭に記載すれば、書き間違いのリスクを減らすことができます
2 DIMENSION A(2,2), B(2,2), C(2,2) int n=2;
double **A;
double **B;
double **C;
FortranではDimension をあらかじめ 2 と固定しています、Cでは Dimension であることのみを宣言して、大きさは指定していません。
Cでは、コンピュータのメモリを有効利用するために、Dimensionの大きさを可変に設定することができます。
そのため、プログラムの途中で、Dimensionの大きさが初めて決定するようなものでも、「とりあえず巨大にDimensionを取っておけば良いかな」ということで、使わないメモリ領域をあらかじめとっておく必要がなく、メモリが必要になったらその都度Dimensionの大きさを設定すればよいので、メモリ使用が経済的(ww)です
3 bool ret;
bool はbooleanで真(true)と偽(false)の2種類の値だけを扱います。
ここでは、MxMのサブルーチンの中で、Dimensionの大きさが0以下だった場合はfalseとしました。
4 A = (double **)(malloc (sizeof(double*) * n));
for (int i = 0; i < n; i++)
A[i] = (double )malloc(sizeof(double) * n);
2では シンボルAがDimensionであることを宣言していますが、その大きさを設定しているのがこの行です。
なお、ここで使用しているmalloc()関数は、最初のinclude文、
#include <malloc>
の中で宣言されています。
5 A(1,1)=1;
A(1,2)=2;
A(2,1)=3;
A(2,2)=4
A[0][0]=1;
A[0][1]=2;
A[1][0]=3;
A[1][1]=4;
ここではDimensionに値を入れていますが
の行列の入力の方法に注意をする必要があります。
FORTRANでは2の大きさのDimensionでは、1から2の成分となりますが、Cでは2の大きさのDimensionでは0から1の成分となります。
これはグラフのX,Y軸の使い方と同じで、0 origin と考えるとわかりやすいです。
6   DO l I=1,2
      DO 2 J=1,2
          C(I,J)=0.0;
2   CONTINUE
1 CONIINUE
for (int j = 0; j < n; j++) {
    for (int i = 0; i < n; i++) {
         C[j][i] = 0.0;
    }
}
FORTRANでのDOループは、Cでのfor文となります。
DOループでは、どこまでループさせるかを行番号とCONTINUで表示していますが、Cではfor文の範囲を{ }カギかっこで指定します。
また、FORTRANでは、I=1,2ということで、I を1から2まで変位させていますが、for文では、
for (int j = 0; j < n; j++)
integer宣言したj、初期値0を、jがnより小さい間だけ、jを1ずつ大きくしてゆく
  と、書きます。ここでnは、2なので、jは0,1 と変位することになります
7 CALL MXM(A, B, C, 2) ret=MxM(A, B, C, n);
FORTRANではサブルーチンを呼ぶときはCALL文を使用しますが、Cでは、そのままのfunctionとして使用します。
このfunctionは、1 で宣言されています
8 if (A) {
      for (int i = 0; i < n; i++) {
              if (A[i])
                  free(A[i]);
              }
        }
 free(A);
Cでは、いつでも自由にDimensionの大きさを設定できることを4で記載しましたが、使わなくなったDimension:メモリ空間を解放する必要があります。
なおプログラムが終了すれば、すべてのメモリ空間は解放されます。
プログラムの途中で使用しなくなったメモリ空間を解放できるので、プログラムのほかのシンボルが空いたメモリ空間を使用できるようにできるため、経済的(?)です。
大きなDimensionを使うプログラムでブルースクリーンになったり、プログラムが吹っ飛ぶのは、大概メモリの使い過ぎなので、これを使用して、こまめにメモリを解放してあげると、プログラムの安定性がでてきます。
なお、ここで使用しているfree()関数は、最初のinclude文、 #include の中で宣言されています。
9 // ------------SUB ROUTINE MXM -------
SUBROUTIN MXM(A,B,C,N)
DIMENSION A(N,N), B(N,N), C(N,N)
INTEGER I,J,K
DOUBLE PRECISION S

//A x B
DO l I=1,N
   DO 2 J=1,N
      S=0.0
      DO 6 K=1,N
         S=S+A(I,K) * B(K,J)
      3 CONTINUE
      C(I,J)=S
   2 CONTINUE
1 CONIINUE
RETURN
END
//----------------------------------------
// Sub routine M x M
//----------------------------------------
bool MxM(double** M1, double** M2, double** Mout, int n)
{
double s;
if(n<1)
 return false;
//M1 x M2
for (int i = 0; i < n; i++) {
 for (int j = 0; j < n; j++) {
  s=0.0;
  for (int k = 0; k < n; k++) {
   s=s + M1[i][k] * M2[k][j];
  }
  Mout[i][j]=s;
 }
}
return true;
}
サブルーチンについては、行列をポインタとして渡す(C言語)か、シンボルとして渡す(FORTRAN)かの他には、すでに説明した通りです







































































































次のページ →
C言語での特徴


「有限要素法における平面トラスの解析」プログラムをC言語で書いてみる : 目次

2015年1月1日木曜日

FORTRAN77言語とC言語の基本的な相違点 (1)

あけましておめでとうございます。2015年が皆様にとっても、素晴らしい年でありますように。。。
----------------------------------------------------

n行n列の行列で MxM を計算する場合を例として、
FORTRAN77言語とC言語の基本的な相違点を
紹介します

n行n列の MxMの行列計算のサブルーチンMXM()

これを呼ぶメインルーチン
FORTRAN77で書いたものと、Cで書いたものは以下の様になります


<<FORTRAN77>>
// -----MAIN ROUTINE-----
DIMENSION A(2,2),  B(2,2),  C(2,2)
INTEGER I,J

A(1,1)=1;
A(1,2)=2;
A(2,1)=3;
A(2,2)=4;
             
B(1,1)=5;
B(1,2)=6;
B(2,1)=7;
B(2,2)=8;

DO  l  I=1,2
DO  2  J=1,2
C(I,J)=0.0;
2       CONTINUE
1  CONIINUE

CALL MXM(A, B, C, 2)
END
// ------SUB ROUTINE  MXM -------
SUBROUTIN MXM(A,B,C,N)
DIMENSION A(N,N), B(N,N), C(N,N)
INTEGER I,J,K
DOUBLE PRECISION S
DO  l  I=1,N
DO  2  J=1,N
S=0.0
DO 6 K=1,N
S=S+A(I,K) * B(K,J)
3  CONTINUE
C(I,J)=S
2 CONTINUE
1  CONIINUE
RETURN
END
 <<FORTRAN77>>
// -----MAIN ROUTINE-----
DIMENSION A(2,2),  B(2,2),  C(2,2)
INTEGER I,J

A(1,1)=1;
A(1,2)=2;
A(2,1)=3;
A(2,2)=4;
             
B(1,1)=5;
B(1,2)=6;
B(2,1)=7;
B(2,2)=8;

DO  l  I=1,2
DO  2  J=1,2
C(I,J)=0.0;
2       CONTINUE
1  CONIINUE

CALL MXM(A, B, C, 2)
END
// ------SUB ROUTINE  MXM -------
SUBROUTIN MXM(A,B,C,N)
DIMENSION A(N,N), B(N,N), C(N,N)
INTEGER I,J,K
DOUBLE PRECISION S
DO  l  I=1,N
DO  2  J=1,N
S=0.0
DO 6 K=,N
S=S+A(I,K) * B(K,J)
3  CONTINUE
C(I,J)=S
2 CONTINUE
1  CONIINUE
RETURN
END

<<C>>
#include <malloc.h>
#include <stdlib.h>
bool MxM(double** M1, double** M2, double** Mout, int n);

int _tmain(int argc, _TCHAR* argv[])
{
int n=2;
double **A;
double **B;
double **C;
bool ret;

//各ポインタに対して、サイズを割り当てる  
A =  (double **)(malloc (sizeof(double*) * n));
for (int i = 0; i < n; i++)
A[i] = (double *)malloc(sizeof(double) * n);

B =  (double **)(malloc (sizeof(double*) * n));
for (int i = 0; i < n; i++)
B[i] = (double *)malloc(sizeof(double) * n);

C =  (double **)(malloc (sizeof(double*) * n));
for (int i = 0; i < n; i++)
C[i] = (double *)malloc(sizeof(double) * n);

A[0][0]=1;
A[0][1]=2;
A[1][0]=3;
A[1][1]=4;
B[0][0]=5;
B[0][1]=6;
B[1][0]=7;
B[1][1]=8;

for (int j = 0; j < n; j++) {
for (int i = 0; i < n; i++) {
C[j][i] = 0.0;
}
}
ret=MxM(A, B, C, n);
//A, B, Cの解放
if (A) {
for (int i = 0; i < n; i++) {
if (A[i])  free(A[i]);
}
    }
    free(A);
if (B) {
for (int i = 0; i < n; i++) {
if (B[i])  free(B[i]);
}
    }
    free(B);
if (C) {
for (int i = 0; i < n; i++) {
if (C[i])  free(C[i]);
}
 }
 free(C);

return ret;
}


//--------------------------------------------
//  Sub routine M x M
//--------------------------------------------
bool MxM(double** M1, double** M2, double** Mout, int n)
{
double s;

if(n<1) return false;  //error

//M1 x M2
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
s=0.0;
for (int k = 0; k < n; k++) {
s=s + M1[i][k] * M2[k][j];
}
Mout[i][j]=s;
}
}
return true;
}

次のページ →
FORTRAN77言語とC言語の基本的な相違点 (2)

「有限要素法における平面トラスの解析」プログラムをC言語で書いてみる : 目次