Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

KM2016 / Elliptic / fem4

.pdf
Скачиваний:
10
Добавлен:
14.03.2016
Размер:
55.63 Кб
Скачать

Приложение к разделу 4 Линейное уравнение общего вида

fem4.h

#include <ctype.h> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <string.h>

static double funD( double xi, double bi []); static double funC( double xi, double bi []); static double funA( double xi, double bi []); static double fun_q( double xi, double bi []);

void K_ij(int N, double K [], double x [], double bi [], double a, double (*funD)( double xi, double bi []),

double (*funC)( double xi, double bi []), double (*funA)( double xi, double bi []));

void q_i(int , double [], double [], double [], double (*)( double, double *)); double domik(double x, int j, int mp, double *xx);

double intgD(int, int, double *, double *, double (*)(double, double *));

double intgCq(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);

fem4.cpp

#include "fem4.h"

static double funD( double xi, double b []) {

double D [] = {1.0, 0.5}; // Задаём коэффициенты диффузии int Ni;

// Находим в каком слое находится координата xi if (xi<=b[1]) Ni = 0;

else Ni = 1; return D[Ni];

}

static double funC( double xi, double b []) {

double C [] = {0.3, 0.6}; // Задаём коэффициенты конвекции int Ni;

// Находим в каком слое находится координата xi if (xi<=b[1]) Ni = 0;

else Ni = 1; return C[Ni];

}

static double funA( double xi, double b []) {

double A [] = {0.7, 0.4}; // Задаём коэффициенты поглощения int Ni;

// Находим в каком слое находится координата xi if (xi<=b[1]) Ni = 0;

else Ni = 1; return A[Ni];

}

static double fun_q( double xi, double b []) { return (-6*xi + 1);

//return 3.14159*3.14159*sin(3.14159*x); // return x*x*x*x;

}

int main(int argc,char *argv[]) { double a, *bx, *step, *hp, *hm; int NL, *ib, knots_N, test; double *x, h, x_max;

double *K, *q, *solution, result;

NL = 2; //число слоёв

a = 0.5; // коэффициент в граничном условии

double b[3] = {0.0, 0.2, 1.0}; // координаты границ слоёв

int N[2] = {3, 3}; // задаём число узлов внутри слоя, не считая узел на правой границе

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[i]; } //задаём номера - индексы - узлов на границах bx[0] = 0.0;

for (int i = 0; i < NL; i++) { // шаг в слое и координаты левых границ слоёв (должны совпадать с b[i]) step[i] = (b[i+1]-b[i])/N[i];

bx[i+1] = b[i] + step[i]*N[i];

}

knots_N = ib[NL]+1; // всего узлов, считая узел в начале координат x = new double[knots_N]; // выделение памяти для координат узлов

hp = new double[knots_N]; // выделение памяти для шага впрёд из данного узла hm = 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;

}

}

solution = new double[knots_N];

K_ij(knots_N, K, x, b , a, funD, funC, funA) ; // Матрица

q_i(knots_N, x, b, q, fun_q); //Правая часть матричного уравнения result = lufact(knots_N, K, q, solution);

test = 0;

result = output(test, knots_N, x, b, solution, "result.txt");

return 1;

}

//Вывод решения в файл

int output(int test, int N, double *x, double *b, double *solution, const char *filename) {

FILE *out;

 

 

out = fopen(filename, "wt");;

 

double u_i, x_i, sol_i, q_i;

 

int result;

 

 

if (test == 1) {

 

 

fprintf(out,"\n x

u(x)

solution\n");

for (int i=0;i<N;i++) { x_i = x[i];

u_i = pow(x_i,3.0) - x_i; //u_i = sin(3.14159*x_i); sol_i = solution[i];

fprintf(out,"%-12.3g%-12.7g%-12.7g\n",x_i, u_i, sol_i);

}

 

 

result = 1;

 

 

}

 

 

else if (test == 0) {

 

 

fprintf(out,"\n x

q(x)

solution\n");

for (int i=0;i<N;i++) { x_i = x[i];

sol_i = solution[i]; q_i = fun_q(x_i,b);

fprintf(out,"%-12.3g%-12.7g%-12.7g\n",x_i, q_i, sol_i);

}

result = 1;

}

else {

fprintf(out,"\n Sorry, no solution!\n"); result = 0;

}

fclose(out); return result;

}

void K_ij(int N, double K [], double x [], double b [], double a, double (*funD)( double xi, double b []),

double (*funC)( double xi, double b []), double (*funA)( double xi, double b [])) {

//Вычисление матричных коэффициентов уравнения Кu=q

//N - число узлов

//x[] - координаты узлов

//a - коэффициент в граничном условии

//funD, funC, funA - функциональные коэффициенты дифф. уравннения

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];

K[i] = -a + intgD(1, i, x, b, funD)/(hp*hp)

-intgCq(1, i, 1, x, b, funC, domik)/hp

-intgA(1, 0, 1, 0, 1, x, b, funA, domik);

}

else if (i==n && j==n) { // главная диагональ последняя строка, последний узел hm = x[n]-x[n-1];

K[i*N+i] = intgD(-1, i, x, b, funD)/(hm*hm) + intgCq(-1, i, -1, x, b, funC, domik)/hm - - intgA(-1, i, -1, j, -1, x, b, funA, domik);

}

else { // главная диагональ от второй до предпоследней строк hm = x[i]-x[i-1]; hp = x[i+1]-x[i];

K[i*N+i] = intgD(-1, i, x, b, funD)/(hm*hm) + intgD(1, i, x, b, funD)/(hp*hp)

+intgCq(-1, i, -1, x, b, funC, domik)/hm - intgCq(1, i, 1, x, b, funC, domik)/hp

-intgA(-1,i,-1, i, -1, x, b, funA, domik) - intgA(1, i, 1, i, 1, x, b, funA, domik);

}

}

else if ( (i-j)==1 ) { // под главной диагональю hm = x[i] - x[j];

K[i*N+j] = - intgD(-1, i, x, b, funD)/(hm*hm) - intgCq(1, i, 1, x, b, funC, domik)/hm

- intgA(-1, i, -1, i-1, 1, x, b, funA, domik);

}

else if ( (j-i)==1 ) { // над главной диагональю hp = x[j] - x[i];

D = intgD(1, i, x, b, funD)/(hp*hp);

C = intgCq(1, i, 1, x, b, funC, domik)/hp;

A = intgA(1, i, 1, i+1, -1, x, b, funA, domik); K[i*N+j] = - D + C - A;

}

else { K[i*N+j] = 0.; }

}

}

}

void q_i(int knots_N, double x [], double b[], double q[], double (*fun_q)( double xi, double b [])) { //построение правой части уравнения Кu=q

//knots_N - число узлов

//x[] - координаты узлов

//funq(x) - правая часть диф. уравнения

int n = knots_N - 1; // n - индекс последнего узла for (int i=0; i <= n; i++) {

if (i == 0) {

q[i] = intgCq(1, i, 1, x, b, fun_q, domik);

}

else if (i == n) {

q[i] = intgCq(-1, i, -1, x, b, fun_q, domik);

}

else {

q[i] = intgCq(-1, i, -1, x, b, fun_q, domik) + intgCq(1, i, 1, x, b, fun_q, domik);

}

}

}

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 (*fun)(double, double *) ) {

//Интегрируем функцию 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) + fun(x_kp, b) );

}

return s;

}

double intgCq(int mp, int i, int mpi, double *x, double *b, double (*fun)(double, double *), double (*domik)(double, int, int, double *)) {

//Интегрируем функцию fun * domik ( это funC,fun_q)

//i - индекс узла (строки для funq)

//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 = 3;

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) + domik(x_kp,i,mpi,x)*fun(x_kp, b) );

}

return s;

}

double intgA(int mp, int i, int mpi, int j, int mpj, double *x, double *b,

double (*fun)(double, double *), 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 = 3;

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)*domik(x_k,j,mpj,x) + domik(x_kp,i,mpi,x)*fun(x_kp, b)*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);

}

Соседние файлы в папке Elliptic