Добавил:
Upload
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:
// Приложение к разделу 4 Линейное уравнение общего вида
//fem4.h
/*
#include <ctype.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
static double funD( double xi, double b [], double alpha [], double r [], double d1 [], double t);
static double funC( double xi, double b [],double alpha [], double r [], double d1 [], double t);
static double funA( double xi, double b [],double alpha [], double t);
static double fun_q(int si, double x [],double b [], double alpha [],double r [],double tau1);
static double fun_a(int fb, double t, double alpha [], double r [])
void K_ij(int N, double K [], double x [], double b [], double t,
double alpha [], double r [], double d1 [],
double (*funD)(double xi, double b [], double alpha [], double r [], double d1 [], double t),
double (*funC)(double xi, double b [],double alpha [], double r [], double d1 [], double t),
double (*funA)(double xi, double b [],double alpha [], double t),
double (*fun_a)(int fb, double t, double alpha [], double r []) );
static double fun_q(int si, double x [],double b [], double alpha [],double r [],double tau1);
double domik(double x, int j, int mp, double *xx);
double intgD(int, int, double *, double *, double (*)(double, double *));
double intgC(int, int, int , double *, double *, double (*)(double, double *), double (*)(double, int, int, double *));
double intgA(int, int ,int, int , int , double *, double *, double (*)(double, double *), double (*)(double, int, int, double *));
int i_max(int N, int p, double V[]);
int lufact(int, double [], double [], double []);
void SaveToFile(int, double*, const char* );
int output(int test, int N, double* x, double *b, double *solution, const char* filename);
*/
#include "fem5_0.h"
static double funD( double xi, double b [], double alpha [], double r [], double d1 [], double t) {
// Вычисляем коэффициент диффузии по формуле (93)
int Ni; double a, value;
// Находим в каком слое находится координата xi
if (xi<=b[1]) Ni = 0;
else Ni = 1;
a = 2*alpha[Ni]-1;
value = r[Ni]*r[Ni]*alpha[Ni]/3/d1[Ni]*pow((1-t),a);
return value;
}
static double funC( double xi, double b [],double alpha [], double r [], double d1 [], double t) {
// Вычисляем коэффициент конвекции по формуле (94)
double a_1, a_0, value;
// Попадаем на границу?
/* if ( xi==b[1] ) {
a_0 = 2*alpha[0]-1;
a_1 = 2*alpha[1]-1;
value = - r[0]*r[0]*alpha[0]/3/d1[0]*pow((1-t),a_1) +
r[1]*r[1]*alpha[1]/3/d1[1]*pow((1-t),a_0);
}
else */
value = 0;
return value;
}
static double funA( double xi, double b [],double alpha [], double t) {
// Вычисляем коэффициент поглощения
int Ni; double value;
// Находим в каком слое находится координата xi
if (xi<=b[1]) Ni = 0;
else Ni = 1;
value = (1-alpha[Ni])/(1-t);
return value;
}
static double fun_q(int si, double x [],double b [], double alpha [],double r [],double tau) {
// Дельта - источник в узле с индексом si интегрируем по окрестности узла и по интервалу времени
double xi, hm, hp, value;
xi =x[si]; hm = x[si] - x[si-1]; hp = x[si+1] - x[si];
value = 1/alpha[0]/r[0]/(hm+hp)/tau;
return value;
}
static double fun_a(int fb, double t, double alpha [], double r []) {
double a, ras, value;
a = alpha[fb];
ras = r[fb];
value = 0.5*ras*a*pow((1-t),a-1);
return value;
}
int main(int argc,char *argv[]) {
double *bx, *step;
int NL, *ib, knots_N, test;
double *x, h, x_max, *tt, t, tau;
double *K, *q, *solution, *u, result;
double alpha[2] = {1.7, 0 }; // Задаём параметры диффузии
double r[2] = {1, 0};
double d1[2] = {2.5, 0};
NL = 1; //число слоёв
double b[2] = {0.0, 1.0}; // координаты границ слоёв
int N = 30; // задаём число узлов внутри слоя, не считая узел на правой границе
int si = 10; // Задаём индекс узла с источником электронов
int NT = 300; // Задаём число шагов по времени
tt = new double [NT+1];
tau = 1.0/NT;
bx = new double[NL+1];
step = new double[NL];
ib = new int [NL+1];
ib[0]=0;
for (int i=0; i <= NL; i++) { ib[i+1] = ib[i] + N; } //задаём номера - индексы - узлов на границах
bx[0] = 0.0;
for (int i = 0; i < NL; i++) { // шаг в слое и координаты левых границ слоёв (должны совпадать с b[i])
step[i] = (b[i+1]-b[i])/N;
bx[i+1] = b[i] + step[i]*N;
}
knots_N = ib[NL]+1; // всего узлов, считая узел в начале координат
x = new double[knots_N]; // выделение памяти для координат узлов
K = new double [knots_N*knots_N]; // выделение памяти для матрицы
q = new double[knots_N]; // выделение памяти для правой части
x[0] = 0.0; // помещаем начало координат на левую границу и задаём координаты узлов
for (int k = 0; k < NL; k++) {
for (int i = 1; i <= (ib[k+1] - ib[k]); i++) {
x[i+ib[k]] = bx[k] + step[k]*i;
}
}
SaveToFile(knots_N, x, "x.dat" );
solution = new double[knots_N];
u = new double[knots_N*NT];
for (int k = 0; k<1; k++) {
t = tau*k+0.5*tau;
tt[k] = t;
K_ij(knots_N, K, x, b, t, alpha, r, d1, funD, funC, funA, fun_a) ; // Матрица
q_i(k, q, knots_N, x, b, si, alpha, r, tau, fun_q ); //Правая часть матричного уравнения
SaveToFile(knots_N*knots_N, K, "K.dat" );
SaveToFile(knots_N, q, "q.dat" );
result = lufact(knots_N, K, q, solution);
SaveToFile(knots_N, solution, "sol.dat" );
for (int i = 0; i<knots_N; i++) {
q[i] = solution[i];
u[knots_N*k+i] = solution[i];
}
//Вывод решения в файл
}
AddToFile(knots_N*NT, u, "u.dat" );
return 1;
}
void K_ij(int N, double K [], double x [], double b [], double t,
double alpha [], double r [], double d1 [],
double (*funD)(double xi, double b [], double alpha [], double r [], double d1 [], double t),
double (*funC)(double xi, double b [],double alpha [], double r [], double d1 [], double t),
double (*funA)(double xi, double b [],double alpha [], double t),
double (*fun_a)(int fb, double t, double alpha [], double r []) ) {
// Вычисление матричных коэффициентов уравнения Кu=q
// N - число узлов
// K[] - матрица
// x[] - координаты узлов
// a - коэффициент в граничном условии
// funD, funC, funA, fun_a - функциональные коэффициенты дифф. уравннения
int n = N-1; // индекс узла на правой границе
double hm, hp, D, C, A;
for (int i=0; i < N; i++) {
for (int j=0; j < N; j++) {
if (i==j) { // главная диагональ
if (i==0 && j==0) { // главная диагональ первая строка левая граница
hp = x[1]-x[0];
D = intgD(1, i, x, b, alpha, r, d1, t, funD)/(hp*hp);
C = intgC(1, i, 1, x, b, alpha, r, d1, t, funC, domik)/hp;
A = intgA(1, 0, 1, 0, 1, x, b, alpha, t, funA, domik);
K[i] = - fun_a(0, t, alpha, r) + D - C - A;
}
else if (i==n && j==n) { // главная диагональ последняя строка, последний узел
hm = x[n]-x[n-1];
D = intgD(-1, i, x, b, alpha, r, d1, t, funD);
C = intgC(-1, i, -1, x, b, alpha, r, d1, t, funC, domik)/hm;
A = intgA(-1, i, -1, j, -1, x, b, alpha, t, funA, domik);
K[i*N+i] = fun_a(0, t, alpha, r) + D + C - A;
}
else { // главная диагональ от второй до предпоследней строк
hm = x[i]-x[i-1]; hp = x[i+1]-x[i];
D = intgD(-1, i, x, b, alpha, r, d1, t, funD)/(hm*hm)
+ intgD(1, i, x, b, alpha, r, d1, t, funD)/(hp*hp);
C = intgC(-1, i, -1, x, b,alpha, r, d1, t, funC, domik)/hm
- intgC(1, i, 1, x, b,alpha, r, d1, t, funC, domik)/hp;
A = intgA(-1,i,-1, i, -1, x, b, alpha, t, funA, domik)
- intgA(1, i, 1, i, 1, x, b, alpha, t, funA, domik);
K[i*N+i] = D + C - A;
}
}
else if ( (i-j)==1 ) { // под главной диагональю
hm = x[i] - x[j];
D = intgD(-1, i, x, b,alpha, r, d1, t, funD)/(hm*hm);
C = intgC(1, i, 1, x, b,alpha, r, d1, t, funC, domik)/hm;
A = intgA(-1, i, -1, i-1, 1, x, b, alpha, t, funA, domik);
K[i*N+j] = -D - C - A;
}
else if ( (j-i)==1 ) { // над главной диагональю
hp = x[j] - x[i];
D = intgD(1, i, x, b,alpha, r, d1, t, funD)/(hp*hp);
C = intgC(1, i, 1, x, b,alpha, r, d1, t, funC, domik)/hp;
A = intgA(1, i, 1, i+1, -1, x, b, alpha, t,funA, domik);
K[i*N+j] = - D + C - A;
}
else { K[i*N+j] = 0.; }
}
}
}
void q_i(int k, double q[],int knots_N, double x[], double b[],
int si, double alpha[],double r[],double tau,
double (*fun_q)(int, double *,double *,
double *,double *,double) ) {
//построение правой части уравнения Кu=q
// knots_N - число узлов
// x[] - координаты узлов
// fun_q(x,t) - источник электронов
int n = knots_N - 1; // n - индекс последнего узла
for (int i=0; i <= n; i++) {
if ((i == si) && (k == 0)) {
q[i] = fun_q(si, x, b, alpha, r, tau);
}
else q[i] = 0;
}
}
double domik(double x, int j, int mp, double *xx) {
// Пробная функция
// x - переменная интегрирования
// j - индекс узла
// mp = 1 - интегрируем вперёд, = -1 - назад
// xx[] - координаты всех узлов
// x_j - координата узла крыши домика
// h - шаг между узлами
double x_j, h, value ;
x_j = xx[j];
if (mp > 0) {
h = xx[j+1] - x_j;
value = -1.0/h*(x - x_j - h);
}
else {
h = x_j - xx[j-1];
value = 1.0/h*(x - x_j + h);
}
return value;
}
double intgD(int mp, int i, double *x, double *b,
double alpha [], double r [], double d1 [], double t,
double (*fun)( double xi, double b [], double alpha [], double r [], double d1 [], double t)) {
// Интегрируем функцию funD из j-того узла i-той строки
// i - индекс строки, j - индекс узла
// mp - направление интегрирования от узла с индексом равным индексу строки: вперёд 1, или назад -1
// x[] - координаты узлов
// b [] - координаты границ слоёв
// fun(x,b) - интегрируемая функция, x - переменная интегрирования
int m = 10;
double x0, h, dh, x_k, x_kp, s;
if (mp > 0) { // интегрируем вперёд от узла с индексом равным индексу строки
x0 = x[i]; // нижний предел интеграла
h = x[i+1] - x0;
}
else { // интегрируем назад
x0 = x[i-1];
h = x[i] - x0;
}
dh = h/m; // шаг интегрирования
s = 0;
for (int k=0; k<m; k++) {
x_k = x0 + dh*k;
x_kp = x_k + dh;
s = s + 0.5*dh*(fun(x_k, b, alpha, r, d1, t ) + fun(x_kp, b, alpha, r, d1, t) );
}
return s;
}
double intgC(int mp, int i, int mpi, double *x, double *b,
double alpha [], double r [], double d1 [], double t,
double (*fun)( double xi, double b [], double alpha [], double r [], double d1 [], double t),
double (*domik)(double, int, int, double *)) {
// Интегрируем функцию fun * domik (fun - это funC)
// i - индекс узла
// mpi - верхний индекс у пробной функции "домик"
// mp = 1 интегрируем на шаг вперёд, или -1 назад из этого узла
// b [] - координаты границ слоёв
// x[] - координаты узлов
// fun(x,b) - интегрируемая функция, x - переменная интегрирования
// domik(x,j,mp,xx[]) - x - переменная интегрирования, j -индекс узла,
double x0, h, dh, x_k, x_kp, s;
int m = 10;
if (mp < 0 ) { // интегрируем назад
x0 = x[i-1]; // нижний предел интеграла
h = x[i] - x0;
}
else { // интегрируем вперёд
x0 = x[i];
h = x[i+1] - x0;
}
dh = h/m;
s = 0;
for (int k=0; k<m; k++) {
x_k = x0 + dh*k;
x_kp = x_k + dh;
s = s + 0.5*dh*( domik(x_k,i,mpi,x)*fun(x_k, b, alpha, r, d1, t )
+ domik(x_kp,i,mpi,x)*fun(x_kp, b, alpha, r, d1, t) );
}
return s;
}
double intgA(int mp, int i, int mpi, int j, int mpj, double *x, double *b, double *alpha, double t,
double (*fun)( double xi, double b [],double alpha [], double t),
double (*domik)(double, int, int, double *)) {
// Интегрируем функцию domik*funA*domik
// mp - направление интегрирования от узла с индексом равным индексу строки: вперёд 1, или назад -1
// i - индекс узла равный индексу строки
// j - индекс того же или соседнего справа или слева узла
// mpi, mpj = (+) (-) - верхние индексы у пробной функции "домик"
// b [] - координаты границ слоёв
// x[] - координаты узлов
// fun(x,b) - интегрируемая функция, x - переменная интегрирования
// domik(x,j,mp,xx[]) - x - переменная интегрирования, j -индекс узла,
int m = 10;
double x_j, x0, h, dh, x_k, x_kp, s;
if (mp<0) { // интегрируем назад
x0 = x[i-1]; // нижний предел интеграла
h = x[i] - x0;
}
else { // интегрируем вперёд
x0 = x[i];
h = x[i+1]- x0;
}
dh = h/m;
s = 0;
for (int k=0; k<m; k++) {
x_k = x0 + dh*k;
x_kp = x_k + dh;
s = s + 0.5*dh*( domik(x_k,i,mpi,x)*fun(x_k, b, alpha, t)*domik(x_k,j,mpj,x) +
domik(x_kp,i,mpi,x)*fun(x_kp, b, alpha, t)*domik(x_kp,j,mpj,x) );
}
return s;
}
int lufact(int N, double A [], double q[], double solution[]) {
// Вход - K - матрица размера NxN
// - q - матрица размера Nx1
// Выход - Х - матрица размера Nx1, содержащая решение KX=q
// Инициализация X, Y, временное сохранение матрицы С и строк
// заданной матрицы перестановок R
// double A[500][500];
double *X, *Y, *C, *V, mult;
int *R, *J, ip, d, result;
X = new double[N];
Y = new double[N];
C = new double[N];
V = new double[N];
R = new int [N];
J = new int [N];
for (int i = 0; i < N; i++) {
X[i] = 0.0; Y[i] = 0.0; C[i] = 0.0; J[i] = 0;
R[i] = i;
}
int j;
for (int p=0; p < N; p++) {
// Выписываем столбец p
for (int i=0; i < N; i++) {
V[i] = A[i*N+p];
}
// Находим номер строки главного элемента для столбца p
j = i_max(N,p,V);
J[p] = j; // смещение строки с главным элементом относительно строки p
// Меняем местами строки p и j
for (int i=0; i < N; i++) {
// Записывваем p-ю строку в С
C[i] = A[p*N+i];
}
// Записываем в p+j-ую строку p-ую строку
for (int i=0; i < N; i++) {
A[p*N+i] = A[(p+j)*N+i];
}
// Записываем p-ую строку в p+j-ую строку
for (int i=0; i < N; i++) {
A[(p+j)*N+i] = C[i];
}
d = R[p];
R[p] = R[p+j];
R[p+j] = d;
if (A[p*N+p] == 0) {
printf("Матрица вырождена. Нет единственного решения!");
result = 0;
return result;
}
// Вычисление множителя и размещение под диагональю матрицы К
for (int k=p+1; k<N; k++) {
mult = A[k*N+p]/A[p*N+p];
A[k*N+p] = mult;
for (int i = p+1; i<N; i++) {
A[k*N+i] = A[k*N+i] - mult*A[p*N+i];
}
}
}
// Прямая прогонка: Решение для Y
Y[0] = q[R[0]];
//Y[0] = q[0];
double M;
for (int k=1; k<N; k++) {
M = 0.0;
for (int i=0; i<k; i++) { // Скалярное произведение векторов
M = M + A[k*N+i]*Y[i];
}
Y[k] = q[R[k]] - M;
// Y[k] = q[k] - M;
}
// Обратная прогонка: Решение для X
X[N-1] = Y[N-1]/A[(N-1)*N+N-1];
solution[N-1] = X[N-1];
for (int k=N-2; k>=0; k--) {
M = 0.0;
for (int i=k+1; i<N; i++) {
M = M + A[k*N+i]*X[i];
}
X[k] = (Y[k] - M)/A[k*N+k];
solution[k] = X[k];
}
result = 1;
return result;
}
int i_max(int N, int p, double V[]) {
int max_i;
max_i = 0;
for (int i=p; i < N-2; i++) {
if ( fabs(V[i+1]) > fabs(V[i]) ) max_i = i+1-p;
}
return max_i;
}
void SaveToFile(int knots_N, double* x, const char* filename)
{
FILE *out;
out = fopen(filename, "wt");;
for (int i=0; i < knots_N; i++)
{
fprintf(out,"%g\n",x[i]);
}
fclose(out);
}
void AddToFile(int knots_N, double* x, const char* filename)
{
FILE *out;
out = fopen(filename, "wa");;
for (int i=0; i < knots_N; i++)
{
fprintf(out,"%g\n",x[i]);
}
fclose(out);
}