我正在尝试制作一个用于模拟原始方程式的基本程序,但是由于它迅速发散,所以出现了问题。 我以这篇论文为指导: http://www.met.reading.ac.uk/~ross/Science/PrimEqs.html确实不错,但并没有帮助我将其转换为工作代码。我得到了概念(发散,导数,材料导数(某种),压力梯度等...),但是由于我的代码一直在混乱,所以它很奇怪。
黏度和扩散度均为0,所以不必担心它们。(我已经分别测试了它们,并且两者都很稳定)
void update()
{
VDiv = Divergence(Velocity);
PVector[][] ViscosityVector = VectorLaplace(Velocity);
TempChange = Laplace(Temp);//diffusion operator
PGrad = Gradient(Pressure);//pressure force
for(int i=amountX-1;i>=0;i--)
{
for(int j=amountY-1;j>=0;j--)
{
TempChange[i][j]*=Diffusion;
TempChange[i][j]-=VDiv[i][j]*Pressure[i][j];// temp changes as volume changes
PVector Accel=new PVector(0,Grav).sub(PVector.div(PGrad[i][j],Density[i][j]));
Accel.add(PVector.mult(ViscosityVector[i][j],Viscosity));//viscocity
float TS=(Density[i][j]*HeatCapacity);
//the material derivative
Velocity[i][j].add(Accel.mult(DT));
Temp[i][j]+=DT*TempChange[i][j]/TS;
if(i<amountX-1)
{
Temp[i+1][1]+= Velocity[i][j].x*DT;
Temp[i][j]-= Velocity[i][j].x*DT;
Density[i+1][j]+= Velocity[i][j].x*DT;
Density[i][j]-= Velocity[i][j].x*DT;
}
if(j<amountY-1)
{
Temp[i][j+1]+= Velocity[i][j].y*DT;
Temp[i][j]-= Velocity[i][j].y*DT;
Density[i][j+1]+= Velocity[i][j].y*DT;
Density[i][j]-= Velocity[i][j].y*DT;
}
// ideal gas law
Pressure[i][j]=Density[i][j]*(GasConst*Temp[i][j]);
}
}
}
我很确定子功能没有问题,但是在这里以防万一。
PVector[][] Gradient(float[][] Input)
{
PVector[][] Out = new PVector[amountX][amountY];
for(int i=0;i<amountX;i++)
{
for(int j=0;j<amountY;j++)
{
Out[i][j]=new PVector();
if(j<amountY-1)
Out[i][j].y=(-Input[i][j]+Input[i][j+1])*DY;
if(i<amountX-1)
Out[i][j].x=(-Input[i][j]+Input[i+1][j])*DX;
}
}
return Out;
}
PVector[][] VectorLaplace(PVector[][] Input)
{
float[][] InputX=new float[amountX][amountY];
float[][] InputY=new float[amountX][amountY];
for(int i =0;i<amountX;i++)
{
for(int j =0;j<amountY;j++)
{
InputX[i][j]=Input[i][j].x;
InputY[i][j]=Input[i][j].y;
}
}
InputX = Laplace(InputX);
InputY = Laplace(InputY);
PVector[][] Out = new PVector[amountX][amountY];
for(int i =0;i<amountX;i++)
{
for(int j =0;j<amountY;j++)
{
Out[i][j]=new PVector(InputX[i][j],InputY[i][j]);
}
}
return Out;
}
float[][] Laplace(float[][] Input)
{
float[][] Flow = new float[amountX][amountY];
for(int i =0;i<amountX;i++)
{
for(int j =0;j<amountY;j++)
{
if(i>0)
{
Flow[i][j]-=Input[i][j];
Flow[i-1][j]+=Input[i][j];
}
if(j>0)
{
Flow[i][j]-=Input[i][j];
Flow[i][j-1]+=Input[i][j];
}
if(i<amountX-1)
{
Flow[i][j]-=Input[i][j];
Flow[i+1][j]+=Input[i][j];
}
if(j<amountY-1)
{
Flow[i][j]-=Input[i][j];
Flow[i][j+1]+=Input[i][j];
}
}
}
return Flow;
}
float[][] Divergence(PVector[][] Input)
{
float[][] Out = new float[amountX][amountY];
for(int i=0;i<amountX;i++)
{
for(int j=0;j<amountY;j++)
{
if(i>0)
{
Out[i][j]-=(Input[i-1][j].x)*DX;
}
if(j>0)
{
Out[i][j]-=(Input[i][j-1].y)*DY;
}
if(i<amountX-1)
{
Out[i][j]+=(Input[i][j].x)*DX;
}
if(j<amountY-1)
{
Out[i][j]+=(Input[i][j].y)*DY;
}
}
}
return Out;
}
有人可以看到问题所在吗?
失败所需的最少代码:
void update()
{
PGrad = Gradient(Pressure);//pressure force
for(int i=amountX-1;i>=0;i--)
{
for(int j=amountY-1;j>=0;j--)
{
PVector Accel=new PVector(0,Grav).sub(PVector.div(PGrad[i][j],Density[i][j]));
//the material derivative
Velocity[i][j].add(Accel.mult(DT));
if(i<amountX-1)
{
Density[i+1][j]+= Velocity[i][j].x*DT*Density[i][j];
Density[i][j]-= Velocity[i][j].x*DT*Density[i][j];
}
if(j<amountY-1)
{
Density[i][j+1]+= Velocity[i][j].y*DT*Density[i][j];
Density[i][j]-= Velocity[i][j].y*DT*Density[i][j];
}
// ideal gas law
Pressure[i][j]=Density[i][j];
}
}
}
PVector[][] Gradient(float[][] Input)
{
PVector[][] Out = new PVector[amountX][amountY];
for(int i=0;i<amountX;i++)
{
for(int j=0;j<amountY;j++)
{
Out[i][j]=new PVector();
if(j<amountY-1)
Out[i][j].y=(-Input[i][j]+Input[i][j+1])*DY;
if(i<amountX-1)
Out[i][j].x=(-Input[i][j]+Input[i+1][j])*DX;
}
}
return Out;
}
简单的一维伪代码:
for(int i =0;i<N-1;i++)
Gradient[i]=(Pressure[i]-Pressure[i+1])*dx;
for(int i =0;i<N;i++)
{
Accel = -Gradient[i]/Density[i];
Velocity[i]+=Accel*dt;
if(i<N-1)
{
Density[i+1]+=Velocity*dt;
Density[i]-=Velocity*dt;
}
Pressure[i]=Density[i];
}
这里是测试的全部内容。包含温度,粘度和扩散。如果需要,可以禁用它们。需要处理https://processing.org/
int amountX=40;
int amountY=20;
float[][] Temp=new float[amountX][amountY];
float[][] Density=new float[amountX][amountY];
float[][] Pressure=new float[amountX][amountY];
PVector[][] Velocity=new PVector[amountX][amountY];
float Grav=0.05;
float GasConst=1;
float HeatCapacity=5;
float Diffusion=0.5;
float Viscosity=0.4;
float DX=1;
float DY=1;
float DT=0.001;
int Warp = 1;
float[][] VDiv;
float[][] TempChange;
PVector[][] PGrad;
void setup()
{
size(1000,500);
for(int i=0;i<amountX;i++)
{
for(int j=0;j<amountY;j++)
{
Temp[i][j]=3;
Pressure[i][j]=exp(j*Grav/(GasConst*Temp[i][j]))*40;
Density[i][j]=Pressure[i][j]/(GasConst*Temp[i][j]);
}
}
for(int i=0;i<amountX;i++)
{
for(int j=0;j<amountY;j++)
{
Velocity[i][j]=new PVector(0,0);
}
}
int Min=10;
int Max=15;
for(int i=Min;i<Max;i++)
{
for(int j=Min;j<Max;j++)
{
float x=(i-Min)/(float)(Max-Min);
float y=(j-Min)/(float)(Max-Min);
Temp[i][j]=lerp(3,6,exp(-(sq(2*x-1)+sq(2*y-1))*3));
}
}
for(int i =0;i<0;i++)
{
update();
}
}
void draw()
{
background(201);
for(int i = 0;i<Warp;i++)
{
update();
}
show();
}
void show()
{
float dx=width/(float)amountX;
float dy=height/(float)amountY;
float dv=10*dx;
noStroke();
for(int i=0;i<amountX;i++)
{
for(int j=0;j<amountY;j++)
{
fill(Temp[i][j]*10,0,Density[i][j]*10);
rect(dx*i,dy*j,dx,dy);
}
}
stroke(255);
for(int i=0;i<amountX;i+=1)
{
for(int j=0;j<amountY;j+=1)
{
line(dx*(i+0.5),dy*(j+0.5),dx*(i+0.5)+Velocity[i][j].x*dv,dy*(j+0.5)+Velocity[i][j].y*dv);
}
}
int MouseI=(int)(mouseX/dx);
int MouseJ=(int)(mouseY/dy);
fill(255);
if(MouseI>0&&MouseJ>0&&MouseI<amountX-1&&MouseJ<amountY-1)
{
text("Temp:"+Temp[MouseI][MouseJ],10,20);
text("Pres:"+Pressure[MouseI][MouseJ],10,40);
text("Dens:"+Density[MouseI][MouseJ],10,60);
}
}
void update()
{
VDiv = Divergence(Velocity);
PVector[][] ViscosityVector = VectorLaplace(Velocity);
TempChange = Laplace(Temp);//diffusion operator
PGrad = Gradient(Pressure);//pressure force
for(int i=amountX-1;i>=0;i--)
{
for(int j=amountY-1;j>=0;j--)
{
TempChange[i][j]*=Diffusion;
TempChange[i][j]-=VDiv[i][j]*Pressure[i][j];// temp changes as volume changes
PVector Accel=new PVector(0,Grav).sub(PVector.div(PGrad[i][j],Density[i][j]));
Accel.add(PVector.mult(ViscosityVector[i][j],Viscosity));//viscocity
float TS=(Density[i][j]*HeatCapacity);
//the material derivative
Velocity[i][j].add(Accel.mult(DT));
Temp[i][j]+=DT*TempChange[i][j]/TS;
if(i<amountX-1)
{
Temp[i+1][1]+= Velocity[i][j].x*DT;
Temp[i][j]-= Velocity[i][j].x*DT;
Density[i+1][j]+= Velocity[i][j].x*Density[i][j];
Density[i][j]-= Velocity[i][j].x*Density[i][j];
}
if(j<amountY-1)
{
Temp[i][j+1]+= Velocity[i][j].y*DT;
Temp[i][j]-= Velocity[i][j].y*DT;
Density[i][j+1]+= Velocity[i][j].y*DT*Density[i][j];
Density[i][j]-= Velocity[i][j].y*DT*Density[i][j];
}
// ideal gas law
Pressure[i][j]=Density[i][j]*(GasConst*Temp[i][j]);
}
}
}
PVector[][] Gradient(float[][] Input)
{
PVector[][] Out = new PVector[amountX][amountY];
for(int i=0;i<amountX;i++)
{
for(int j=0;j<amountY;j++)
{
Out[i][j]=new PVector();
if(j<amountY-1)
Out[i][j].y=(-Input[i][j]+Input[i][j+1])*DY;
if(i<amountX-1)
Out[i][j].x=(-Input[i][j]+Input[i+1][j])*DX;
}
}
return Out;
}
PVector[][] VectorLaplace(PVector[][] Input)
{
float[][] InputX=new float[amountX][amountY];
float[][] InputY=new float[amountX][amountY];
for(int i =0;i<amountX;i++)
{
for(int j =0;j<amountY;j++)
{
InputX[i][j]=Input[i][j].x;
InputY[i][j]=Input[i][j].y;
}
}
InputX = Laplace(InputX);
InputY = Laplace(InputY);
PVector[][] Out = new PVector[amountX][amountY];
for(int i =0;i<amountX;i++)
{
for(int j =0;j<amountY;j++)
{
Out[i][j]=new PVector(InputX[i][j],InputY[i][j]);
}
}
return Out;
}
float[][] Laplace(float[][] Input)
{
float[][] Flow = new float[amountX][amountY];
for(int i =0;i<amountX;i++)
{
for(int j =0;j<amountY;j++)
{
if(i>0)
{
Flow[i][j]-=Input[i][j];
Flow[i-1][j]+=Input[i][j];
}
if(j>0)
{
Flow[i][j]-=Input[i][j];
Flow[i][j-1]+=Input[i][j];
}
if(i<amountX-1)
{
Flow[i][j]-=Input[i][j];
Flow[i+1][j]+=Input[i][j];
}
if(j<amountY-1)
{
Flow[i][j]-=Input[i][j];
Flow[i][j+1]+=Input[i][j];
}
}
}
return Flow;
}
float[][] Divergence(PVector[][] Input)
{
float[][] Out = new float[amountX][amountY];
for(int i=0;i<amountX;i++)
{
for(int j=0;j<amountY;j++)
{
if(i>0)
{
Out[i][j]-=(Input[i-1][j].x)*DX;
}
if(j>0)
{
Out[i][j]-=(Input[i][j-1].y)*DY;
}
if(i<amountX-1)
{
Out[i][j]+=(Input[i][j].x)*DX;
}
if(j<amountY-1)
{
Out[i][j]+=(Input[i][j].y)*DY;
}
}
}
return Out;
}