二维热传导离散数值解

时间:2022-12-16 18:00:15

Crank_Nicolson.h

#include <GL/glut.h>  
#include <stdio.h>  
#include <stdlib.h>
#include <iostream>
#include <malloc.h>
#include <math.h>
int xnseg_ = 100;
int ynseg_ = 100;
int tnseg_ = 100;
struct Heat {
		double u[101][101];
};
struct Heat heat[101];
struct Heat_h {
		double u_h[101][101];
};
struct Heat_h heat_h[100];
double xx[101];
double yy[101];
/////////////////////////////////////////////////////////////////////////
class Crank_Nicolson {
public :
   Crank_Nicolson(void);
	void clear(void);
	void clear_index(void);
	~Crank_Nicolson(void) { clear(); }
public :
	void set_init_funct0(double (*_funct0)(double _x, double _y)) { funct0_ = _funct0; }
	void set_init_funcx0(double (*_funcx0)(double _y, double _t)) { funcx0_ = _funcx0; } //初始条件 u(x,0)=f(x)
	void set_init_funcxn(double (*_funcxn)(double _y, double _t)) { funcxn_ = _funcxn; }
	void set_init_funcy0(double (*_funcy0)(double _x, double _t)) { funcy0_ = _funcy0; } //初始条件 u(x,0)=f(x)
	void set_init_funcyn(double (*_funcyn)(double _x, double _t)) { funcyn_ = _funcyn; }
	void setSegment(double _xbgn, double _xend, double _ybgn, double _yend); //_xbgn,_xend分别为数组 x 的初值和末值; _xnseg为将x 分成的段数
	void init_arrays(double _tbgn, double _tvary); //_tbgn为起始时间, _tseg为将时间分成的段数, _tvary为相邻时间的差值
	void set_c(double _c); //设置温度系数c
	void get_rx(void); //计算系数r
	void get_ry(void);
	void init_index_hf(int layer, int row);
	void guassi_hf();
	void calculate_hf_onerow(int layer, int row);
	void calculate_hf_onelayer(int layer);
	void init_index(int layer, int col);
	void guassi();
	void calculate_onecol(int layer, int col);
	void calculate_onelayer(int layer);
	void calculate(void); //计算不同时间不同位置处的温度, 并将结果放入数组二维u 
	void show_layer(int layer);
private :
	double xbgn_, xend_, ybgn_, yend_, tbgn_, tvary_; //tvary_为相邻时间的差值
	double c_, rx_, ry_;
	double (*funct0_)(double,double);
	double (*funcx0_)(double,double);
	double (*funcxn_)(double,double);
	double (*funcy0_)(double,double);
	double (*funcyn_)(double,double);
	double *y, *x, *t; //t 存放时间, x存放位置
	double *t_h;
	double *index1;
	double *index2;
	double *index3;
	double *result;
};

 file.h

/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
#include "Crank_Nicolson.h"


/////////////////////////////////////////////////////////////////////////////////////////
Crank_Nicolson::Crank_Nicolson() {
	xbgn_ = 0;	xend_ = 0;	ybgn_ = 0;	yend_ = 0;
	tbgn_ = 0;	tvary_ = 0;
	c_ = 0;		rx_ = 0;	ry_ = 0;
	y = NULL;	x = NULL;	t = NULL;	t_h = NULL;
}


////////////////////////////////////////////////////////////////////////////////////////////
void Crank_Nicolson::clear() {
	if(y)
		delete []y;
	if(x)
		delete []x;
	if(t)
		delete []t;
}



/////////////////////////////////////////////////////////////////////////////////
void Crank_Nicolson::setSegment(double _xbgn, double _xend, double _ybgn, double _yend) {
	if(_xbgn >= _xend) {
		std::cout << "Err: range of X is wrong." << '\n';
		exit(0); 
	}	
	if(_ybgn >= _yend) {
		std::cout << "Err: range of y is wrong." << '\n';
		exit(0); 
	}
	xbgn_ = _xbgn;	
	xend_ = _xend;

	ybgn_ = _ybgn;	
	yend_ = _yend;
}


//////////////////////////////////////////////////////////////////////////////
void Crank_Nicolson::init_arrays(double _tbgn, double _tvary) {
	clear();
	if(_tbgn < 0) {
		std::cout << "Err: t is NOT defined at all." << '\n';
		exit(0); 
	}	
	if(_tvary < 0) {
		std::cout << "Err: tvary is NOT defined at all." << '\n';
		exit(0); 
	}
	tbgn_ = _tbgn;	tvary_ = _tvary;
	
	index1 = (double *) malloc ((xnseg_-2)*sizeof(double));
	index2 = (double *) malloc ((xnseg_-1)*sizeof(double));
	index3 = (double *) malloc ((xnseg_-2)*sizeof(double));
	result = (double *) malloc ((xnseg_-1)*sizeof(double));
		
	y = (double *)malloc((ynseg_+1)*sizeof(double));
	x = (double *)malloc((xnseg_+1)*sizeof(double));
	t = (double *)malloc((tnseg_+1)*sizeof(double));
	t_h = (double *)malloc((tnseg_)*sizeof(double));
	
	*(t+0) = tbgn_;
	for(int i = 1; i <= tnseg_; i++)
		*(t+i) = *(t+i-1) + tvary_;

	*(t_h+0) = tbgn_+(1.0/2)*tvary_;
	for(i = 1; i < tnseg_; i++)
		*(t_h+i) = *(t_h+i-1) + tvary_;

	*(y+0) = ybgn_;
	yy[0]=*(y+0);
	double yi = (yend_ - ybgn_) / ynseg_;
	for(i = 1; i <= ynseg_; i++) {
		*(y+i) = *(y+i-1) + yi;
		yy[i]=*(y+i);
	}

	*(x+0) = xbgn_;
	xx[0]=*(x+0);
	double xi = (xend_ - xbgn_) / xnseg_;
	for (i = 1; i <= xnseg_; i++) { 
		*(x+i) = *(x+ i-1) + xi;
		xx[i]=*(x+i);
	}

	for (int j=0; j<=tnseg_; j++) {
		for (i = 0; i <= ynseg_ ; i++) {
			heat[j].u[0][i] = funcx0_(*(y+i),*(t+i));
			heat[j].u[xnseg_][i] = funcxn_(*(y+i),*(t+i));
		}
		for (i = 1; i < xnseg_ ; i++) {
			heat[j].u[i][0] = funcy0_(*(x+i),*(t+i));
			heat[j].u[i][ynseg_] = funcyn_(*(x+i),*(t+i));
		}
	}
	
	for (j=0; j<tnseg_; j++) {
		for (i = 0; i <= ynseg_ ; i++) {
			heat_h[j].u_h[0][i] = funcx0_(*(y+i),*(t_h+i));
			heat_h[j].u_h[xnseg_][i] = funcxn_(*(y+i),*(t_h+i));
		}
		for (i = 1; i < xnseg_ ; i++) {
			heat_h[j].u_h[i][0] = funcy0_(*(x+i),*(t_h+i));
			heat_h[j].u_h[i][ynseg_] = funcyn_(*(x+i),*(t_h+i));
		}
	}

	//initial condition: u(x,0)=f(x)
	for (i = 1; i< xnseg_; i++) 
		for(int j=1; j<ynseg_; j++)
			heat[0].u[i][j] = funct0_ (*(x+i),*(y+j)); //equation func_(float) has been identified before
}

//////////////////////////////////////////
void Crank_Nicolson::set_c(double _c) {
	c_ = _c;
}

////////////////////////////////////////////////
void Crank_Nicolson::get_rx() {
	double xi = (xend_ - xbgn_) / xnseg_; 
	rx_ = (c_*tvary_) / (xi*xi);
	std::cout << "rx = " << rx_ << '\n';
}
void Crank_Nicolson::get_ry() {
	double yi = (yend_ - ybgn_) / ynseg_; 
	ry_ = (c_*tvary_) / (yi*yi);
	std::cout << "ry = " << ry_ << '\n';
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////new!!!!!!!!
void Crank_Nicolson::init_index_hf(int layer, int row) { //从0 1 开始 row 到 ynseg_-1 结束
	*(index2+1) = 1+rx_;
	*(index3+1) = -1*rx_*(1.0/2);
	*(result+1) = 1.0/2*rx_*heat[layer].u[1][row-1] + (1-rx_)*heat[layer].u[1][row] + 1.0/2*rx_*heat[layer].u[1][row+1] +1.0/2*rx_*heat_h[layer].u_h[0][row];
	for(int i = 2; i < xnseg_-1; i++) {
		*(index1+i) = -1*rx_*(1.0/2);
		*(index2+i) = 1+rx_;
		*(index3+i) = -1*rx_*(1.0/2);
		*(result+i) = 1.0/2*rx_*heat[layer].u[i][row-1] + (1-rx_)*heat[layer].u[i][row] + 1.0/2*rx_*heat[layer].u[i][row+1];
	}
	*(index1+i) = -1*rx_*(1.0/2);
	*(index2+i) = 1+rx_;
	*(result+i) = 1.0/2*rx_*heat[layer].u[i][row-1] + (1-rx_)*heat[layer].u[i][row] + 1.0/2*rx_*heat[layer].u[i][row+1] + 1.0/2*rx_*heat_h[layer].u_h[xnseg_][row];
}

void Crank_Nicolson::guassi_hf() {
	for (int i = 2; i < xnseg_-1; i++) {
		*(index2+i) = (*(index2+i)) * ( (-1)*(*(index2+i-1)) / (*(index1+i)) ) + (*(index3+i-1));
		*(index3+i) = (*(index3+i)) * ( (-1)*(*(index2+i-1)) / (*(index1+i)) );
		*(result+i) = (*(result+i)) * ( (-1)*(*(index2+i-1)) / (*(index1+i)) ) + (*(result+i-1));
		*(index1+i) = 0;
	}
	*(index2+i) = (*(index2+i)) * ( (-1)*(*(index2+i-1)) / (*(index1+i)) ) + (*(index3+i-1));
	*(result+i) = (*(result+i)) * ( (-1)*(*(index2+i-1)) / (*(index1+i)) ) + (*(result+i-1));
	*(index1+i) = 0;
}

void Crank_Nicolson::calculate_hf_onerow(int layer, int row) { //0,1
	init_index_hf(layer, row);
	guassi_hf();

	double y_pre;
	y_pre = ( (*(result+xnseg_-1)) ) / (*(index2+xnseg_-1));
	double y_next = y_pre;
	heat_h[layer].u_h[xnseg_-1][row] = y_next;
	for (int i = xnseg_-2; i > 1; i--) {
		y_pre  = ( (*(result+i)) - ( (*(index3+i)) * y_next ) ) / (*(index2+i));
		heat_h[layer].u_h[i][row] = y_pre;
		y_next = y_pre;
	}
	y_pre = ( *(result+1) - (*(index3+1))*y_next) / (*(index2+1));
	heat_h[layer].u_h[i][row] = y_pre;
}
void Crank_Nicolson::calculate_hf_onelayer(int layer) { //0~tnseg_-1
	int row;
	for(row=1; row<ynseg_; row++)
		calculate_hf_onerow(layer, row);
}

void Crank_Nicolson::init_index(int layer, int col) { //从0 1 开始 col 到 xnseg_-1 结束
	*(index2+1) = 1+rx_;
	*(index3+1) = -1*rx_*(1.0/2);
	*(result+1) = 1.0/2*rx_*heat_h[layer].u_h[col-1][1] + (1-rx_)*heat_h[layer].u_h[col][1] + 1.0/2*rx_*heat_h[layer].u_h[col+1][1] +(1.0/2)*rx_*heat[layer+1].u[col][0];
	for(int i = 2; i < ynseg_-1; i++) {
		*(index1+i) = -1*rx_*(1.0/2);
		*(index2+i) = 1+rx_;
		*(index3+i) = -1*rx_*(1.0/2);
		*(result+i) = (1.0/2)*rx_*heat_h[layer].u_h[col-1][i] + (1-rx_)*heat_h[layer].u_h[col][i] + (1.0/2)*rx_*heat_h[layer].u_h[col+1][i];
	}
	*(index1+i) = -1*rx_*(1.0/2);
	*(index2+i) = 1+rx_;
	*(result+i) = 1.0/2*rx_*heat_h[layer].u_h[col-1][i] + (1-rx_)*heat_h[layer].u_h[col][i] + 1.0/2*rx_*heat_h[layer].u_h[col+1][i] + 1.0/2*rx_*heat[layer+1].u[col][ynseg_];
}

void Crank_Nicolson::guassi() {
	for (int i = 2; i < ynseg_-1; i++) {
		*(index2+i) = (*(index2+i)) * ( (-1)*(*(index2+i-1)) / (*(index1+i)) ) + (*(index3+i-1));
		*(index3+i) = (*(index3+i)) * ( (-1)*(*(index2+i-1)) / (*(index1+i)) );
		*(result+i) = (*(result+i)) * ( (-1)*(*(index2+i-1)) / (*(index1+i)) ) + (*(result+i-1));
		*(index1+i) = 0;
	}
	*(index2+i) = (*(index2+i)) * ( (-1)*(*(index2+i-1)) / (*(index1+i)) ) + (*(index3+i-1));
	*(result+i) = (*(result+i)) * ( (-1)*(*(index2+i-1)) / (*(index1+i)) ) + (*(result+i-1));
	*(index1+i) = 0;
}

void Crank_Nicolson::calculate_onecol(int layer, int col) { //0,1
	init_index(layer, col);
	guassi();

	double y_pre;
	y_pre = ( (*(result+ynseg_-1)) ) / (*(index2+ynseg_-1));
	double y_next = y_pre;
	heat[layer+1].u[col][ynseg_-1] = y_next;
	for (int i = ynseg_-2; i > 1; i--) {
		y_pre  = ( (*(result+i)) - ( (*(index3+i)) * y_next ) ) / (*(index2+i));
		heat[layer+1].u[col][i] = y_pre;
		y_next = y_pre;
	}
	y_pre = ( *(result+1) - (*(index3+1))*y_next) / (*(index2+1));
	heat[layer+1].u[col][i] = y_pre;
}
void Crank_Nicolson::calculate_onelayer(int layer) { //0~tnseg_-1
	int col;
	for(col=1; col<xnseg_; col++)
		calculate_onecol(layer, col);
}

///new!!!!!!!!!!!!!!!!!!!!!!!
//////////////////////////////////////////////////////////////////////
void Crank_Nicolson::calculate() {
	int layer;
	for(layer=0; layer<tnseg_; layer++) {
		calculate_hf_onelayer(layer);
		calculate_onelayer(layer);
	}
}

void Crank_Nicolson::show_layer(int layer) {
		std::cout << '\n' << "layer= " << layer << '\n';
		for (int i=0; i<=xnseg_; i=i+5) {
			std::cout<< '\n' << "x=" << *(x+i) << '\n';
			for(int j=0; j<=ynseg_; j=j+10) {
				if(heat[layer].u[i][j]<0)
					heat[layer].u[i][j]=0;
				std::cout<< heat[layer].u[i][j] << "  ";
				}
			}
		std::cout << '\n';
}

Crank_Nicolson.cpp

#include <GL/glut.h>  
#include <stdio.h>  
#include <stdlib.h>  
#define PI 3.1415926
void init(void); 
void reshape(int w,int h);  
void display(void);
void keyboard(unsigned char key, int x, int y);   
int layer = 0;
double maxt0 = 100.0;

#include "file.h"
#include <math.h>
Crank_Nicolson rank_Nicolson;
	
///////////////////////////////////////////
double funct0(double x, double y) {
	return 100-sqrt((x-50.0)*(x-50.0)+(y-50.0)*(y-50.0)); 
//	return 100*sin(PI/10*x)+100*sin(PI/100*y);
}
double funcx0(double y, double t) {
	return 0.0;
} 
double funcxn(double y, double t) {
	return 0.0;
}
double funcy0(double x, double t) {
	return 0.0;
} 
double funcyn(double x, double t) {
	return 0.0;
}
//////////////////////////////////////
int main (int argc, char **argv) {
	
	rank_Nicolson.set_init_funct0(funct0);
	rank_Nicolson.set_init_funcx0(funcx0);
	rank_Nicolson.set_init_funcxn(funcxn);
	rank_Nicolson.set_init_funcy0(funcy0);
	rank_Nicolson.set_init_funcyn(funcyn);
	
	rank_Nicolson.setSegment(0.0, 100.0, 0.0, 100.0); //步长为1
	rank_Nicolson.init_arrays(0.0, 1);
	rank_Nicolson.set_c(10);
	rank_Nicolson.get_rx();
	rank_Nicolson.get_ry();
	rank_Nicolson.calculate();

	glutInit(&argc, argv);  
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); //用GLUT_DOUBLE模式可以消除动画程序的闪烁现象  
   glutInitWindowSize (500, 500);  
   glutInitWindowPosition (100, 100);  
   glutCreateWindow("myheat");  
   init();
	glutDisplayFunc(display);
	glutReshapeFunc(reshape); 
	glutKeyboardFunc(keyboard);
   glutMainLoop();  
	return 0;
}
void init (void)  
{   
	glClearColor (1.0, 1.0, 1.0, 0.0); 
   glShadeModel(GL_SMOOTH); 
}  
void reshape(int w, int h)  
{  
	glViewport (0, 0, (GLsizei) w, (GLsizei) h); //定义适口大小,(x,y)为左下角坐标,(width,height)为高和宽
   glMatrixMode(GL_PROJECTION);  
   glLoadIdentity(); 
	//gluLookAt(50.0,30.0,50.0,0.0,0.0,-1.0,1.0,0.0,0.0); 
   glOrtho(-200, 300, 200, -400, -500, 500); //(left,right,bottom,top,near,far)
   //创建正交平行视景体矩阵,并把它与当前矩阵相乘,(left,bottom,-near)和(right,top,-near)是近侧裁剪平面上的点,分别映射到适口窗口的左下角和右上角;
   //(left,bottom,-far)和(right,top,-far)是远侧裁剪平面上的点,分别映射到视口窗口的左下角和右上角.
	glRotatef(90,0,1,0);
	glRotatef(90,1,0,0);
	glTranslated(10.0,-30,0.0);
	glScalef(2.0,2.0,2.0);
   glMatrixMode(GL_MODELVIEW);  
   glLoadIdentity(); 
} 

void display() {
	glClear (GL_COLOR_BUFFER_BIT);
	GLint i, j;
	GLdouble x_lf;

	for(i=0; i<xnseg_; i++) {
		for(j=0; j<ynseg_; j++) {
			glBegin(GL_POINTS);
			//glPolygonMode(GL_FRONT_AND_BACK,GL_LINES);
			x_lf = heat[layer].u[i][j] / maxt0;
			if(x_lf>1) x_lf=1;
			glColor3f(0.0+x_lf,0.0,1.0-(0.0+x_lf));
			glVertex3f(xx[i],yy[j],heat[layer].u[i][j]);
			glEnd();
		}
	}
	glutSwapBuffers(); //与双缓冲模式相对应,若是单缓冲模式,则用glFlush() 
	rank_Nicolson.show_layer(layer);	
}
void keyboard(unsigned char key, int x, int y) {
	if(key == 'g' || key == 'G') {
		layer++;
		display();	
	}
}