/
simulation.py
113 lines (84 loc) · 3.11 KB
/
simulation.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import numpy as np
import cv2
from scipy import interpolate
from scipy import ndimage
from scipy import sparse
import scipy.sparse.linalg as linalg # import spsolve
#ffmpeg -i ./%06d.jpg will.mp4
### Setup
dt = 0.01
img = cv2.imread('fajar-2.jpg')
# make image smaller to make run faster if you want
#img = cv2.pyrDown(img)
#img = cv2.pyrDown(img)
Nx = img.shape[0]
Ny = img.shape[1]
v = np.zeros((Nx,Ny,2))
x = np.linspace(0,1,Nx, endpoint=False)
y = np.linspace(0,1,Ny, endpoint=False)
X, Y = np.meshgrid(x,y, indexing='ij')
#v[:,:,0] = -Y + 0.5
#v[:,:,1] = X - 0.5
#### Build necessary derivative and interpolation matrices
def build_grad(N):
# builds N-1 x N finite difference matrix
data = np.array([-np.ones(N), np.ones(N-1)])
return sparse.diags(data, np.array([0, 1]), shape= (N-1,N))
# gradient operators
gradx = sparse.kron(build_grad(Nx), sparse.identity(Ny-1))
grady = sparse.kron(sparse.identity(Nx-1), build_grad(Ny))
def build_K(N):
# builds N-1 x N - 1 K second defivative matrix
data = np.array([-np.ones(N-2), 2*np.ones(N-1), -np.ones(N-2)])
diags =np.array([-1, 0, 1])
return sparse.diags(data, diags )
# Laplacian operator . Zero dirichlet boundary conditions
# why the hell is this reversed? Sigh.
K = sparse.kronsum(build_K(Ny),build_K(Nx))
Ksolve = linalg.factorized(K)
def build_interp(N):
data = np.array([np.ones(N)/2., np.ones(N-1)/2.])
diags = np.array([0, 1])
return sparse.diags(data, diags, shape= (N-1,N))
interpy = sparse.kron(sparse.identity(Nx), build_interp(Ny))
interpx = sparse.kron(build_interp(Nx), sparse.identity(Ny))
def projection_pass(vx,vy):
# alternating projection? Not necessary. In fact stupid. but easy.
'''
vx[0,:] = 0
vx[-1,:] = 0
vy[:,0] = 0
vy[:,-1] = 0
'''
vx[0,:] /= 2.
vx[-1,:] /= 2.
vy[:,0] /= 2.
vy[:,-1] /= 2.
div = gradx.dot(vx.flatten()) + grady.dot(vy.flatten()) #calculate divergence
w = Ksolve(div.flatten())#spsolve(K, div.flatten()) #solve potential
return gradx.T.dot(w).reshape(Nx,Ny-1), grady.T.dot(w).reshape(Nx-1,Ny)
for i in range(600):
#while True: #
v[:,:,0] += np.linalg.norm(img,axis=2) * dt * 0.001 # gravity force
# interpolate onto edges
vx = interpy.dot(v[:,:,0].flatten()).reshape(Nx,Ny-1)
vy = interpx.dot(v[:,:,1].flatten()).reshape(Nx-1,Ny)
# project incomperessible
dvx, dvy = projection_pass(vx,vy)
#interpolate change back to original grid
v[:,:,0] -= interpy.T.dot(dvx.flatten()).reshape(Nx,Ny)
v[:,:,1] -= interpx.T.dot(dvy.flatten()).reshape(Nx,Ny)
#advect everything
coords = np.stack( [(X - v[:,:,0]*dt)*Nx, (Y - v[:,:,1]*dt)*Ny], axis=0)
print(coords.shape)
print(v.shape)
for j in range(3):
img[:,:,j] = ndimage.map_coordinates(img[:,:,j], coords, order=5, mode='wrap')
v[:,:,0] = ndimage.map_coordinates(v[:,:,0], coords, order=5, mode='wrap')
v[:,:,1] = ndimage.map_coordinates(v[:,:,1], coords, order=5, mode='wrap')
cv2.imshow('image',img)
cv2.imwrite(f'fajar-2/{i:06}.jpg',img)
k = cv2.waitKey(30) & 0xFF
if k == ord(' '):
break
cv2.destroyAllWindows()