(Stokes方程式を有限要素法で解くときのプログラムの書き方は、 公開していなかったっけ… おおむね川原 [2] に従って書いてあります。)
/*
* stokes3.c --- 定常 Stokes 問題の有限要素解を求めるプログラム
* 連立1次方程式を解くために LAPACK を利用
*
* oyabun でのコンパイル
* g77 -I/usr/local/include -O -o stokes3 stokes3.c -llapack -lblas -lmatrix
*/
/* 実行は ./file_name 領域データ 流速の保存ファイル名 圧力の保存ファイル名 */
#include <math.h>
#include <stdio.h>
#include <matrix.h>
#define USELAPACK
void dgbsv_(int *n, int *kl, int *ku, int *nrhs,
double *AB, int *ldab, int *ipiv, double *b, int *ldb, int *info);
int max(int a, int b) { return (a > b) ? a : b; }
int min(int a, int b) { return (a < b) ? a : b; }
/* 一次元配列で計算するのは生で書くと大変なのでマクロで処理 */
#define AB(i,j) ab[(j)*nb+(kl+ku+(i)-(j))]
/* 関数定義*/
/* 全体係数マトリックス全体自由項ベクトルを生成する関数 */
void make_matrix(int T, vector ab, int kl, int ku, int nb,
vector u, double nu, double rho,
int **num, int *cum,
vector fx, vector fy, double hx, double hy)
{
int i,j,k,I,J;
double hx2,hy2,nurho;
matrix A = new_matrix(9,9);
matrix B = new_matrix(9,4);
matrix C = new_matrix(9,4);
matrix D = new_matrix(9,9);
hx2 = hx*hx; hy2 = hy*hy;
nurho = nu * rho;
for (i = 0; i < 9; i++) {
for (j = 0; j < 4; j++)
B[i][j] = C[i][j] = 0;
for (j = 0; j < 9; j++)
A[i][j] = D[i][j] = 0;
}
/* 行列Aの成分の入力*/
for (i=0; i<=3; i++)
A[i][i]= 28* (hx2 + hy2);
A[4][4]=A[6][6]= 112 * hx2 + 64 * hy2;
A[5][5]=A[7][7]= 64 * hx2 + 112 * hy2;
for (i=0;i<=3;i++)
A[i][8]= -16 * ( hx2 + hy2 );
A[4][5]=A[4][7]=A[5][6]=A[6][7]= -16 * ( hx2 + hy2 );
A[4][8]=A[6][8]= -128 * hx2 + 32 * hy2;
A[5][8]=A[7][8]= 32 * hx2 - 128 * hy2;
A[0][5]=A[1][7]=A[2][7]=A[3][5]= 8 * hx2 + 2 * hy2;
A[0][6]=A[1][6]=A[2][4]=A[3][4]= 2 * hx2 + 8 * hy2;
A[0][4]=A[1][4]=A[2][6]=A[3][6]= 14 * hx2 - 32 * hy2;
A[0][7]=A[1][5]=A[2][5]=A[3][7]= -32 * hx2 + 14 * hy2;
A[0][1]=A[2][3]= -7 * hx2 + 4 * hy2;
A[0][3]=A[1][2]= 4 * hx2 - 7 * hy2;
A[0][2]=A[1][3]= -hx2 - hy2;
A[4][6]= 16 * hx2 - 16 * hy2;
A[5][7]= -16 * hx2 + 16 * hy2;
A[8][8]= 256 * hx2 + 256 * hy2;
for (j=0;j<9;j++)
for (i=0;i<9;i++)
A[i][j] = A[j][i];
for (i=0;i<9;i++)
for (j=0;j<9;j++)
A[i][j] = (1.0/(90*hx*hy)) * A[i][j];
/* 行列Bの成分の入力*/
for(i=0;i<9;i++)
for(j=0;j<4;j++)
B[i][j]=0;
B[0][0]=B[3][3]=-25; B[1][1]=B[2][2]=25;
B[1][0]=B[2][3]=5; B[0][1]=B[3][2]=-5;
B[4][0]=B[6][3]=20; B[4][1]=B[6][2]=-20;
B[5][0]=B[5][3]=10; B[5][1]=B[5][2]=50;
B[7][0]=B[7][3]=-50; B[7][1]=B[7][2]=-10;
B[8][0]=B[8][3]=40; B[8][1]=B[8][2]=-40;
for (i=0;i<9;i++)
for (j=0;j<4;j++)
B[i][j] = (hy/180.0) * B[i][j];
/* 行列Cの成分の入力*/
for(i=0;i<9;i++)
for(j=0;j<4;j++)
C[i][j]=0;
C[0][0]=C[1][1]=-25;
C[2][2]=C[3][3]=25;
C[0][3]=C[1][2]=-5;
C[3][0]=C[2][1]=5;
C[4][0]=C[4][1]=-50;
C[4][2]=C[4][3]=-10;
C[5][1]=C[7][0]=20;
C[5][2]=C[7][3]=-20;
C[6][0]=C[6][1]=10;
C[6][2]=C[6][3]=50;
C[8][0]=C[8][1]=40;
C[8][2]=C[8][3]=-40;
for (i=0;i<9;i++)
for (j=0;j<4;j++)
C[i][j] = (hx/180.0) * C[i][j];
/* 行列Dの成分の入力 */
for(i=0;i<=3;i++)
D[i][i]=16;
for(i=4;i<=7;i++)
D[i][i]=64;
for(i=0;i<=3;i++)
D[i][8]=4;
D[4][5]=D[4][7]=D[5][6]=D[6][7]=4;
for(i=4;i<=7;i++)
D[i][8]=32;
D[0][5]=D[0][6]=D[1][6]=D[1][7]=D[2][4]=D[2][7]=D[3][4]=D[3][5]=-2;
D[0][4]=D[0][7]=D[1][4]=D[1][5]=D[2][5]=D[2][6]=D[3][6]=D[3][7]=8;
D[0][1]=D[0][3]=D[1][2]=D[2][3]=-4;
D[0][2]=D[1][3]=1;
D[4][6]=D[5][7]=-16;
D[8][8]=256;
for (j=0;j<9;j++)
for (i=0;i<9;i++)
D[i][j]=D[j][i];
for (i=0;i<9;i++)
for (j=0;j<9;j++)
D[i][j] = (hx*hy/900.0) * D[i][j];
/* 直接剛性法 */
for (k=0;k<T;k++){
for (i=0;i<9;i++){
I = cum[num[k][i]];
for (j=0;j<9;j++) {
J = cum[num[k][j]];
AB(I,J) += nurho * A[i][j];
AB(I+1,J+1) += nurho * A[i][j];
}
for (j=0;j<4;j++){
J = cum[num[k][j]];
AB(I,J+2) -= B[i][j];
AB(I+1,J+2) -= C[i][j];
AB(J+2,I) -= B[i][j];
AB(J+2,I+1) -= C[i][j];
}
for (j=0;j<9;j++) {
u[I] += rho*D[i][j]*fx[num[k][j]];
u[I+1] += rho*D[i][j]*fy[num[k][j]];
}
}
}
free_matrix(A);
free_matrix(B);
free_matrix(C);
free_matrix(D);
}
void change(int n, vector ab, int kl, int ku, int nb,
int k)
{
int i,j;
for (i = max(0,k-ku); i <= min(n-1,k+kl); i++)
AB(i,k) = 0.0;
for (j = max(0,k-kl); j <= min(n-1,k+ku); j++)
AB(k,j) = 0.0;
AB(k,k) = 1.0;
}
void bound(vector ab, int kl, int ku, int nb,
vector u, int *b, vector bx, vector by,
int D, int *cum, int n)
{
int j,i,k;
for (k = 0; k < D; k++) {
j = cum[b[k]];
/* j列を移項 */
for (i = max(0,j-ku); i <= min(n-1,j+kl); i++)
u[i] -= AB(i,j) * bx[k];
u[j] = bx[k];
change(n, ab, kl, ku, nb, j);
/* j+1列を移項 */
j++;
for (i = max(0,j-ku); i <= min(n-1,j+kl); i++)
u[i] -= AB(i,j) * by[k];
u[j] = by[k];
change(n, ab, kl, ku, nb, j);
}
change(n, ab, kl, ku, nb, 2);
u[2] = 0.0;
}
/* main文*/
int main(int argc, char **argv)
{
/**************** 変数宣言***************/
int i,j;
/* 入力ファイル、出力ファイル*/
FILE *f1,*f2,*f3;
/* nelmt:要素数, nnode:総接点数, num_unknown:未知数の総数, nband:半バンド幅 */
int nnode,nelmt,num_unknown,nband,cum_tmp,max_cum,min_cum;
/* nDir: Dirichlet境界上の節点の総数*/
int nDir;
int *cum, **num, *b;
/* nu:粘性定数, rho:密度, hx,hy:x,yについてのメッシュ幅*/
double nu,rho,hx,hy;
/* bx,by:境界値, fx,fy:外力密度 */
vector x,y,bx,by,fx,fy;
/* 全体自由項ベクトル*/
vector u;
/* 全体係数マトリックス*/
int n,ku,kl,nb,ldab,ldb,nrhs,info;
ivector ipvt;
vector ab;
if (argc != 4) {
fprintf(stderr,
"usage: %s <入力データ> <流速データ> <圧力データ>\n", argv[0]);
exit(1);
}
if ((f1 = fopen(argv[1],"r")) == NULL){
fprintf(stderr, "Can't open %s",argv[1]);
exit(1);
}
/* 総要素数, 総節点数を読む */
fscanf(f1, "%d %d %lf %lf", &nelmt, &nnode, &hx, &hy);
printf("要素数,総節点数,hx,hy=\n%d %d %f %f\n", nelmt, nnode, hx, hy);
x = new_vector(nnode);
y = new_vector(nnode);
if (x == NULL || y == NULL) {
fprintf(stderr, "節点座標を記憶するメモリが確保できません。");
exit(1);
}
if ((num = malloc(nelmt * sizeof(void *))) == NULL) {
fprintf(stderr, "要素と節点の対応用のメモリーが足りません\n");
exit(1);
}
for (i=0;i<nelmt;i++) {
num[i] = malloc(sizeof(int) * 9);
if (num[i] == NULL) {
fprintf(stderr, "要素と節点の対応用のメモリーが足りません\n");
exit(1);
}
}
if ((cum = malloc(sizeof(int) * nnode)) == NULL) {
fprintf(stderr, "累積節点番号用のメモリーが足りません \n");
exit(1);
}
/* 節点の座標、要素節点番号対応表、累積節点番号表、総節点数の読み込み */
for (i=0;i<nnode;i++)
fscanf(f1, "%lf %lf", &x[i], &y[i]);
for (i=0;i<nelmt;i++)
for (j=0;j<9;j++)
fscanf(f1, "%d", &num[i][j]);
for (i=0;i<nnode;i++)
fscanf(f1, "%d", &cum[i]); /* i:全体節点番号, cum:累積節点番号 */
fscanf(f1, "%d", &num_unknown);
printf("未知数の個数=%d\n", num_unknown);
if ((u = new_vector(num_unknown)) == NULL) {
fprintf(stderr, "近似解を記憶するメモリーが不足しています。");
exit(1);
}
/* 半バンド幅 nband の評価 */
nband=0;
for (i=0;i<nelmt;i++){
max_cum=0;
min_cum=num_unknown;
for (j=0;j<9;j++) {
cum_tmp=cum[num[i][j]];
if (max_cum < cum_tmp) max_cum = cum_tmp;
if (min_cum > cum_tmp) min_cum = cum_tmp;
}
if (nband < max_cum - min_cum) nband = max_cum - min_cum;
}
printf("半バンド幅=%d\n", nband);
for (i = 0; i < num_unknown; i++)
u[i] = 0;
kl = ku = nband + 2;
nb = 2 * kl + ku + 1;
n = num_unknown;
ab = new_vector(nb * n);
ipvt = new_ivector(n);
if (ab == NULL || ipvt == NULL) {
fprintf(stderr, "係数行列を記憶するメモリーが足りません\n");
exit(1);
}
for (i = 0; i < (nb * n); i++)
ab[i] = 0;
fscanf(f1, "%lf %lf", &nu, &rho);
fscanf(f1, "%d", &nDir);
printf("ν,ρ=\n%f %f\n", nu, rho);
printf("境界上の節点=%d\n", nDir);
if ((b = malloc(sizeof(int) * nDir)) == NULL){
fprintf(stderr, "境界の番号用のメモリーが足りません。\n");
exit(0);
}
bx = new_vector(nDir);
by = new_vector(nDir);
if (bx == NULL || by == NULL) {
fprintf(stderr, "境界値データを読み込むためのメモリーがありません。");
exit(1);
}
for (i = 0; i < nDir; i++)
fscanf(f1, "%d %lf %lf", &b[i], &bx[i], &by[i]); /* 境界値 (u,v) */
fx = new_vector(nnode);
fy = new_vector(nnode);
if (fx == NULL || fy == NULL) {
fprintf(stderr, "外力データを読み込むためのメモリーがありません。");
exit(1);
}
for (i = 0; i < nnode; i++)
fscanf(f1, "%lf %lf", &fx[i], &fy[i]); /* 外力のx,y成分 */
fclose(f1);
/* 全体係数マトリックス、全体自由項ベクトルの生成 */
make_matrix(nelmt,ab,kl,ku,nb,
u,nu,rho,num,cum,fx,fy,hx,hy);
bound(ab,kl,ku,nb,
u,b,bx,by,nDir,cum,num_unknown);
free(num);
free_vector(fx);
free_vector(fy);
free(b); /*free(cum);*/
free_vector(bx); free_vector(by);
/* 連立一次方程式を解く */
nrhs = 1;
ldab = nb;
ldb = n;
dgbsv_(&n, &kl, &ku, &nrhs, ab, &ldab, ipvt, u, &ldb, &info);
if (info == 0)
printf(" successful\n");
else if (info > 0)
printf(" U is singular\n");
else
printf("%d-th argument has illegal value.\n", abs(info));
printf(" return from dgbsv\n");
/* 計算結果をファイルへ出力 */
if ((f2 = fopen(argv[2],"w")) == NULL) {
printf("Can't open %s",argv[2]);
exit(2);
}
if ((f3 = fopen(argv[3],"w")) == NULL) {
printf("Can't open %s",argv[3]);
exit(3);
}
j=0;
for(i=0;i<num_unknown-3;){
fprintf(f2, "%f %f %f %f\n", x[j], y[j], u[i], u[i+1]);
if(cum[j+1]-cum[j]==3){
fprintf(f3, "%f %f %f\n", x[j], y[j], u[i+2]);
i++;
if(x[j+1]!=x[j]){
fprintf(f3,"\n");
}
}
i=i+2;
j++;
}
fprintf(f2, "%f %f %f %f\n", x[nnode-1], y[nnode-1], u[num_unknown-3], u[num_unknown-2]);
fprintf(f3, "%f %f %f\n", x[nnode-1], y[nnode-1], u[num_unknown-1]);
fclose(f2);
fclose(f3);
return 0;
}
桂田 祐史