#include #include #include #include #ifdef DISPLAY #include SDL_Surface *screen; #endif typedef struct mole mole; enum {NV = 4}; struct mole { double x[NV], xt[NV], xn[NV], xe[NV], xs[NV]; double k[6*NV]; uint32_t c; }; double dt = 0.01; enum { nmoles = 50 }; mole moles[nmoles]; enum { SCRW = 800, SCRH = 600 }; double time; static void init(void) { mole *m; for(m = moles; m < moles + nmoles; m++){ m->x[0] = rand() / (double) RAND_MAX; m->x[1] = rand() / (double) RAND_MAX; m->x[2] = 0.5 * (2 * rand() - 1) / (double) RAND_MAX; m->x[3] = 0.5 * (2 * rand() - 1) / (double) RAND_MAX; m->c = rand(); } } static void forces(int i) { mole *m, *n; double dx, dy, f; for(m = moles; m < moles + nmoles; m++){ m->k[i * NV + 0] = m->xt[2]; m->k[i * NV + 1] = m->xt[3]; m->k[i * NV + 2] = 0; m->k[i * NV + 3] = -4; for(n = moles; n < m; n++){ dx = m->xt[0] - n->xt[0]; dy = m->xt[1] - n->xt[1]; f = 0.001 * pow(dx * dx + dy * dy, -1.5); m->k[i * NV + 2] -= f * dx; m->k[i * NV + 3] -= f * dy; n->k[i * NV + 2] += f * dx; n->k[i * NV + 3] += f * dy; } } } static void rkck(double h) { mole *m; int i; #define F\ for(m = moles; m < moles + nmoles; m++)\ for(i = 0; i < NV; i++)\ m->xt[i] = m->x[i] + h * #define k(n) m->k[n*NV+i] F(0.2*k(0)); forces(1); F((3./40)*k(0)+(9./40)*k(1)); forces(2); F(0.3*k(0)-0.9*k(1)+1.2*k(2)); forces(3); F((-11./54)*k(0)+2.5*k(1)-(70./27.)*k(2)+(35./27.)*k(3)); forces(4); F((1631./55296)*k(0)+(175./512)*k(1)+(575./13824)*k(2)+(44275./110592)*k(3)+(253./4096.)*k(4)); forces(5); for(m = moles; m < moles + nmoles; m++) for(i = 0; i < NV; i++){ m->xn[i] = m->x[i] + h * ((37./378)*k(0)+(250./621)*k(2)+(125./594)*k(3)+(512./1771)*k(5)); m->xe[i] = h * ((37./378-2825./27648)*k(0)+(250./621-18575./48384)*k(2)+(125./594-13525./55296)*k(3)-(277./14336)*k(4)+(512./1771-.25)*k(5)); } #undef F #undef k } static double rkqs(double h) { mole *m; int i; double ht, e; #define SAFETY 0.9 #define ERRCON 1.89e-4 #define eps 1e-5 for(;;){ rkck(h); e = 0; for(m = moles; m < moles + nmoles; m++) for(i = 0; i < NV; i++) if(m->xe[i] / m->xs[i] > e) e = m->xe[i] / m->xs[i]; e /= eps; if(e <= 1.0) break; ht = SAFETY * h * pow(e, -0.25); h = ht <= 0.1*h ? 0.1*h : ht; } time += h; if(e > ERRCON) return SAFETY * h * pow(e, -0.2); return 5*h; } void ode(double fr) { int i; mole *m; double t2; t2 = time + fr; do{ for(m = moles; m < moles + nmoles; m++) for(i = 0; i < NV; i++) m->xt[i] = m->x[i]; forces(0); for(m = moles; m < moles + nmoles; m++) for(i = 0; i < NV; i++) m->xs[i] = fabs(m->x[i]) + fabs(m->k[i]*dt) + 1e-30; if(time + dt > t2) dt = t2 - time; dt = rkqs(dt); for(m = moles; m < moles + nmoles; m++){ for(i = 0; i < NV; i++) m->x[i] = m->xn[i]; if(m->x[0] < 0 && m->x[2] < 0) m->x[2] *= -1; if(m->x[1] < 0 && m->x[3] < 0) m->x[3] *= -1; if(m->x[0] > 1 && m->x[2] > 0) m->x[2] *= -1; if(m->x[1] > 1 && m->x[3] > 0) m->x[3] *= -1; } }while(time < t2); } #ifdef DISPLAY void plot(void) { uint32_t *px; int x, y; mole *m; static int nfr, set[SCRW][SCRH]; SDL_LockSurface(screen); px = screen->pixels; nfr++; for(m = moles; m < moles + nmoles; m++){ x = (int)(m->x[0] * SCRW) % SCRW; y = (int)(m->x[1] * SCRH) % SCRH; if(x < 0) x += SCRW; if(y < 0) y += SCRH; px[y * SCRW + x] = m->c; set[x][y] = nfr; } for(x = 0; x < SCRW; x++) for(y = 0; y < SCRH; y++) if(set[x][y] <= nfr - 50){ px[y * SCRW + x] = 0; set[x][y] = 0; } SDL_UnlockSurface(screen); } #endif int main() { #ifdef DISPLAY SDL_Event ev; if(SDL_Init(SDL_INIT_VIDEO) < 0){ error: fprintf(stderr, "error: %s\n", SDL_GetError()); return 1; } screen = SDL_SetVideoMode(SCRW, SCRH, 32, SDL_DOUBLEBUF); if(screen == NULL) goto error; init(); for(;;){ while(SDL_PollEvent(&ev)) switch(ev.type){ case SDL_QUIT: SDL_Quit(); return 0; } ode(0.001); plot(); SDL_Flip(screen); } #else init(); for(;;){ ode(0.1); fprintf(stderr, "."); fflush(stderr); } #endif }