2021-04-26

拟一维喷管流动的数值解程序分享

全亚声速等熵喷管流动的CFD解法(非守恒型方程)

本文主要分享了安德森的《计算流体力学基础与应用》一书中:“全亚声速等熵喷管流动的CFD解法 — 守恒型方程”的程序求解。水平有限,请见谅!
亚声速——超声速等熵喷管流动的CFD解法的非守恒型方程程序见之前的笔者的博客:
《计算流体力学基础与应用 》- 约翰 D. 安德森
《Computational Fluid Dynamics》- John D. Anderson
第 7 章 拟一维喷管流动的数值解
亚声速——超声速等熵喷管流动的CFD解法(非守恒型方程)

Matlab

Nozzle.m
%%
% Author: CXT
% Date: 2021/4/20 
% Theme: 全亚声速等熵喷管流动
%% 物理符号(无量纲量);
% x —— 空间位置;
% A —— 喷管面积;
% rho —— 密度;
% V —— 速度;
% p —— 压力;
% N —— 计算节点数;
%%
clc;
clear;
close all;
%% 初始条件;
N = 31;% 计算节点数;
x = 0:(3-0)/(N-1):3; % 计算区间;
n1 = 1200; %时间步数;
n2 = 400;

rho0 = 1 - 0.023*x;
T0 = 1 - 0.009333*x;
V0 = 0.05 + 0.11*x;
%% 喷管形状;
A = (1 + 2.2*(x - 1.5).^2).*(x<=1.5) + (1 + 0.2223*(x - 1.5).^2).*(x > 1.5);
A = A./1;
%% 出口与入口压力之比;
f = 0.9;
%% 计算与绘图;
rho_t = rho0;
T_t = T0;
V_t = V0;

tic;
for i = 1:n1
    [rho_t, V_t, T_t, p_t, Ma] = OneStepNozzle(rho_t, V_t, T_t, N, x, A, f);
    
    if (i == n2)
        Q1 = rho_t.*A.*V_t;% 500步的质量流量; 
        p1 = p_t;
    elseif (i == n1)
        Q2 = rho_t.*A.*V_t;% 5000步的质量流量;
        p2 = p_t;
    end
end
toc

% 不同时刻质量流量的变化
Q0 = rho0.*A.*V0;% 初始质量流量;
figure(1);
plot(x, Q1,'r');% 500步的质量流量;
hold on;
plot(x, Q2, 'g');% 5000步的质量流量;
plot(x, Q0,'b');% 初始质量流量;
title("不同时刻质量流量的变化");
hold off;

% 不同时刻压力分布的变化;
p0 = rho0.*T0;
figure(2);
plot(x, p1, 'r');
hold on;
plot(x, p2, 'g');
plot(x, p0, 'b');
title("不同时刻压力分布的变化");
hold off;
OneStepNozzle.m
function [rho_t, V_t, T_t, p_t, Ma] = OneStepNozzle(rho, V, T, N, X, A, f)
%[rho_t, V_t, T_t, p_t, Ma] = OneStepNozzle(rho, V, T, N, X, A, f) 拟一维喷管流动的一个时间步长的计算
%   rho —— 初始密度;
%   V —— 初始速度;
%   T —— 初始温度;
%   N —— 计算节点数;
%   X —— 计算区间;
%   A —— 喷管形状参数;
%   f —— 出口压力与入口压力之比;

%   rho_t —— 下一步的密度;
%   V_t —— 下一步的速度;
%   T_t —— 下一步的温度;
%   p_t —— 下一步的压力;
%   Ma —— 马赫数;
%% 默认参数;
Delta_x = (X(end)-X(1))/(N - 1); %空间步长;
gama = 1.4; %绝热指数;
C = 0.5; %柯朗数;
%% 预估步计算;
% 向前差分;
% 只计算内点;
partial_rho = zeros(1, 3/Delta_x + 1);
partial_V = zeros(1, 3/Delta_x + 1);
partial_T = zeros(1, 3/Delta_x + 1);

for i = 1:N - 1
    
   partial_rho(i) = - V(i)*(rho(i+1) - rho(i))/Delta_x...
                  - rho(i)*(V(i+1) - V(i))/Delta_x...
                  - rho(i)*V(i)*(log(A(i+1)) - log(A(i)))/Delta_x;
              
   partial_V(i) = - V(i)*(V(i+1) - V(i))/Delta_x...
                  - 1/gama*((T(i+1) - T(i))/Delta_x...
                  + T(i)/rho(i)*(rho(i+1)-rho(i))/Delta_x);
    
   partial_T(i) = - V(i)*(T(i+1) - T(i))/Delta_x...
                   - (gama - 1)*T(i)*((V(i+1) - V(i))/Delta_x...
                   + V(i)*(log(A(i+1)) - log(A(i)))/Delta_x);

end
%% 计算时间步长;
Delta_t = min(C * Delta_x ./ (V + sqrt(T)));
%% 计算预估值
bar_rho = rho + partial_rho * Delta_t;
bar_V = V + partial_V * Delta_t;
bar_T = T + partial_T * Delta_t;
%% 计算校正步;
% 向后差分;
% 只计算内点;
bar_partial_rho = zeros(1, 3/Delta_x + 1);
bar_partial_V = zeros(1, 3/Delta_x + 1);
bar_partial_T = zeros(1, 3/Delta_x + 1);

for i = 2:N-1
    
   bar_partial_rho(i) = - bar_V(i)*(bar_rho(i) - bar_rho(i-1))/Delta_x...
                        - bar_rho(i)*(bar_V(i) - bar_V(i-1))/Delta_x...
                        - bar_rho(i)*bar_V(i)*(log(A(i)) - log(A(i-1)))/Delta_x;
   
   bar_partial_V(i) = - bar_V(i)*(bar_V(i) - bar_V(i-1))/Delta_x...
                       - ((bar_T(i) - bar_T(i-1))/Delta_x...
                       + bar_T(i)*(bar_rho(i) - bar_rho(i-1))/(bar_rho(i)*Delta_x))/gama;
    
   bar_partial_T(i) = - bar_V(i)*(bar_T(i) - bar_T(i-1))/Delta_x...
                      - (gama - 1)*bar_T(i)*((bar_V(i) - bar_V(i-1))/Delta_x...
                      + bar_V(i)*(log(A(i)) - log(A(i-1)))/Delta_x); 

end
%% 计算平均时间导数;
partial_rho_av = (partial_rho + bar_partial_rho)/2;
partial_V_av = (partial_V + bar_partial_V)/2;
partial_T_av = (partial_T + bar_partial_T)/2;
%% 校正值;
% t + Delta_t 时的参数;
rho_t = rho + partial_rho_av*Delta_t;
V_t = V + partial_V_av*Delta_t;
T_t = T + partial_T_av*Delta_t;
p_t = rho_t.*T_t;
%% 边界点处的流场变量;
% 入流边界;
rho_t(1) = 1; % 滞止参数;
V_t(1) = 2*V_t(2) - V_t(3); % 允许边界上的 V 是可变化的;
T_t(1) = 1; % 滞止参数;
p_t(1) = rho_t(1)*T_t(1); % 滞止参数;

% 出流边界;
p_t(N) = f; %%f是给定值;
T_t(N) = 2*T_t(N-1) - T_t(N-2);
rho_t(N) = f/T_t(N);
V_t(N) = 2*V_t(N-1) - V_t(N-2);% 允许边界上的V是可变化的;
%% 马赫数
Ma = V_t./sqrt(T_t);
end

C++

OneStepNozzle.h
#pragma once
#include <iostream>
#include <vector>
#include <iomanip>//setprecision(3)
using namespace std;

class Nozzle
{
private:
	double X_first;
	double X_end;//计算区间[X_first, X_end];
	double* A; //喷管面积;
	double* rho;//密度;
	double* T;//温度;
	double* V;//速度;
	int N; //计算节点数;
	int iterations;//迭代次数;
	double F;//出口与入口压力之比;

protected:
	double* p;//压力;
	double* Ma;//马赫数; 
	double Delta_x;// 空间步长;
	double Delta_t;//时间步长;
	double gama;// 绝热指数;
	double C;// 柯朗数;

	中间变量
	double* partial_rho;
	double* partial_V;
	double* partial_T;

	double* bar_rho;
	double* bar_V;
	double* bar_T;

	double* bar_partial_rho;
	double* bar_partial_V;
	double* bar_partial_T;

	double* partial_rho_av;
	double* partial_V_av;
	double* partial_T_av;
	

public:
	void _init();

	Nozzle(double x_f, double x_e, double a[], double rho0[], double T0[], 
		   double V0[], int n, int it, double f);
	
	Nozzle(const Nozzle& N);

	void oneStepmacCormack();

	void iterativeCompute();//迭代计算;

	void print();//输出最终的计算结果;

	~Nozzle();
};
OneStepNozzle.cpp
#include "OneStepNozzle.h"

void Nozzle::_init()
{
	this->Delta_x = (X_end - X_first) / (N - 1);// 空间步长;
	this->Delta_t = -1;//时间步长;
	this->gama = 1.4;// 绝热指数;
	this->C = 0.5;// 柯朗数;

	//创建向量;
	//this->rho = new double[N];
	//this->V = new double[N];
	//this->T = new double[N];

	this->partial_rho = new double[N];
	this->partial_V = new double[N];
	this->partial_T = new double[N];

	this->bar_rho = new double[N];
	this->bar_V = new double[N];
	this->bar_T = new double[N];

	this->bar_partial_rho = new double[N];
	this->bar_partial_V = new double[N];
	this->bar_partial_T = new double[N];

	this->partial_rho_av = new double[N];
	this->partial_V_av = new double[N];
	this->partial_T_av = new double[N];

	this->p = new double[N];
	this->Ma = new double[N];
}

Nozzle::Nozzle(double x_f,double x_e,double a[], double rho0[],double T0[],
	           double V0[], int n,int it, double f):
	X_first(x_f), X_end(x_e),A(a),rho(rho0),V(V0),T(T0), N(n), iterations(it), F(f)
{
	//用户需要输入:计算区间[x_f,x_e];
	//           喷管形状向量 a[];
	//           初始密度 rho0[];
	//           初始温度T0[];
	//           初始速度V0[];
	//           节点数 n;
	//           迭代次数 it;
	//           出口与入口压力之比 f;

	_init();
}

Nozzle::Nozzle(const Nozzle& _N)
{
	//浅拷贝;
	this->N = _N.N;
	this->X_first = _N.X_first;
	this->X_end = _N.X_end;

	this->Delta_x = _N.Delta_x;
	this->Delta_t = _N.Delta_t;

	this->gama = _N.gama;
	this->C = _N.C;

	this->iterations = _N.iterations;
	this->F = _N.F;

	//深拷贝;
	this->rho = new double(*_N.rho);
	this->V = new double(*_N.V);
	this->T = new double(*_N.T);

	this->partial_rho = new double(*_N.partial_rho);
	this->partial_V = new double(*_N.partial_V);
	this->partial_T = new double(*_N.partial_T);

	this->bar_rho = new double(*_N.bar_rho);
	this->bar_V = new double(*_N.bar_V);
	this->bar_T = new double(*_N.bar_T);

	this->bar_partial_rho = new double(*_N.bar_partial_rho);
	this->bar_partial_V = new double(*_N.bar_partial_V);
	this->bar_partial_T = new double(*_N.bar_partial_T);

	this->partial_rho_av = new double(*_N.partial_rho_av);
	this->partial_V_av = new double(*_N.partial_V_av);
	this->partial_T_av = new double(*_N.partial_T_av);

	this->p = new double(*_N.p);
	this->Ma = new double(*_N.Ma);

	this->A = new double(*_N.A);
}

void Nozzle::oneStepmacCormack()//使用Mac Cormack法计算;
{
	 预估步计算;
	// 向前差分;
	// 只计算内点;
	for (int i = 0; i <= N - 2; i++)
	{
		partial_rho[i] = -V[i] * (rho[i + 1] - rho[i]) / Delta_x
					   - rho[i] * (V[i + 1] - V[i]) / Delta_x
			           - rho[i] * V[i] * (log(A[i + 1]) - log(A[i])) / Delta_x;

		partial_V[i] = -V[i] * (V[i + 1] - V[i]) / Delta_x
			         - 1 / gama * ((T[i + 1] - T[i]) / Delta_x
				     + T[i] / rho[i] * (rho[i + 1] - rho[i]) / Delta_x);

		partial_T[i] = -V[i] * (T[i + 1] - T[i]) / Delta_x
			- (gama - 1) * T[i] * ((V[i + 1] - V[i]) / Delta_x
				+ V[i] * (log(A[i + 1]) - log(A[i])) / Delta_x);
	}
	partial_rho[N-1] = 0;
	partial_V[N-1] = 0;
	partial_T[N-1] = 0;

	计算最小时间步长;

	Delta_t = C * Delta_x / (V[0] + sqrt(T[0]));//将首节点计算的时间步长赋值给 Delta_t;

	for (int i = 1;i < N;i++)//从第个二节点计算到最后一个节点;
	{
		if (C * Delta_x / (V[i] + sqrt(T[i])) <= this->Delta_t)
		{
			this->Delta_t = C * Delta_x / (V[i] + sqrt(T[i]));
		}
	}

	// 计算预估值
	for (int i = 0;i < N;i++)
	{
		bar_rho[i] = rho[i] + partial_rho[i] * Delta_t;
		bar_V[i] = V[i] + partial_V[i] * Delta_t;
		bar_T[i] = T[i] + partial_T[i] * Delta_t;
	}

	 计算校正步;
	// 向后差分;
	// 只计算内点;
	for (int i = 1;i <= N - 1;i++)
	{
		bar_partial_rho[i] = -bar_V[i] * (bar_rho[i] - bar_rho[i - 1]) / Delta_x
			- bar_rho[i] * (bar_V[i] - bar_V[i - 1]) / Delta_x
			- bar_rho[i] * bar_V[i] * (log(A[i]) - log(A[i - 1])) / Delta_x;

		bar_partial_V[i] = -bar_V[i] * (bar_V[i] - bar_V[i - 1]) / Delta_x
			- ((bar_T[i] - bar_T[i - 1]) / Delta_x
				+ bar_T[i] * (bar_rho[i] - bar_rho[i - 1]) / (bar_rho[i] * Delta_x)) / gama;

		bar_partial_T[i] = -bar_V[i] * (bar_T[i] - bar_T[i - 1]) / Delta_x
			- (gama - 1) * bar_T[i] * ((bar_V[i] - bar_V[i - 1]) / Delta_x
				+ bar_V[i] * (log(A[i]) - log(A[i - 1])) / Delta_x);
	}
	bar_partial_rho[0] = 0;
	bar_partial_T[0] = 0;
	bar_partial_V[0] = 0;

	 计算平均时间导数;
	for (int i = 0;i < N;i++)
	{
		partial_rho_av[i] = (partial_rho[i] + bar_partial_rho[i]) / 2;
		partial_V_av[i] = (partial_V[i] + bar_partial_V[i]) / 2;
		partial_T_av[i] = (partial_T[i] + bar_partial_T[i]) / 2;
	}
	
	 校正值;
	// t + Delta_t 时的参数;

	for (int i = 0;i < N;i++)
	{
		rho[i] = rho[i] + partial_rho_av[i] * Delta_t;
		V[i] = V[i] + partial_V_av[i] * Delta_t;
		T[i] = T[i] + partial_T_av[i] * Delta_t;
		p[i] = rho[i] * T[i];
	}

	 边界点处的流场变量;
	// 入流边界;
	rho[0] = 1;// 滞止参数;
	V[0] = 2 * V[1] - V[2];// 允许边界上的 V 是可变化的;
	T[0] = 1;// 滞止参数;
	p[0] = rho[0] * T[0];// 滞止参数;

	// 出流边界;
	p[N - 1] = this->F;
	T[N - 1] = 2 * T[N - 2] - T[N - 3];
	rho[N - 1] = this->F / T[N - 1];
	V[N - 1] = 2 * V[N - 2] - V[N - 3];
	
	 马赫数
	for (int i = 0;i < N;i++)
	{
		Ma[i] = V[i] / sqrt(T[i]);
	}
}

void Nozzle::iterativeCompute()//迭代计算;
{
	for (int it = 0;it < this->iterations;it++)
	{
		oneStepmacCormack();
	}
}

void Nozzle::print()
{	
	iterativeCompute();

	cout << "节点" << "\t" << "密度" << "\t" << "速度" << "\t" 
		 << "温度" << "\t" << "压力" << "\t" << "马赫数" << endl;

	for (int i = 0;i < N;i++)
	{
		cout << i + 1 << "\t" 
			<< setprecision(4) << rho[i] << "\t" 
			<< setprecision(4) << V[i] << "\t"
			<< setprecision(4) << T[i] << "\t" 
			<< setprecision(4) << p[i] << "\t" 
			<< setprecision(4) << Ma[i] << endl;
	}
}

Nozzle::~Nozzle()
{
	//delete[] rho;
	//delete[] V;
	//delete[] T;

	delete[] partial_rho;
	delete[] partial_V;
	delete[] partial_T;

	delete[] bar_rho;
	delete[] bar_V;
	delete[] bar_T;

	delete[] bar_partial_rho;
	delete[] bar_partial_V;
	delete[] bar_partial_T;

	delete[] partial_rho_av;
	delete[] partial_V_av;
	delete[] partial_T_av;

	delete[] p;
	delete[] Ma;
}
拟一维喷管流动的数值解.cpp
/*
 Author: CXT
 Date : 2021 / 4 / 20
 Theme : 拟一维全亚声速等熵喷管
 %物理符号(无量纲量);
 x —— 空间位置;
 A —— 喷管面积;
 rho —— 密度;
 V —— 速度;
 p —— 压力;
 N —— 计算节点数;
 */

#include <iostream>
#include <cmath>//sqrt();
#include <ctime>
#include "OneStepNozzle.h"
using namespace std;

void test()
{
	double x_f = 0;//计算区间[x_f,x_e];
	double x_e = 3;
	int n = 31;//节点数;
	int it = 5000;//迭代次数;
	double f = 0.93;//出口与入口压力之比;

	double* x = new double[n];
	double* a = new double[n];
	double* rho0 = new double[n];
	double* T0 = new double[n];
	double* V0 = new double[n];

	//准备节点;
	for (int i = 0; i<n; i++)
	{
		x[i] = x_f + (x_e - x_f) / (n - 1) * i;

		a[i] = (1 + 2.2 * pow(x[i] - 1.5,2)) * (x[i] <= 1.5) 
			 + (1 + 0.2223 * pow(x[i] - 1.5, 2)) * (x[i] > 1.5);
		rho0[i] = 1 - 0.023 * x[i];
		T0[i] = 1 - 0.009333 * x[i];
		V0[i] = 0.05 + 0.11 * x[i];
	}

	Nozzle N1(x_f,x_e,a,rho0,T0,V0,n,it,f);
	N1.print();

	delete[] x;
	delete[] a;
	delete[] rho0;
	delete[] T0;
	delete[] V0;
}

int main()
{
	clock_t start = clock();
	test();
	clock_t end = clock();

	cout << "Total time: " << end - start << "ms" << endl;

	system("pause");
	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值