持续不定期更新:CFD&C++之拟一维喷管流动的数值解(1)

前言:

学习openfoam,或者准确来说,CFD,断断续续也有5个多月。3月底在本科学校写下的第一篇openfoam学习的博文,到现在在研一的学校里,尝试自己写代码计算cfd问题,慢慢一点一点地构建自己的自信心。其实说实话,学CFD很难,尤其是前期要战胜纯理论带来的「空虚」感,找到学习的落脚点。我不敢说现在的自己又足够的自信,但坚信「即使没有希望也要坚持下来」,终有一天会在学习中找到自我。

学习C++是因为之前学openfoam时理解代码所需,后来渐渐敲起了代码。在暑假时看了john D. Anderson教授的计算流体力学基础及其应用这本书,这对初学的我来说无疑是雪中送炭。不仅绘声绘色地回答我「什么是CFD」、「为什么要有CFD」等等问题,而且还很系统地讲解了一些很基础很基础的流体、计算流体的概念。公式推导之详尽,为我扫清了学习CFD的第一道障碍。在此书的第七章之后,便是一些「应用」。说是应用,其实离真正的工程应用还远着呢。作者只是将前面6章讲到的知识、方法,应用到一些比价理论化的模型上罢了。这篇博文便是写此书的第一个应用的模型「拉伐尔喷管」

暑假看此书时便已有自己写代码摸索的打算,但彼时正在看openfoam的代码和其他的书,觉得需要“做好准备”。此时准备得也差不多,便想着一边写代码一边写博文。不求进展神速,但求每天进步。

正文:

一、摘要

本文首先简要地介绍了此次CFD问题中的「拉伐尔喷管」的物理模型,并在拟一维定常等熵流动的假设条件之下,得出了解析解用于检验计算结果。然后通过编程实现流场的初始化,以及算出最小时间间隔,与书本所给的数据基本吻合。

二、物理问题简介

在这里偷个懒,直接截书本的图(侵删):

持续不定期更新:CFD&C++之拟一维喷管流动的数值解(1)_第1张图片

得出解析解所需方程(继续偷懒!):

持续不定期更新:CFD&C++之拟一维喷管流动的数值解(1)_第2张图片

这是可以得出解析解的,解和图像如下:

持续不定期更新:CFD&C++之拟一维喷管流动的数值解(1)_第3张图片持续不定期更新:CFD&C++之拟一维喷管流动的数值解(1)_第4张图片

后面计算时上面的解会用来检验计算结果的准确性。

三、编程思路

为了与书本所给的数据对比,喷管横截面积、初始流场照搬书本:

横截面积公式:

效果:持续不定期更新:CFD&C++之拟一维喷管流动的数值解(1)_第5张图片

密度、流速、温度:

	for (i = 0; i <= cellNumber; i++)
	{
		X[i] = i * deltaX;
		A[i] = 1.0 + 2.2 * (X[i] - 1.5)* (X[i] - 1.5);//公式7-73,p219
		rho[i] = 1.0 - 0.314 * X[i];//公式7-74a,p220
		T[i] = 1.0 - 0.2314 * X[i];//公式7-74b,p220
		V[i] = (0.1 + 1.09 * X[i]) * sqrt(T[i]);//公式7-74c,p220
		a[i] = sqrt(T[i]);//公式7-75,p222
	}

这是t=0时刻拟定的流场。密度、问题和流速随x轴线性变化,这当然是假设的啦!合理的假设能提高收敛的成功率,加快收敛速度。

为了编程效率,我在一开始定义了一些不变的常量、经常出现可能要改的变量: 

constexpr auto gamma = 1.4;//气体比热比
constexpr auto R = 287.0;//空气常数
constexpr auto cfl = 0.5;//库朗数
constexpr auto timeStep = 1000;//时间步
constexpr auto deltaX = 0.1;//x方向间距

接着,我定义了流场的

constexpr auto cellNumber = 30;

class cellField
{
private:
	double a[cellNumber + 1];
public:
	cellField()
	{
		for (int i = 0; i <= cellNumber; i++)
		{
			a[i] = 0;
		}
	}
	double& operator[](int i)
	{
		return a[i];
	}
	cellField(double initial)
	{
		for (int i = 0; i <= cellNumber; i++)
		{
			a[i] = initial;
		}
	}

	cellField operator+(cellField& b)
	{
		cellField c;
		for (int i = 0; i <= cellNumber; i++)
		{
			c[i] = a[i] + b[i];
		}
		return c;
	}
	cellField operator-(cellField& b)
	{
		cellField c;
		for (int i = 0; i <= cellNumber; i++)
		{
			c[i] = a[i] - b[i];
		}
		return c;
	}
	cellField operator*(cellField& b)
	{
		cellField c;
		for (int i = 0; i <= cellNumber; i++)
		{
			c[i] = a[i] * b[i];
		}
		return c;
	}
	cellField operator/(cellField& b)
	{
		cellField c;
		for (int i = 0; i <= cellNumber; i++)
		{
			c[i] = a[i] / b[i];
		}
		return c;
	}

	cellField operator+(double b)
	{
		cellField c;
		for (int i = 0; i <= cellNumber; i++)
		{
			c[i] = a[i] + b;
		}
		return c;
	}
	cellField operator-(double b)
	{
		cellField c;
		for (int i = 0; i <= cellNumber; i++)
		{
			c[i] = a[i] - b;
		}
		return c;
	}
	cellField operator*(double b)
	{
		cellField c;
		for (int i = 0; i <= cellNumber; i++)
		{
			c[i] = a[i] * b;
		}
		return c;
	}
	cellField operator/(double b)
	{
		cellField c;
		for (int i = 0; i <= cellNumber; i++)
		{
			c[i] = a[i] / b;
		}
		return c;
	}

	void inverse(cellField& b ,double e)
	{
		for (int i = 0; i <= cellNumber; i++)
		{
			a[i] = e / b[i];
		}
	}
};//cellield类可相互加减乘除,并可与数加减乘除。

以上是用于整个计算过程的流场的类。定义重载函数使得类和类之间、类和数之间能直接进行加减乘除运算。

变量定义都是用英文,程序比较简单,很好理解,就不一一去解释啦。

最后放上这一阶段的结果,以及和书本数据的对比:

持续不定期更新:CFD&C++之拟一维喷管流动的数值解(1)_第6张图片持续不定期更新:CFD&C++之拟一维喷管流动的数值解(1)_第7张图片

结果基本吻合。

四、小结

这一阶段还没有涉及到真正的计算。真正的挑战还在最后。可以发现在流场类那边有很多还未定义的函数,包括预估步和校正步等等步骤,但我想也不会很难,只是需要比较细心。

一步步建立自信。

 

参考文献:

《C++ Primer Plus 第六版》

约翰D. 安德森. 计算流体力学基础及其应用[M]. 北京: 机械工业出版社, 2007.

你可能感兴趣的:(编程人生,C++)