Aşağıdaki sıvı simülasyonu, paper by Stam'un bir çevirisi. Gerçekten korkunç bir şey oldu. Program her zaman düşük bir DIFF=0.01
ile çalıştırıldığında, değerler küçükten başlar ve sonra hızla genişler veya "patlatır". Matematik rutinlerini dikkatli bir şekilde kontrol ettim. Kod bir 0.5
ile başladığından, matematiksel olarak çarparak ve bir grup sıfır ekleyerek, sonuç sıfır sıfıra yakın ve diğer vektörlere yakın olmalıdır.Sıvı Simülasyonu "Üfleme"
Kod oldukça uzun, ben de bunları parçalara ayırdım ve fazladan kodları kaldırdım. Tüm başlangıç ve SDL kodları eksi olarak sadece 120 satır vardır. Birkaç saat boyunca hiçbir değişiklik yapmadan değişiklikler yapmaya çalıştım, bu yüzden yardım çok takdir ediliyor.
Bazı deneylerden sonra, DIFF
çok düşük ayarlandığında bazı kayan nokta hatası olabileceğine inanıyorum. Değer 0.01
'dan 0.02
'a artırıldığında, değerler patlamaz. Bununla birlikte, bunun tüm sorun olduğunu düşünmüyorum.
Net olmak gerekirse, 1201ProgramAlarm ve vidstige tarafından geçerli olan yanıtlar sorunu çözmez.
kalın kısımlarındaki bölümleri önemli parçalardır, gerisi tamlık içindir.
başlayarak şeyler,
#include <SDL2/SDL.h>
#include <stdio.h>
#include <iostream>
#include <algorithm>
#define IX(i,j) ((i)+(N+2)*(j))
using namespace std;
// Constants
const int SCREEN_WIDTH = 600;
const int SCREEN_HEIGHT = 600; // Should match SCREEN_WIDTH
const int N = 20; // Grid size
const int SIM_LEN = 1000;
const int DELAY_LENGTH = 40; // ms
const float VISC = 0.01;
const float dt = 0.1;
const float DIFF = 0.01;
const bool DISPLAY_CONSOLE = false; // Console or graphics
const bool DRAW_GRID = false; // implement later
const int nsize = (N+2)*(N+2);
Matematik Diffüz rutinleri 1+4*a
bölün rutinleri atlayın. Bu ima yoğunluğu < = 1 olmalıdır?
void set_bnd(int N, int b, vector<float> &x)
{
// removed
}
inline void lin_solve(int N, int b, vector<float> &x, vector<float> &x0, float a, float c)
{
for (int k=0; k<20; k++)
{
for (int i=1; i<=N; i++)
{
for (int j=1; j<=N; j++)
{
x[IX(i,j)] = (x0[IX(i,j)] + a*(x[IX(i-1,j)]+x[IX(i+1,j)]+x[IX(i,j-1)]+x[IX(i,j+1)]))/c;
}
}
set_bnd (N, b, x);
}
}
// Add forces
void add_source(vector<float> &x, vector<float> &s, float dt)
{
for (int i=0; i<nsize; i++) x[i] += dt*s[i];
}
// Diffusion with Gauss-Seidel relaxation
void diffuse(int N, int b, vector<float> &x, vector<float> &x0, float diff, float dt)
{
float a = dt*diff*N*N;
lin_solve(N, b, x, x0, a, 1+4*a);
}
// Backwards advection
void advect(int N, int b, vector<float> &d, vector<float> &d0, vector<float> &u, vector<float> &v, float dt)
{
float dt0 = dt*N;
for (int i=1; i<=N; i++)
{
for (int j=1; j<=N; j++)
{
float x = i - dt0*u[IX(i,j)];
float y = j - dt0*v[IX(i,j)];
if (x<0.5) x=0.5; if (x>N+0.5) x=N+0.5;
int i0=(int)x; int i1=i0+1;
if (y<0.5) y=0.5; if (y>N+0.5) y=N+0.5;
int j0=(int)y; int j1=j0+1;
float s1 = x-i0; float s0 = 1-s1; float t1 = y-j0; float t0 = 1-t1;
d[IX(i,j)] = s0*(t0*d0[IX(i0,j0)] + t1*d0[IX(i0,j1)]) +
s1*(t0*d0[IX(i1,j0)] + t1*d0[IX(i1,j1)]);
}
}
set_bnd(N, b, d);
}
}
void project(int N, vector<float> &u, vector<float> &v, vector<float> &p, vector<float> &div)
{
float h = 1.0/N;
for (int i=1; i<=N; i++)
{
for (int j=1; j<=N; j++)
{
div[IX(i,j)] = -0.5*h*(u[IX(i+1,j)] - u[IX(i-1,j)] +
v[IX(i,j+1)] - v[IX(i,j-1)]);
p[IX(i,j)] = 0;
}
}
set_bnd(N, 0, div); set_bnd(N, 0, p);
lin_solve(N, 0, p, div, 1, 4);
for (int i=1; i<=N; i++)
{
for (int j=1; j<=N; j++)
{
u[IX(i,j)] -= 0.5*(p[IX(i+1,j)] - p[IX(i-1,j)])/h;
v[IX(i,j)] -= 0.5*(p[IX(i,j+1)] - p[IX(i,j-1)])/h;
}
}
set_bnd(N, 1, u); set_bnd(N, 2, v);
}
Yoğunluk ve hız çözücü
// Density solver
void dens_step(int N, vector<float> &x, vector<float> &x0, vector<float> &u, vector<float> &v, float diff, float dt)
{
add_source(x, x0, dt);
swap(x0, x); diffuse(N, 0, x, x0, diff, dt);
swap(x0, x); advect(N, 0, x, x0, u, v, dt);
}
// Velocity solver: addition of forces, viscous diffusion, self-advection
void vel_step(int N, vector<float> &u, vector<float> &v, vector<float> &u0, vector<float> &v0, float visc, float dt)
{
add_source(u, u0, dt); add_source(v, v0, dt);
swap(u0, u); diffuse(N, 1, u, u0, visc, dt);
swap(v0, v); diffuse(N, 2, v, v0, visc, dt);
project(N, u, v, u0, v0);
swap(u0, u); swap(v0, v);
advect(N, 1, u, u0, u0, v0, dt); advect(N, 2, v, v0, u0, v0, dt);
project(N, u, v, u0, v0);
}
Ben floating-point inconsistencies kabul ama -ffloat-store
ile derleme sonra sorun hala devam etti.
valgrind' 'altında programını çalıştırmayı deneyin. Otomatik olarak neyin yanlış olduğunu söyleyebilir. Linux'ta olduğunuzu farz ediyorum .... –
Hata ayıklayıcınızda iki ayrı örneği açın ve yan yana adım atın ve iki noktanın nedenini ve nedenini görün. Ayrıca lütfen bu makroyu da bırakın. Bir satır içi işlevi yapacağız. –
@JohnZwinck Tamam, hata ayıklama için yeni ve bu – qwr