├── .gitignore ├── DiffusionSolver.py ├── NSConvergence.py ├── DiffusionConvergence.py ├── DFConvergence2.py ├── DFConvergence.py ├── 1D-Unsteady-Quadratic.py ├── 1D-Unsteady.py ├── 1D-Steady.py ├── 1D-Steady-Quadratic.py ├── NavierStokesSolver.py ├── FadlunEtAlSolver.py └── DirectForcingSolver.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.png 3 | *.swp 4 | ._* 5 | -------------------------------------------------------------------------------- /DiffusionSolver.py: -------------------------------------------------------------------------------- 1 | from DirectForcingSolver import DirectForcingSolver 2 | import numpy as np 3 | import scipy.sparse as sp 4 | import scipy.sparse.linalg as sla 5 | import numpy.linalg as la 6 | import matplotlib.pyplot as plt 7 | import os 8 | 9 | class DiffusionSolver(DirectForcingSolver): 10 | def __init__(self, N=4, alphaImplicit=1., alphaExplicit=0., gamma=0., zeta=0., nu=0.01, dt=-1.0, folder=".", order='linear', side='outside'): 11 | DirectForcingSolver.__init__(self, N, alphaImplicit, alphaExplicit, gamma, zeta, nu, dt, folder) 12 | self.gamma = 0. 13 | self.zeta = 0. 14 | self.order = order 15 | self.side = side 16 | 17 | def stepTime(self): 18 | # solve for intermediate velocity 19 | self.calculateRN() 20 | self.qStar, _ = sla.cg(self.A, self.rn) 21 | 22 | # projection step 23 | self.q = self.qStar 24 | 25 | if __name__ == "__main__": 26 | solver = DiffusionSolver(N=80, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=1./np.pi, folder="diffusion-linear-outside") 27 | solver.runSimulation(nt=20, nsave=1) 28 | 29 | solver = DiffusionSolver(N=80, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=1./np.pi, order='constant', folder="diffusion-constant-outside") 30 | solver.runSimulation(nt=20, nsave=1) -------------------------------------------------------------------------------- /NSConvergence.py: -------------------------------------------------------------------------------- 1 | from NavierStokesSolver import NavierStokesSolver 2 | import numpy as np 3 | import numpy.linalg as la 4 | 5 | NT = 20 6 | START_SIZE = 20 7 | 8 | print "-"*80 9 | print "Navier-Stokes solver" 10 | print "-"*80 11 | size = START_SIZE 12 | solver = NavierStokesSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=0.001, folder="NS-grid0") 13 | solver.runSimulation(nt=NT, plot=True, nsave=NT) 14 | u0 = np.reshape(solver.q[::2]/solver.h, (size, size)) 15 | solver.exactSolutionTaylorGreen(solver.dt*NT) 16 | uExact = np.reshape(solver.exactSolution[::2]/solver.h, (size, size)) 17 | print "Difference between 0 and exact:", la.norm(u0-uExact) 18 | print " " 19 | 20 | size *= 3 21 | solver = NavierStokesSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=0.001) 22 | solver.runSimulation(nt=NT, plot=False) 23 | u1 = np.reshape(solver.q[::2]/solver.h, (size, size))[1::3,2::3] 24 | print "Difference between 1 and exact:", la.norm(u1-uExact) 25 | print "Difference between 1 and 0 :", la.norm(u1-u0) 26 | print "Theoretical order of convergence:", (np.log(la.norm(u1-uExact))-np.log(la.norm(u0-uExact)))/np.log(3) 27 | print " " 28 | 29 | size *= 3 30 | solver = NavierStokesSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=0.001, folder="NS-grid2") 31 | solver.runSimulation(nt=NT, plot=True, nsave=NT) 32 | u2 = np.reshape(solver.q[::2]/solver.h, (size, size))[4::9,8::9] 33 | print "Difference between 2 and exact:", la.norm(u2-uExact) 34 | print "Difference between 2 and 1 :", la.norm(u2-u1) 35 | print "Theoretical order of convergence:", (np.log(la.norm(u2-uExact))-np.log(la.norm(u1-uExact)))/np.log(3) 36 | print " " 37 | 38 | print "Experimental order of convergence:", (np.log(la.norm(u2-u1))-np.log(la.norm(u1-u0)))/np.log(3) -------------------------------------------------------------------------------- /DiffusionConvergence.py: -------------------------------------------------------------------------------- 1 | from DiffusionSolver import DiffusionSolver 2 | import numpy as np 3 | import numpy.linalg as la 4 | import matplotlib.pyplot as plt 5 | from mpl_toolkits.mplot3d import axes3d 6 | 7 | def plotField(u, size): 8 | h = 2*np.pi/size 9 | x = np.arange(h, 2*np.pi+h, h) 10 | y = np.arange(h/2., 2*np.pi, h) 11 | X, Y = np.meshgrid(x,y) 12 | fig = plt.figure() 13 | ax = fig.add_subplot(111, projection='3d') 14 | surf = ax.plot_wireframe(X, Y, u) 15 | ax.set_zlim3d(-0.5, 2) 16 | plt.savefig("%d.png" % (size)) 17 | 18 | if __name__ == "__main__": 19 | NT = 20 20 | START_SIZE = 20 21 | 22 | h = 2*np.pi/START_SIZE 23 | x = np.arange(h, 2*np.pi+h, h) 24 | y = np.arange(h/2., 2*np.pi, h) 25 | X, Y = np.meshgrid(x,y) 26 | 27 | print "-"*80 28 | print "Direct Forcing solver" 29 | print "-"*80 30 | size = START_SIZE 31 | print size, 'x', size 32 | solver = DiffusionSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=0.1, order='constant', folder="grid0", side='outside') 33 | solver.runSimulation(nt=NT, nsave=NT) 34 | print " " 35 | #u0 = np.reshape(solver.q[::2]/solver.h, (size, size)) 36 | u0 = np.reshape(solver.qZeroed[::2]/solver.h, (size, size)) 37 | plotField(u0, size) 38 | 39 | size *= 3 40 | print size, 'x', size 41 | solver = DiffusionSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=0.1, order='constant', folder="grid1", side='outside') 42 | solver.runSimulation(nt=NT, nsave=NT) 43 | #u1 = np.reshape(solver.q[::2]/solver.h, (size, size)) 44 | u1 = np.reshape(solver.qZeroed[::2]/solver.h, (size, size)) 45 | e10 = la.norm(u1[1::3,2::3]-u0) 46 | print "Difference between 1 and 0:", e10 47 | print " " 48 | plotField(u1, size) 49 | 50 | size *= 3 51 | print size, 'x', size 52 | solver = DiffusionSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=0.1, order='constant', folder="grid2", side='outside') 53 | solver.runSimulation(nt=NT, nsave=NT) 54 | #u2 = np.reshape(solver.q[::2]/solver.h, (size, size)) 55 | u2 = np.reshape(solver.qZeroed[::2]/solver.h, (size, size)) 56 | e21 = la.norm(u2[4::9,8::9]-u1[1::3,2::3]) 57 | print "Difference between 2 and 1:", e21 58 | print " " 59 | plotField(u2, size) 60 | 61 | print "Experimental order of convergence:", (np.log(e21)-np.log(e10))/np.log(3) -------------------------------------------------------------------------------- /DFConvergence2.py: -------------------------------------------------------------------------------- 1 | from DirectForcingSolver import DirectForcingSolver 2 | import numpy as np 3 | import numpy.linalg as la 4 | import matplotlib.pyplot as plt 5 | from mpl_toolkits.mplot3d import axes3d 6 | 7 | def outside(x, y, R=np.pi/2.): 8 | return (x-np.pi)**2 + (y-np.pi)**2 >= R**2 9 | 10 | def interpolatedField(u, size, factor): 11 | h = 2*np.pi/(size*factor) 12 | x = np.arange(h, 2*np.pi+h, h) 13 | y = np.arange(h/2., 2*np.pi, h) 14 | newU = np.zeros((size*factor, size*factor)) 15 | n = 0 16 | for j in xrange(size): 17 | for i in xrange(size): 18 | for jj in xrange(factor): 19 | eta = (jj+1.)/factor 20 | for ii in xrange(factor): 21 | xi = (ii+1.)/factor 22 | J = j*factor+jj 23 | I = i*factor+ii 24 | newU[J, I] = (1.-xi)*(1.-eta)*u[j-1,i-1] + (xi)*(1.-eta)*u[j-1,i] + (xi)*(eta)*u[j,i] + (1.-xi)*(eta)*u[j,i-1] 25 | if not outside(x[I], y[J]): 26 | newU[J, I] = 0. 27 | return newU 28 | 29 | def plotField(u, size, name): 30 | h = 2*np.pi/size 31 | x = np.arange(h, 2*np.pi+h, h) 32 | y = np.arange(h/2., 2*np.pi, h) 33 | X, Y = np.meshgrid(x,y) 34 | fig = plt.figure() 35 | ax = fig.add_subplot(111, projection='3d') 36 | surf = ax.plot_wireframe(X, Y, u) 37 | ax.set_zlim3d(0, 2) 38 | plt.savefig("%s.png" % (name)) 39 | 40 | if __name__ == "__main__": 41 | NT = 20 42 | START_SIZE = 15 43 | 44 | h = 2*np.pi/START_SIZE 45 | x = np.arange(h, 2*np.pi+h, h) 46 | y = np.arange(h/2., 2*np.pi, h) 47 | X, Y = np.meshgrid(x,y) 48 | 49 | print "-"*80 50 | print "Direct Forcing solver" 51 | print "-"*80 52 | size = START_SIZE 53 | print size, 'x', size 54 | solver = DirectForcingSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.05, dt=0.0001, order='linear', folder="DF"+str(size), side='outside') 55 | solver.runSimulation(nt=NT, nsave=NT) 56 | print " " 57 | u0 = np.reshape(solver.q[::2]/solver.h, (size, size)) 58 | newU0 = interpolatedField(u0, size, 9) 59 | plotField(newU0, size*9, str(size)) 60 | 61 | size *= 3 62 | print size, 'x', size 63 | solver = DirectForcingSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.05, dt=0.0001, order='linear', folder="DF"+str(size), side='outside') 64 | solver.runSimulation(nt=NT, nsave=NT) 65 | print " " 66 | u1 = np.reshape(solver.q[::2]/solver.h, (size, size)) 67 | newU1 = interpolatedField(u1, size, 3) 68 | plotField(newU1, size*3, str(size)) 69 | #u1 = np.reshape(solver.qZeroed[::2]/solver.h, (size, size)) 70 | e10 = la.norm(newU1-newU0) 71 | print "Difference between 1 and 0:", e10 72 | print " " 73 | 74 | size *= 3 75 | print size, 'x', size 76 | solver = DirectForcingSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.05, dt=0.0001, order='linear', folder="DF"+str(size), side='outside') 77 | solver.runSimulation(nt=NT, nsave=NT) 78 | print " " 79 | u2 = np.reshape(solver.q[::2]/solver.h, (size, size)) 80 | plotField(u2, size, str(size)) 81 | #u2 = np.reshape(solver.qZeroed[::2]/solver.h, (size, size)) 82 | e21 = la.norm(u2-newU1) 83 | print "Difference between 2 and 1:", e21 84 | print " " 85 | 86 | print "Experimental order of convergence:", (np.log(e21)-np.log(e10))/np.log(3) -------------------------------------------------------------------------------- /DFConvergence.py: -------------------------------------------------------------------------------- 1 | from DirectForcingSolver import DirectForcingSolver 2 | import numpy as np 3 | import numpy.linalg as la 4 | import matplotlib.pyplot as plt 5 | from mpl_toolkits.mplot3d import axes3d 6 | from matplotlib.colors import LogNorm 7 | 8 | def plotField(u, size, name, folder): 9 | h = 2*np.pi/size 10 | x = np.arange(h, 2*np.pi+h, h) 11 | y = np.arange(h/2., 2*np.pi, h) 12 | X, Y = np.meshgrid(x,y) 13 | plt.ioff() 14 | fig = plt.figure() 15 | ax = fig.add_subplot(111, projection='3d') 16 | surf = ax.plot_wireframe(X, Y, u) 17 | ax.set_zlim3d(0, 2) 18 | fig.savefig("%s/%d.png" % (folder, name)) 19 | 20 | def plotDiff(u2, u1, size, name, folder): 21 | h = 2*np.pi/size 22 | x = np.arange(h, 2*np.pi+h, h) 23 | y = np.arange(h/2., 2*np.pi, h) 24 | X, Y = np.meshgrid(x,y) 25 | plt.ioff() 26 | fig = plt.figure() 27 | ax = fig.add_subplot(111) 28 | CS = ax.pcolor(X, Y, abs(u2-u1), norm=LogNorm(vmin=1e-10, vmax=1)) 29 | fig.gca().set_aspect('equal', adjustable='box') 30 | fig.colorbar(CS) 31 | fig.savefig("%s/diff%d.png" % (folder, name)) 32 | 33 | if __name__ == "__main__": 34 | NT = 20 35 | START_SIZE = 20 36 | ORDER = 'linear' 37 | FOLDER = str(START_SIZE)+'-'+ORDER 38 | 39 | print "\nInterpolation type: %s\n" % (ORDER) 40 | 41 | h = 2*np.pi/START_SIZE 42 | x = np.arange(h, 2*np.pi+h, h) 43 | y = np.arange(h/2., 2*np.pi, h) 44 | X, Y = np.meshgrid(x,y) 45 | 46 | print "-"*80 47 | print "Direct Forcing solver" 48 | print "-"*80 49 | size = START_SIZE 50 | print size, 'x', size 51 | solver = DirectForcingSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=0.0001, order=ORDER, folder=FOLDER+"/DF"+str(size), side='outside', coarsest=START_SIZE) 52 | solver.runSimulation(nt=NT, nsave=NT) 53 | umask, vmask = solver.createMask() 54 | print " " 55 | u0 = np.reshape(solver.q[::2]/solver.h, (size, size)) 56 | v0 = np.reshape(solver.q[1::2]/solver.h, (size, size)) 57 | #plotField(u0, size) 58 | plotField(u0*umask, size, size, FOLDER) 59 | 60 | size *= 3 61 | print size, 'x', size 62 | solver = DirectForcingSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=0.0001, order=ORDER, folder=FOLDER+"/DF"+str(size), side='outside', coarsest=START_SIZE) 63 | solver.runSimulation(nt=NT, nsave=NT) 64 | u1 = np.reshape(solver.q[::2]/solver.h, (size, size)) 65 | v1 = np.reshape(solver.q[1::2]/solver.h, (size, size)) 66 | e10u = la.norm((u1[1::3,2::3]-u0)*umask) 67 | e10v = la.norm((v1[2::3,1::3]-v0)*vmask) 68 | print "Difference between 1 and 0 (u):", e10u 69 | print "Difference between 1 and 0 (v):", e10v 70 | print " " 71 | plotField(u1[1::3,2::3]*umask, START_SIZE, size, FOLDER) 72 | plotDiff(u1[1::3,2::3]*umask, u0*umask, START_SIZE, size, FOLDER) 73 | 74 | size *= 3 75 | print size, 'x', size 76 | solver = DirectForcingSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=0.0001, order=ORDER, folder=FOLDER+"/DF"+str(size), side='outside', coarsest=START_SIZE) 77 | solver.runSimulation(nt=NT, nsave=NT) 78 | u2 = np.reshape(solver.q[::2]/solver.h, (size, size)) 79 | v2 = np.reshape(solver.q[1::2]/solver.h, (size, size)) 80 | e21u = la.norm((u2[4::9,8::9]-u1[1::3,2::3])*umask) 81 | e21v = la.norm((v2[8::9,4::9]-v1[2::3,1::3])*vmask) 82 | print "Difference between 2 and 1 (u):", e21u 83 | print "Difference between 2 and 1 (v):", e21v 84 | print " " 85 | plotField(u2[4::9,8::9]*umask, START_SIZE, size, FOLDER) 86 | plotDiff(u2[4::9,8::9]*umask, u1[1::3,2::3]*umask, START_SIZE, size, FOLDER) 87 | 88 | print "Experimental order of convergence (u):", (np.log(e21u)-np.log(e10u))/np.log(3) 89 | print "Experimental order of convergence (v):", (np.log(e21v)-np.log(e10v))/np.log(3) 90 | 91 | size *= 3 92 | print size, 'x', size 93 | solver = DirectForcingSolver(N=size, alphaExplicit=0., alphaImplicit=1., nu=0.05, dt=0.0001, order=ORDER, folder=FOLDER+"/DF"+str(size), side='outside', coarsest=START_SIZE) 94 | solver.runSimulation(nt=NT, nsave=NT) 95 | u3 = np.reshape(solver.q[::2]/solver.h, (size, size)) 96 | v3 = np.reshape(solver.q[1::2]/solver.h, (size, size)) 97 | e32u = la.norm((u3[13::27,26::27]-u2[4::9,8::9])*umask) 98 | e32v = la.norm((v3[26::27,13::27]-v2[8::9,4::9])*vmask) 99 | print "Difference between 2 and 1 (u):", e32u 100 | print "Difference between 2 and 1 (v):", e32v 101 | print " " 102 | plotField(u3[13::27,26::27]*umask, START_SIZE, size, FOLDER) 103 | plotDiff(u3[13::27,26::27]*umask, u2[4::9,8::9]*umask, START_SIZE, size, FOLDER) 104 | 105 | print "Experimental order of convergence (u):", (np.log(e32u)-np.log(e21u))/np.log(3) 106 | print "Experimental order of convergence (v):", (np.log(e32v)-np.log(e21v))/np.log(3) 107 | -------------------------------------------------------------------------------- /1D-Unsteady-Quadratic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import numpy as np 3 | import scipy.sparse as sp 4 | import scipy.sparse.linalg as sla 5 | import numpy.linalg as la 6 | import matplotlib 7 | matplotlib.use('Agg') 8 | import matplotlib.pyplot as plt 9 | import os 10 | import errno 11 | 12 | def unsteady_channel_flow(N=20, nu=.125, dpdx=-1., interp='linear', nt=400, dt=0.001, folder="new"): 13 | try: 14 | os.makedirs(folder) 15 | except OSError as exc: 16 | if exc.errno == errno.EEXIST and os.path.isdir(folder): 17 | pass 18 | else: 19 | raise 20 | eps = 1.e-8 21 | h = 1./N 22 | y = np.linspace(-0.5+h/2., 0.5-h/2., N) 23 | mask = np.ones(N) 24 | width = 0.8 25 | 26 | left = 0 27 | while y[left]+eps < -width/2.: 28 | left+=1 29 | a = y[left]+width/2. 30 | C2_left = 2*a/(a+h) 31 | C3_left = -a/(a+2*h) 32 | 33 | right = N-1 34 | while y[right]-eps > width/2.: 35 | right-=1 36 | a = width/2.-y[right] 37 | C2_right = 2*a/(a+h) 38 | C3_right = -a/(a+2*h) 39 | 40 | for i in xrange(len(mask)): 41 | if iright: 42 | mask[i] = 0. 43 | 44 | u = np.zeros(N) 45 | uExact = np.zeros(N) 46 | uExact[:] = dpdx/nu/8.*(4*y[:]*y[:]-width**2) 47 | 48 | # matrix 49 | rows = np.zeros(5*N, dtype=np.int) 50 | cols = np.zeros(5*N, dtype=np.int) 51 | vals = np.zeros(5*N, dtype=np.float) 52 | # rhs 53 | b = np.zeros(N) 54 | 55 | index = 0 56 | 57 | for i in xrange(N): 58 | # coefficent of u_{i-2} 59 | rows[index] = i 60 | cols[index] = i-2 if i>1 else N+i-2 61 | if i==left: 62 | vals[index] = 0. 63 | elif i==right: 64 | vals[index] = -C3_right if interp=='quadratic' else 0. 65 | else: 66 | vals[index] = 0. 67 | index+=1 68 | 69 | # coefficient of u_{i-1} 70 | rows[index] = i 71 | cols[index] = i-1 if i>0 else N+i-1 72 | if i==left: 73 | vals[index] = 0. 74 | elif i==right: 75 | vals[index] = -C2_right if interp=='quadratic' else 0. 76 | else: 77 | vals[index] = -nu*dt/h**2 78 | index+=1 79 | 80 | rows[index] = i 81 | cols[index] = i 82 | vals[index] = 1. if (i==left or i==right) else (1. + 2.*nu*dt/h**2) 83 | index+=1 84 | 85 | rows[index] = i 86 | cols[index] = i+1 if i y_right_wall: 37 | right-=1 38 | xi_right = (y_right_wall-y[right])/(y_right_wall-y[right]+h) 39 | 40 | for i in xrange(len(mask)): 41 | if iright: 42 | mask[i] = 0. 43 | 44 | u = np.zeros(N) 45 | uExact = np.zeros(N) 46 | uExact[:] = dpdx/nu/8.*(4*(y[:]-y_origin)*(y[:]-y_origin)-width**2) 47 | 48 | # matrix 49 | rows = np.zeros(3*N, dtype=np.int) 50 | cols = np.zeros(3*N, dtype=np.int) 51 | vals = np.zeros(3*N, dtype=np.float) 52 | # rhs 53 | b = np.zeros(N) 54 | 55 | index = 0 56 | 57 | for i in xrange(N): 58 | rows[index] = i 59 | cols[index] = i-1 if i>0 else N-1 60 | if i==left: 61 | vals[index] = 0. 62 | elif i==right: 63 | vals[index] = -xi_right if interp=='linear' else 0. 64 | else: 65 | vals[index] = -nu*dt/h**2 66 | index+=1 67 | 68 | rows[index] = i 69 | cols[index] = i 70 | vals[index] = 1. if (i==left or i==right) else (1. + 2.*nu*dt/h**2) 71 | index+=1 72 | 73 | rows[index] = i 74 | cols[index] = i+1 if i0: 119 | start1 = start0 + 3**(i-1) 120 | stride1 = stride0*3 121 | diffs[i-1] = la.norm(u[i][start1::stride1] - u[i-1][start0::stride0]) 122 | sizes[i-1] = len(u[i]) 123 | start0 = start1 124 | stride0 = stride1 125 | 126 | h_right = y_right_wall-y_right[:] 127 | h_left = y_left[:]-y_left_wall 128 | np.set_printoptions(6) 129 | print "{}: {} {},".format(sizes[0]/3, h_left, h_right), 130 | observed_rates[0:] = (np.log(diffs[1:])-np.log(diffs[0:-1]))/np.log(1.0/3) 131 | best_fit_rate = -np.polyfit(np.log(sizes), np.log(diffs), 1)[0] 132 | theoretical_rates_left[0:] = 1 + np.log((h_left[1:-1]-3*h_left[0:-2])/(h_left[2:]-3*h_left[1:-1]))/np.log(3.0) 133 | theoretical_rates_right[0:] = 1 + np.log((h_right[1:-1]-3*h_right[0:-2])/(h_right[2:]-3*h_right[1:-1]))/np.log(3.0) 134 | np.set_printoptions(3) 135 | print " Expt: {} {:.3f}, Theory: left: {} right: {}".format(observed_rates, best_fit_rate, theoretical_rates_left, theoretical_rates_right) 136 | 137 | if __name__=="__main__": 138 | START = 10 139 | END = 21 140 | INTERP = "linear" 141 | NUM_GRIDS = 4 142 | print "\nThree-grid convergence" 143 | for size in range(START,END): 144 | FOLDER = str(size) + '-' + INTERP 145 | three_grid_convergence(size, INTERP, NUM_GRIDS, FOLDER) -------------------------------------------------------------------------------- /1D-Steady.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import numpy as np 3 | import scipy.sparse as sp 4 | import scipy.sparse.linalg as sla 5 | import numpy.linalg as la 6 | import matplotlib 7 | matplotlib.use('Agg') 8 | import matplotlib.pyplot as plt 9 | import os 10 | import errno 11 | 12 | def steady_channel_flow(N=20, nu=.125, dpdx=-1., interp='linear', folder="new"): 13 | try: 14 | os.makedirs(folder) 15 | except OSError as exc: 16 | if exc.errno == errno.EEXIST and os.path.isdir(folder): 17 | pass 18 | else: 19 | raise 20 | eps = 1.e-8 21 | h = 1./N 22 | y = np.linspace(-0.5+h/2., 0.5-h/2., N) 23 | mask = np.ones(N) 24 | width = 0.8 25 | left = 0 26 | while y[left]+eps < -width/2.: 27 | left+=1 28 | xi_left = (y[left]+width/2.)/(y[left]+width/2.+h) 29 | right = N-1 30 | while y[right]-eps > width/2.: 31 | right-=1 32 | xi_right = (width/2.-y[right])/(width/2.-y[right]+h) 33 | 34 | for i in xrange(len(mask)): 35 | if iright: 36 | mask[i] = 0. 37 | 38 | u = np.zeros(N) 39 | uExact = np.zeros(N) 40 | uExact[:] = dpdx/nu/8.*(4*y[:]*y[:]-width**2) 41 | 42 | # matrix 43 | rows = np.zeros(3*N, dtype=np.int) 44 | cols = np.zeros(3*N, dtype=np.int) 45 | vals = np.zeros(3*N, dtype=np.float) 46 | # rhs 47 | b = np.zeros(N) 48 | 49 | index = 0 50 | 51 | for i in xrange(N): 52 | rows[index] = i 53 | cols[index] = i-1 if i>0 else N-1 54 | if i==left: 55 | vals[index] = 0. 56 | elif i==right: 57 | vals[index] = -xi_right if interp=='linear' else 0. 58 | else: 59 | vals[index] = 1. 60 | index+=1 61 | 62 | rows[index] = i 63 | cols[index] = i 64 | vals[index] = 1. if (i==left or i==right) else -2. 65 | index+=1 66 | 67 | rows[index] = i 68 | cols[index] = i+1 if i0: 140 | start1 = start0 + 3**(i-1) 141 | stride1 = stride0*3 142 | diffs[i-1] = la.norm(u[i][start1::stride1] - u[i-1][start0::stride0]) 143 | sizes[i-1] = size 144 | start0 = start1 145 | stride0 = stride1 146 | 147 | h = 0.4-y_right[:] 148 | np.set_printoptions(6) 149 | print "{}\t{}".format(sizes[0]/3, h), 150 | observed_rates[0:] = (np.log(diffs[1:])-np.log(diffs[0:-1]))/np.log(1.0/3) 151 | best_fit_rate = -np.polyfit(np.log(sizes), np.log(diffs), 1)[0] 152 | theoretical_rates[0:] = 1 + np.log((h[1:-1]-3*h[0:-2])/(h[2:]-3*h[1:-1]))/np.log(3.0) 153 | np.set_printoptions(3) 154 | print "\t{}\t{:.3f}\t{}".format(observed_rates, best_fit_rate, theoretical_rates) 155 | 156 | if __name__=="__main__": 157 | START = 10 158 | END = 21 159 | INTERP = "linear" 160 | NUM_GRIDS = 5 161 | print "\nTwo-grid convergence" 162 | for size in range(START,END): 163 | FOLDER = str(size) + '-' + INTERP 164 | two_grid_convergence(size, INTERP, NUM_GRIDS, FOLDER) 165 | print "\nThree-grid convergence" 166 | for size in range(START,END): 167 | FOLDER = str(size) + '-' + INTERP 168 | three_grid_convergence(size, INTERP, NUM_GRIDS, FOLDER) -------------------------------------------------------------------------------- /1D-Steady-Quadratic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import numpy as np 3 | import scipy.sparse as sp 4 | import scipy.sparse.linalg as sla 5 | import numpy.linalg as la 6 | import matplotlib 7 | matplotlib.use('Agg') 8 | import matplotlib.pyplot as plt 9 | import os 10 | import errno 11 | 12 | def steady_channel_flow(N=20, nu=.125, dpdx=-1., interp='linear', folder="new"): 13 | try: 14 | os.makedirs(folder) 15 | except OSError as exc: 16 | if exc.errno == errno.EEXIST and os.path.isdir(folder): 17 | pass 18 | else: 19 | raise 20 | eps = 1.e-8 21 | h = 1./N 22 | y = np.linspace(-0.5+h/2., 0.5-h/2., N) 23 | mask = np.ones(N) 24 | width = 0.8 25 | 26 | left = 0 27 | while y[left]+eps < -width/2.: 28 | left+=1 29 | a = y[left]+width/2. 30 | C2_left = 2*a/(a+h) 31 | C3_left = -a/(a+2*h) 32 | 33 | right = N-1 34 | while y[right]-eps > width/2.: 35 | right-=1 36 | a = width/2.-y[right] 37 | C2_right = 2*a/(a+h) 38 | C3_right = -a/(a+2*h) 39 | 40 | for i in xrange(len(mask)): 41 | if iright: 42 | mask[i] = 0. 43 | 44 | u = np.zeros(N) 45 | uExact = np.zeros(N) 46 | uExact[:] = dpdx/nu/8.*(4*y[:]*y[:]-width**2) 47 | 48 | # matrix 49 | rows = np.zeros(5*N, dtype=np.int) 50 | cols = np.zeros(5*N, dtype=np.int) 51 | vals = np.zeros(5*N, dtype=np.float) 52 | # rhs 53 | b = np.zeros(N) 54 | 55 | index = 0 56 | 57 | for i in xrange(N): 58 | # coefficent of u_{i-2} 59 | rows[index] = i 60 | cols[index] = i-2 if i>1 else N+i-2 61 | if i==left: 62 | vals[index] = 0. 63 | elif i==right: 64 | vals[index] = -C3_right if interp=='quadratic' else 0. 65 | else: 66 | vals[index] = 0. 67 | index+=1 68 | 69 | # coefficient of u_{i-1} 70 | rows[index] = i 71 | cols[index] = i-1 if i>0 else N+i-1 72 | if i==left: 73 | vals[index] = 0. 74 | elif i==right: 75 | vals[index] = -C2_right if interp=='quadratic' else 0. 76 | else: 77 | vals[index] = 1. 78 | index+=1 79 | 80 | rows[index] = i 81 | cols[index] = i 82 | vals[index] = 1. if (i==left or i==right) else -2. 83 | index+=1 84 | 85 | rows[index] = i 86 | cols[index] = i+1 if i0: 17 | self.dt = dt 18 | print "nu =", self.nu 19 | print "h =", self.h 20 | print "dt =", self.dt 21 | self.alphaExplicit = alphaExplicit 22 | self.alphaImplicit = alphaImplicit 23 | self.gamma = gamma 24 | self.zeta = zeta 25 | self.folder = folder 26 | 27 | def initVecs(self): 28 | N = self.N 29 | self.phi = np.zeros(N*N) 30 | self.q = np.zeros(2*N*N) 31 | self.qStar = np.zeros(2*N*N) 32 | self.rn = np.zeros(2*N*N) 33 | self.H = np.zeros(2*N*N) 34 | self.initFluxes() 35 | 36 | def initFluxes(self): 37 | h = self.h 38 | N = self.N 39 | index = 0 40 | for j in xrange(N): 41 | for i in xrange(N): 42 | # u 43 | x = (i+1)*h 44 | y = (j+0.5)*h 45 | self.q[index] = np.sin(x)*np.cos(y)*h 46 | index+=1 47 | 48 | # v 49 | x = (i+0.5)*h 50 | y = (j+1)*h 51 | self.q[index] = -np.cos(x)*np.sin(y)*h 52 | index+=1 53 | 54 | def exactSolutionTaylorGreen(self, t): 55 | h = self.h 56 | N = self.N 57 | self.exactSolution = np.zeros(2*N*N) 58 | index = 0 59 | for j in xrange(N): 60 | for i in xrange(N): 61 | # u 62 | x = (i+1)*h 63 | y = (j+0.5)*h 64 | self.exactSolution[index] = np.exp(-2*self.nu*t)*np.sin(x)*np.cos(y)*h 65 | index+=1 66 | 67 | # v 68 | x = (i+0.5)*h 69 | y = (j+1)*h 70 | self.exactSolution[index] = -np.exp(-2*self.nu*t)*np.cos(x)*np.sin(y)*h 71 | index+=1 72 | 73 | def initMatrices(self): 74 | self.generateA() 75 | self.generateBNQ() 76 | self.generateQTBNQ() 77 | 78 | def generateBNQ(self): 79 | N = self.N 80 | rows = np.zeros(4*N*N, dtype=np.int) 81 | cols = np.zeros(4*N*N, dtype=np.int) 82 | vals = np.zeros(4*N*N, dtype=np.float) 83 | 84 | index = 0 85 | row_index = 0 86 | for j in xrange(N): 87 | for i in xrange(N): 88 | # u 89 | rows[index] = row_index 90 | cols[index] = j*N+i 91 | vals[index] = -1. 92 | index+=1 93 | 94 | rows[index] = row_index 95 | cols[index] = j*N+i+1 if i0 else 2*((N-1)*N+i) 141 | vals[index] = -alpha*nu*1./h**2 142 | index+=1 143 | 144 | rows[index] = row_index 145 | cols[index] = 2*(j*N+(i-1)) if i>0 else 2*(j*N+(N-1)) 146 | vals[index] = -alpha*nu*1./h**2 147 | index+=1 148 | 149 | rows[index] = row_index 150 | cols[index] = 2*(j*N+i) 151 | vals[index] = 1./dt + alpha*nu*4./h**2 152 | index+=1 153 | 154 | rows[index] = row_index 155 | cols[index] = 2*(j*N+(i+1)) if i0 else 2*((N-1)*N+i)+1 169 | vals[index] = -alpha*nu*1./h**2 170 | index+=1 171 | 172 | rows[index] = row_index 173 | cols[index] = 2*(j*N+(i-1))+1 if i>0 else 2*(j*N+(N-1))+1 174 | vals[index] = -alpha*nu*1./h**2 175 | index+=1 176 | 177 | rows[index] = row_index 178 | cols[index] = 2*(j*N+i)+1 179 | vals[index] = 1./dt + alpha*nu*4./h**2 180 | index+=1 181 | 182 | rows[index] = row_index 183 | cols[index] = 2*(j*N+(i+1))+1 if i0 else index+2*(N-1) 208 | east = index+2 if i0 else northeast+2*(N-1) 237 | southeast = center-1 238 | southwest = southeast-2 if i>0 else southeast+2*(N-1) 239 | 240 | convection_term = (0.25/h**2)*((self.q[center]+self.q[east])*(self.q[northeast]+self.q[southeast]) - (self.q[center]+self.q[west])*(self.q[northwest]+self.q[southwest]))/h \ 241 | + (0.25/h**2)*((self.q[center]+self.q[north])*(self.q[center]+self.q[north]) - (self.q[center]+self.q[south])*(self.q[center]+self.q[south]))/h 242 | 243 | self.H[index] = self.gamma*convection_term + self.zeta*self.H[index] 244 | self.rn[index] = (-self.H[index] + diffusion_term + self.q[index]/h/self.dt)*h 245 | 246 | index+=1 247 | 248 | def stepTime(self): 249 | # solve for intermediate velocity 250 | self.calculateRN() 251 | self.qStar, _ = sla.bicgstab(self.A, self.rn, tol=1e-8) 252 | 253 | # solve for pressure 254 | self.rhs2 = self.QT*self.qStar 255 | #self.phi, _ = sla.cg(self.QTBNQ, self.rhs2) 256 | self.phi = self.ml.solve(self.rhs2, tol=1e-8) 257 | 258 | # projection step 259 | self.q = self.qStar - self.BNQ*self.phi 260 | 261 | def writeData(self, n): 262 | h = self.h 263 | N = self.N 264 | 265 | 266 | U = np.zeros(N*N) 267 | U[:] = self.q[::2]/h 268 | U = np.reshape(U, (N,N)) 269 | x = np.linspace(h, 2*np.pi, N) 270 | y = np.linspace(0.5*h, 2*np.pi-0.5*h, N) 271 | X, Y = np.meshgrid(x, y) 272 | 273 | plt.ioff() 274 | CS = plt.contour(X, Y, U, levels=np.linspace(-1., 1., 11)) 275 | plt.colorbar(CS) 276 | plt.axis([0, 2*np.pi, 0, 2*np.pi]) 277 | plt.gca().set_aspect('equal', adjustable='box') 278 | plt.savefig("%s/u%07d.png" % (self.folder,n)) 279 | plt.clf() 280 | 281 | V = np.zeros(N*N) 282 | V[:] = self.q[1::2]/h 283 | V = np.reshape(V, (N,N)) 284 | x = np.linspace(0.5*h, 2*np.pi-0.5*h, N) 285 | y = np.linspace(h, 2*np.pi, N) 286 | X, Y = np.meshgrid(x, y) 287 | 288 | CS = plt.contour(X, Y, V, levels=np.linspace(-1., 1., 11)) 289 | plt.colorbar(CS) 290 | plt.axis([0, 2*np.pi, 0, 2*np.pi]) 291 | plt.gca().set_aspect('equal', adjustable='box') 292 | plt.savefig("%s/v%07d.png" % (self.folder, n)) 293 | plt.clf() 294 | 295 | def runSimulation(self, nt=20, nsave=1, plot=True): 296 | try: 297 | os.makedirs(self.folder) 298 | except OSError as exc: 299 | if exc.errno == errno.EEXIST and os.path.isdir(self.folder): 300 | pass 301 | else: 302 | raise 303 | self.initVecs() 304 | self.initMatrices() 305 | if plot: 306 | self.writeData(0) 307 | for n in xrange(1,nt+1): 308 | self.stepTime() 309 | if n%nsave==0 and plot: 310 | self.writeData(n) 311 | 312 | if __name__ == "__main__": 313 | NT = 20 314 | 315 | solver = NavierStokesSolver(N=6, alphaExplicit=0., alphaImplicit=1., dt=0.1, folder="NS06") 316 | solver.runSimulation(nt=NT) 317 | 318 | solver = NavierStokesSolver(N=12, alphaExplicit=0., alphaImplicit=1., dt=0.1, folder="NS12") 319 | solver.runSimulation(nt=NT) 320 | 321 | solver = NavierStokesSolver(N=24, alphaExplicit=0., alphaImplicit=1., dt=0.1, folder="NS24") 322 | solver.runSimulation(nt=NT) 323 | -------------------------------------------------------------------------------- /FadlunEtAlSolver.py: -------------------------------------------------------------------------------- 1 | from NavierStokesSolver import NavierStokesSolver 2 | import numpy as np 3 | import scipy.sparse as sp 4 | import scipy.sparse.linalg as sla 5 | import numpy.linalg as la 6 | import matplotlib.pyplot as plt 7 | import os 8 | 9 | def outside(x, y, R=np.pi/2.): 10 | return (x-np.pi)**2 + (y-np.pi)**2 >= R**2 11 | 12 | def inside(x, y, R=np.pi/2.): 13 | return (x-np.pi)**2 + (y-np.pi)**2 <= R**2 14 | 15 | def pointOfIntersectionX(xLeft, xRight, y): 16 | x0 = np.pi + np.sqrt((np.pi/2.)**2 - (y-np.pi)**2) 17 | x1 = np.pi - np.sqrt((np.pi/2.)**2 - (y-np.pi)**2) 18 | if xLeft <= x0 and x0 <=xRight: 19 | return x0 20 | else: 21 | return x1 22 | 23 | def pointOfIntersectionY(yBottom, yTop, x): 24 | y0 = np.pi + np.sqrt((np.pi/2.)**2 - (x-np.pi)**2) 25 | y1 = np.pi - np.sqrt((np.pi/2.)**2 - (x-np.pi)**2) 26 | if yBottom <= y0 and y0 <=yTop: 27 | return y0 28 | else: 29 | return y1 30 | 31 | class FadlunEtAlSolver(NavierStokesSolver): 32 | def __init__(self, N=4, alphaImplicit=1., alphaExplicit=0., gamma=1., zeta=0., nu=0.01, dt=-1.0, folder=".", order='linear', side='outside', coarsest=15): 33 | NavierStokesSolver.__init__(self, N, alphaImplicit, alphaExplicit, gamma, zeta, nu, dt, folder) 34 | self.order = order 35 | self.side = side 36 | self.coarsest = coarsest 37 | 38 | def initVecs(self): 39 | NavierStokesSolver.initVecs(self) 40 | N = self.N 41 | self.qZeroed = np.zeros(2*N*N) 42 | self.tagsX = -np.ones(2*N*N, dtype=np.int) 43 | self.coeffsX = np.zeros(2*N*N) 44 | self.tagsY = -np.ones(2*N*N, dtype=np.int) 45 | self.coeffsY = np.zeros(2*N*N) 46 | self.xu = -np.zeros(N+1) 47 | self.yu = -np.zeros(N+1) 48 | self.xv = -np.zeros(N+1) 49 | self.yv = -np.zeros(N+1) 50 | self.initCoords() 51 | self.tagPoints() 52 | self.net_flux = np.zeros(0) 53 | 54 | def initFluxes(self): 55 | h = self.h 56 | N = self.N 57 | row_index = 0 58 | for j in xrange(N): 59 | for i in xrange(N): 60 | # u 61 | x = (i+1)*h 62 | y = (j+0.5)*h 63 | self.q[row_index] = 1.0*h 64 | row_index+=1 65 | 66 | # v 67 | x = (i+0.5)*h 68 | y = (j+1)*h 69 | self.q[row_index] = 0.0*h 70 | row_index+=1 71 | 72 | def initCoords(self): 73 | N = self.N 74 | h = self.h 75 | index = 0 76 | for j in xrange(N): 77 | self.yu[j] = (j+0.5)*h 78 | self.yv[j] = (j+1)*h 79 | for i in xrange(N): 80 | self.xu[i] = (i+1)*h 81 | self.xv[i] = (i+0.5)*h 82 | self.xu[N] = (N+1)*h 83 | self.yu[N] = (N+0.5)*h 84 | self.xv[N] = (N+0.5)*h 85 | self.yv[N] = (N+1)*h 86 | #print self.xu 87 | #print self.yu 88 | #print self.xv 89 | #print self.yv 90 | 91 | def tagPoints(self): 92 | if self.side =='outside': 93 | self.tagOutsidePoints() 94 | if self.side =='inside': 95 | self.tagInsidePoints() 96 | self.plotTaggedPoints() 97 | 98 | def tagOutsidePoints(self): 99 | N = self.N 100 | h = self.h 101 | index = 0 102 | for j in xrange(N): 103 | for i in xrange(N): 104 | # tagsX 105 | if outside(self.xu[i], self.yu[j]) and not outside(self.xu[i-1], self.yu[j]): 106 | x = pointOfIntersectionX(self.xu[i-1], self.xu[i], self.yu[j]) 107 | self.tagsX[index] = index+2 108 | self.coeffsX[index] = (self.xu[i]-x)/(self.xu[i+1]-x) 109 | elif outside(self.xu[i], self.yu[j]) and not outside(self.xu[i+1], self.yu[j]): 110 | x = pointOfIntersectionX(self.xu[i], self.xu[i+1], self.yu[j]) 111 | self.tagsX[index] = index-2 112 | self.coeffsX[index] = (self.xu[i]-x)/(self.xu[i-1]-x) 113 | 114 | # tagsY 115 | if outside(self.xu[i], self.yu[j]) and not outside(self.xu[i], self.yu[j-1]): 116 | y = pointOfIntersectionY(self.yu[j-1], self.yu[j], self.xu[i]) 117 | self.tagsY[index] = index+2*N 118 | self.coeffsY[index] = (self.yu[j]-y)/(self.yu[j+1]-y) 119 | elif outside(self.xu[i], self.yu[j]) and not outside(self.xu[i], self.yu[j+1]): 120 | y = pointOfIntersectionY(self.yu[j], self.yu[j+1], self.xu[i]) 121 | self.tagsY[index] = index-2*N 122 | self.coeffsY[index] = (self.yu[j]-y)/(self.yu[j-1]-y) 123 | 124 | index+=1 125 | 126 | # tagsX 127 | if outside(self.xv[i], self.yv[j]) and not outside(self.xv[i-1], self.yv[j]): 128 | x = pointOfIntersectionX(self.xv[i-1], self.xv[i], self.yv[j]) 129 | self.tagsX[index] = index+2 130 | self.coeffsX[index] = (self.xv[i]-x)/(self.xv[i+1]-x) 131 | elif outside(self.xv[i], self.yv[j]) and not outside(self.xv[i+1], self.yv[j]): 132 | x = pointOfIntersectionX(self.xv[i], self.xv[i+1], self.yv[j]) 133 | self.tagsX[index] = index-2 134 | self.coeffsX[index] = (self.xv[i]-x)/(self.xv[i-1]-x) 135 | 136 | # tagsY 137 | if outside(self.xv[i], self.yv[j]) and not outside(self.xv[i], self.yv[j-1]): 138 | y = pointOfIntersectionY(self.yv[j-1], self.yv[j], self.xv[i]) 139 | self.tagsY[index] = index+2*N 140 | self.coeffsY[index] = (self.yv[j]-y)/(self.yv[j+1]-y) 141 | elif outside(self.xv[i], self.yv[j]) and not outside(self.xv[i], self.yv[j+1]): 142 | y = pointOfIntersectionY(self.yv[j], self.yv[j+1], self.xv[i]) 143 | self.tagsY[index] = index-2*N 144 | self.coeffsY[index] = (self.yv[j]-y)/(self.yv[j-1]-y) 145 | 146 | index+=1 147 | 148 | #print np.reshape(self.tagsX[::2], (N,N)) 149 | #print np.reshape(self.tagsX[1::2], (N,N)) 150 | #print np.reshape(self.tagsY[::2], (N,N)) 151 | #print np.reshape(self.tagsY[1::2], (N,N)) 152 | 153 | def tagInsidePoints(self): 154 | N = self.N 155 | h = self.h 156 | for j in xrange(1,N-1): 157 | for i in xrange(1,N-1): 158 | index = 2*(j*N+i) 159 | # tagsX 160 | if inside(self.xu[i], self.yu[j]) and not inside(self.xu[i-1], self.yu[j]): 161 | x = pointOfIntersectionX(self.xu[i-1], self.xu[i], self.yu[j]) 162 | self.tagsX[index] = index+2 163 | self.coeffsX[index] = (self.xu[i]-x)/(self.xu[i+1]-x) 164 | elif inside(self.xu[i], self.yu[j]) and not inside(self.xu[i+1], self.yu[j]): 165 | x = pointOfIntersectionX(self.xu[i], self.xu[i+1], self.yu[j]) 166 | self.tagsX[index] = index-2 167 | self.coeffsX[index] = (self.xu[i]-x)/(self.xu[i-1]-x) 168 | 169 | # tagsY 170 | if inside(self.xu[i], self.yu[j]) and not inside(self.xu[i], self.yu[j-1]): 171 | y = pointOfIntersectionY(self.yu[j-1], self.yu[j], self.xu[i]) 172 | self.tagsY[index] = index+2*N 173 | self.coeffsY[index] = (self.yu[j]-y)/(self.yu[j+1]-y) 174 | elif inside(self.xu[i], self.yu[j]) and not inside(self.xu[i], self.yu[j+1]): 175 | y = pointOfIntersectionY(self.yu[j], self.yu[j+1], self.xu[i]) 176 | self.tagsY[index] = index-2*N 177 | self.coeffsY[index] = (self.yu[j]-y)/(self.yu[j-1]-y) 178 | 179 | index+=1 180 | # tagsX 181 | if inside(self.xv[i], self.yv[j]) and not inside(self.xv[i-1], self.yv[j]): 182 | x = pointOfIntersectionX(self.xv[i-1], self.xv[i], self.yv[j]) 183 | self.tagsX[index] = index+2 184 | self.coeffsX[index] = (self.xv[i]-x)/(self.xv[i+1]-x) 185 | elif inside(self.xv[i], self.yv[j]) and not inside(self.xv[i+1], self.yv[j]): 186 | x = pointOfIntersectionX(self.xv[i], self.xv[i+1], self.yv[j]) 187 | self.tagsX[index] = index-2 188 | self.coeffsX[index] = (self.xv[i]-x)/(self.xv[i-1]-x) 189 | 190 | # tagsY 191 | if inside(self.xv[i], self.yv[j]) and not inside(self.xv[i], self.yv[j-1]): 192 | y = pointOfIntersectionY(self.yv[j-1], self.yv[j], self.xv[i]) 193 | self.tagsY[index] = index+2*N 194 | self.coeffsY[index] = (self.yv[j]-y)/(self.yv[j+1]-y) 195 | elif inside(self.xv[i], self.yv[j]) and not inside(self.xv[i], self.yv[j+1]): 196 | y = pointOfIntersectionY(self.yv[j], self.yv[j+1], self.xv[i]) 197 | self.tagsY[index] = index-2*N 198 | self.coeffsY[index] = (self.yv[j]-y)/(self.yv[j-1]-y) 199 | 200 | #print np.reshape(self.tagsX[::2], (N,N)) 201 | #print np.reshape(self.tagsX[1::2], (N,N)) 202 | #print np.reshape(self.tagsY[::2], (N,N)) 203 | #print np.reshape(self.tagsY[1::2], (N,N)) 204 | 205 | def plotTaggedPoints(self): 206 | N = self.N 207 | plt.ioff() 208 | fig = plt.figure() 209 | ax = fig.add_subplot(111) 210 | indices = [i for i,tagX in enumerate(self.tagsX) if tagX>-1] 211 | x = np.zeros(len(indices)) 212 | y = np.zeros(len(indices)) 213 | for I, index in enumerate(indices): 214 | idx = index/2 215 | i = idx % N 216 | j = idx / N 217 | if index % 2 == 0: 218 | x[I] = self.xu[i] 219 | y[I] = self.yu[j] 220 | else: 221 | x[I] = self.xv[i] 222 | y[I] = self.yv[j] 223 | ax.plot(x, y, 'ob') 224 | 225 | indices = [i for i,tagY in enumerate(self.tagsY) if tagY>-1] 226 | x = np.zeros(len(indices)) 227 | y = np.zeros(len(indices)) 228 | for I, index in enumerate(indices): 229 | idx = index/2 230 | i = idx % N 231 | j = idx / N 232 | if index % 2 == 0: 233 | x[I] = self.xu[i] 234 | y[I] = self.yu[j] 235 | else: 236 | x[I] = self.xv[i] 237 | y[I] = self.yv[j] 238 | ax.plot(x, y, 'xr', mew=1.5) 239 | 240 | ax.axis([0, 2*np.pi, 0, 2*np.pi]) 241 | ax.grid(True) 242 | ax.set_xticks(np.linspace(0, 2*np.pi, N+1)) 243 | ax.set_yticks(np.linspace(0, 2*np.pi, N+1)) 244 | fig.gca().set_aspect('equal', adjustable='box') 245 | circ = plt.Circle((np.pi, np.pi), radius=np.pi/2., color='k', fill=False) 246 | ax.add_patch(circ) 247 | fig.savefig(self.folder+"/taggedPoints.png") 248 | fig.clf() 249 | 250 | def generateA(self): 251 | NavierStokesSolver.generateA(self) 252 | N = self.N 253 | index = 0 254 | for j in xrange(N): 255 | for i in xrange(N): 256 | if self.order == 'constant': 257 | # u 258 | if self.tagsX[index]>-1 or self.tagsY[index]>-1: 259 | start = self.A.indptr[index] 260 | self.A.data[start] = 0. 261 | self.A.data[start+1] = 0. 262 | self.A.data[start+2] = 1./self.dt 263 | self.A.data[start+3] = 0. 264 | self.A.data[start+4] = 0. 265 | index+=1 266 | 267 | # v 268 | if self.tagsX[index]>-1 or self.tagsY[index]>-1: 269 | start = self.A.indptr[index] 270 | self.A.data[start] = 0. 271 | self.A.data[start+1] = 0. 272 | self.A.data[start+2] = 1./self.dt 273 | self.A.data[start+3] = 0. 274 | self.A.data[start+4] = 0. 275 | index+=1 276 | 277 | if self.order == 'linear': 278 | # u 279 | start = self.A.indptr[index] 280 | if self.tagsX[index]>-1: 281 | self.A.data[start:start+5] = 0. 282 | self.A.data[start+2] = 1./self.dt 283 | for i,idx in enumerate(self.A.indices[start:start+5]): 284 | if idx==self.tagsX[index]: 285 | self.A.data[start+i] = -self.coeffsX[index]/self.dt 286 | #print "index:", index, "tagsX:", self.tagsX[index], "coeffsX:", self.coeffsX[index] 287 | elif self.tagsY[index]>-1: 288 | self.A.data[start:start+5] = 0. 289 | self.A.data[start+2] = 1./self.dt 290 | for i,idx in enumerate(self.A.indices[start:start+5]): 291 | if idx==self.tagsY[index]: 292 | self.A.data[start+i] = -self.coeffsY[index]/self.dt 293 | index+=1 294 | 295 | # v 296 | start = self.A.indptr[index] 297 | if self.tagsY[index]>-1: 298 | self.A.data[start:start+5] = 0. 299 | self.A.data[start+2] = 1./self.dt 300 | for i,idx in enumerate(self.A.indices[start:start+5]): 301 | if idx==self.tagsY[index]: 302 | self.A.data[start+i] = -self.coeffsY[index]/self.dt 303 | elif self.tagsX[index]>-1: 304 | self.A.data[start:start+5] = 0. 305 | self.A.data[start+2] = 1./self.dt 306 | for i,idx in enumerate(self.A.indices[start:start+5]): 307 | if idx==self.tagsX[index]: 308 | self.A.data[start+i] = -self.coeffsX[index]/self.dt 309 | index+=1 310 | #print self.A.data 311 | 312 | def calculateRN(self): 313 | NavierStokesSolver.calculateRN(self) 314 | N = self.N 315 | index = 0 316 | for j in xrange(N): 317 | for i in xrange(N): 318 | # u 319 | if self.tagsX[index]>-1 or self.tagsY[index]>-1: 320 | self.rn[index] = 0. 321 | index+=1 322 | 323 | # v 324 | if self.tagsX[index]>-1 or self.tagsY[index]>-1: 325 | self.rn[index] = 0. 326 | index+=1 327 | 328 | def zeroFluxesInsideBody(self): 329 | N = self.N 330 | halo = 1.0 331 | self.qZeroed[:] = self.q[:] 332 | index = 0 333 | for j in xrange(N): 334 | for i in xrange(N): 335 | # u 336 | if not outside(self.xu[i], self.yu[j], np.pi/2.*halo): 337 | self.qZeroed[index] = 0. 338 | index+=1 339 | 340 | # v 341 | if not outside(self.xv[i], self.yv[j], np.pi/2.*halo): 342 | self.qZeroed[index] = 0. 343 | index+=1 344 | 345 | def createMask(self): 346 | N = self.N 347 | halo = 1.0 348 | umask = np.ones(N*N) 349 | vmask = np.ones(N*N) 350 | index = 0 351 | for j in xrange(N): 352 | for i in xrange(N): 353 | # u 354 | if not outside(self.xu[i], self.yu[j], np.pi/2.*halo): 355 | umask[index] = 0. 356 | 357 | # v 358 | if not outside(self.xv[i], self.yv[j], np.pi/2.*halo): 359 | vmask[index] = 0. 360 | 361 | index+=1 362 | return np.reshape(umask, (N, N)), np.reshape(vmask, (N, N)) 363 | 364 | def writeData(self, n): 365 | h = self.h 366 | N = self.N 367 | 368 | # u-velocity 369 | self.zeroFluxesInsideBody() 370 | U = np.zeros(N*N) 371 | U[:] = self.qZeroed[::2]/h 372 | #U[:] = self.q[::2]/h 373 | U = np.reshape(U, (N,N)) 374 | x = np.linspace(h, 2*np.pi, N) 375 | y = np.linspace(0.5*h, 2*np.pi-0.5*h, N) 376 | X, Y = np.meshgrid(x, y) 377 | fig = plt.figure() 378 | ax = fig.add_subplot(111) 379 | CS = ax.contour(X, Y, U, levels=np.linspace(-2., 2., 21)) 380 | fig.colorbar(CS) 381 | ax.axis([0, 2*np.pi, 0, 2*np.pi]) 382 | #ax.grid(True) 383 | #ax.set_xticks(np.linspace(0, 2*np.pi, self.coarsest+1)) 384 | #ax.set_yticks(np.linspace(0, 2*np.pi, self.coarsest+1)) 385 | fig.gca().set_aspect('equal', adjustable='box') 386 | circ = plt.Circle((np.pi, np.pi), radius=np.pi/2., color='k', fill=False) 387 | ax.add_patch(circ) 388 | fig.savefig("%s/u%07d.png" % (self.folder,n)) 389 | fig.clf() 390 | 391 | # v-velocity 392 | V = np.zeros(N*N) 393 | V[:] = self.qZeroed[1::2]/h 394 | #V[:] = self.q[1::2]/h 395 | V = np.reshape(V, (N,N)) 396 | x = np.linspace(0.5*h, 2*np.pi-0.5*h, N) 397 | y = np.linspace(h, 2*np.pi, N) 398 | X, Y = np.meshgrid(x, y) 399 | fig = plt.figure() 400 | ax = fig.add_subplot(111) 401 | CS = ax.contour(X, Y, V, levels=np.linspace(-2., 2., 21)) 402 | fig.colorbar(CS) 403 | ax.axis([0, 2*np.pi, 0, 2*np.pi]) 404 | #ax.grid(True) 405 | #ax.set_xticks(np.linspace(0, 2*np.pi, self.coarsest+1)) 406 | #ax.set_yticks(np.linspace(0, 2*np.pi, self.coarsest+1)) 407 | fig.gca().set_aspect('equal', adjustable='box') 408 | circ = plt.Circle((np.pi, np.pi), radius=np.pi/2., color='k', fill=False) 409 | ax.add_patch(circ) 410 | fig.savefig("%s/v%07d.png" % (self.folder,n)) 411 | fig.clf() 412 | 413 | # pressure 414 | 415 | def stepTime(self): 416 | NavierStokesSolver.stepTime(self) 417 | 418 | # mass conservation 419 | sum_fluxes = np.sum(self.QT * self.q) 420 | self.net_flux = np.append(self.net_flux, sum_fluxes) 421 | 422 | def runSimulation(self, nt=20, nsave=1, plot=True): 423 | NavierStokesSolver.runSimulation(self, nt=20, nsave=1, plot=True) 424 | 425 | if plot: 426 | plt.ioff() 427 | plt.clf() 428 | plt.plot(np.arange(1,nt+1), self.net_flux) 429 | #plt.axis([0., nt, -1., 1.]) 430 | plt.savefig("%s/net_flux.png" % (self.folder)) 431 | 432 | if __name__ == "__main__": 433 | solver = FadlunEtAlSolver(N=80, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=1./np.pi, side='inside', folder="FadlunEtAl/flow-linear-inside") 434 | solver.runSimulation(nt=20, nsave=1) 435 | 436 | solver = FadlunEtAlSolver(N=80, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=1./np.pi, order='constant', side='inside', folder="FadlunEtAl/flow-constant-inside") 437 | solver.runSimulation(nt=20, nsave=1) 438 | 439 | solver = FadlunEtAlSolver(N=80, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=1./np.pi, folder="FadlunEtAl/flow-linear-outside") 440 | solver.runSimulation(nt=20, nsave=1) 441 | 442 | solver = FadlunEtAlSolver(N=80, alphaExplicit=0., alphaImplicit=1., nu=0.1, dt=1./np.pi, order='constant', folder="FadlunEtAl/flow-constant-outside") 443 | solver.runSimulation(nt=20, nsave=1) 444 | -------------------------------------------------------------------------------- /DirectForcingSolver.py: -------------------------------------------------------------------------------- 1 | from NavierStokesSolver import NavierStokesSolver 2 | import numpy as np 3 | import scipy.sparse as sp 4 | import scipy.sparse.linalg as sla 5 | import numpy.linalg as la 6 | import matplotlib.pyplot as plt 7 | import os 8 | 9 | epsilon = 1.e-8 10 | 11 | def displacement(x1, y1, x2, y2): 12 | return np.sqrt((x1-x2)**2 + (y1-y2)**2) 13 | 14 | def outside(x, y, R=np.pi/2.): 15 | return displacement(x, y, np.pi, np.pi) + epsilon > R 16 | 17 | def inside(x, y, R=np.pi/2.): 18 | return displacement(x, y, np.pi, np.pi) - epsilon < R 19 | 20 | def pointOfIntersectionX(xLeft, xRight, y): 21 | x0 = np.pi + np.sqrt((np.pi/2.)**2 - (y-np.pi)**2) 22 | x1 = np.pi - np.sqrt((np.pi/2.)**2 - (y-np.pi)**2) 23 | if xLeft <= x0 and x0 <=xRight: 24 | return x0 25 | else: 26 | return x1 27 | 28 | def pointOfIntersectionY(yBottom, yTop, x): 29 | y0 = np.pi + np.sqrt((np.pi/2.)**2 - (x-np.pi)**2) 30 | y1 = np.pi - np.sqrt((np.pi/2.)**2 - (x-np.pi)**2) 31 | if yBottom <= y0 and y0 <=yTop: 32 | return y0 33 | else: 34 | return y1 35 | 36 | class DirectForcingSolver(NavierStokesSolver): 37 | def __init__(self, N=4, alphaImplicit=1., alphaExplicit=0., gamma=1., zeta=0., nu=0.01, dt=-1.0, folder=".", order='linear', side='outside', coarsest=15): 38 | NavierStokesSolver.__init__(self, N, alphaImplicit, alphaExplicit, gamma, zeta, nu, dt, folder) 39 | self.order = order 40 | self.side = side 41 | self.coarsest = coarsest 42 | 43 | def initVecs(self): 44 | NavierStokesSolver.initVecs(self) 45 | N = self.N 46 | self.qZeroed = np.zeros(2*N*N) 47 | self.tagsX = -np.ones(2*N*N, dtype=np.int) 48 | self.coeffsX = np.zeros(2*N*N) 49 | self.tagsY = -np.ones(2*N*N, dtype=np.int) 50 | self.coeffsY = np.zeros(2*N*N) 51 | self.xu = -np.zeros(N+1) 52 | self.yu = -np.zeros(N+1) 53 | self.xv = -np.zeros(N+1) 54 | self.yv = -np.zeros(N+1) 55 | self.initCoords() 56 | self.tagPoints() 57 | 58 | def initFluxes(self): 59 | h = self.h 60 | N = self.N 61 | row_index = 0 62 | for j in xrange(N): 63 | for i in xrange(N): 64 | # u 65 | x = (i+1)*h 66 | y = (j+0.5)*h 67 | self.q[row_index] = 1.0*h 68 | row_index+=1 69 | 70 | # v 71 | x = (i+0.5)*h 72 | y = (j+1)*h 73 | self.q[row_index] = 0.0*h 74 | row_index+=1 75 | 76 | def initCoords(self): 77 | N = self.N 78 | h = self.h 79 | index = 0 80 | for j in xrange(N): 81 | self.yu[j] = (j+0.5)*h 82 | self.yv[j] = (j+1)*h 83 | for i in xrange(N): 84 | self.xu[i] = (i+1)*h 85 | self.xv[i] = (i+0.5)*h 86 | self.xu[N] = (N+1)*h 87 | self.yu[N] = (N+0.5)*h 88 | self.xv[N] = (N+0.5)*h 89 | self.yv[N] = (N+1)*h 90 | #print self.xu 91 | #print self.yu 92 | #print self.xv 93 | #print self.yv 94 | 95 | def tagPoints(self): 96 | if self.side =='outside': 97 | self.tagOutsidePoints() 98 | if self.side =='inside': 99 | self.tagInsidePoints() 100 | self.plotTaggedPoints() 101 | 102 | def tagOutsidePoints(self): 103 | N = self.N 104 | h = self.h 105 | index = 0 106 | for j in xrange(N): 107 | for i in xrange(N): 108 | # tagsX 109 | if outside(self.xu[i], self.yu[j]) and not outside(self.xu[i-1], self.yu[j]): 110 | x = pointOfIntersectionX(self.xu[i-1], self.xu[i], self.yu[j]) 111 | self.tagsX[index] = index+2 112 | self.coeffsX[index] = (self.xu[i]-x)/(self.xu[i+1]-x) 113 | elif outside(self.xu[i], self.yu[j]) and not outside(self.xu[i+1], self.yu[j]): 114 | x = pointOfIntersectionX(self.xu[i], self.xu[i+1], self.yu[j]) 115 | self.tagsX[index] = index-2 116 | self.coeffsX[index] = (self.xu[i]-x)/(self.xu[i-1]-x) 117 | 118 | # tagsY 119 | if outside(self.xu[i], self.yu[j]) and not outside(self.xu[i], self.yu[j-1]): 120 | y = pointOfIntersectionY(self.yu[j-1], self.yu[j], self.xu[i]) 121 | self.tagsY[index] = index+2*N 122 | self.coeffsY[index] = (self.yu[j]-y)/(self.yu[j+1]-y) 123 | elif outside(self.xu[i], self.yu[j]) and not outside(self.xu[i], self.yu[j+1]): 124 | y = pointOfIntersectionY(self.yu[j], self.yu[j+1], self.xu[i]) 125 | self.tagsY[index] = index-2*N 126 | self.coeffsY[index] = (self.yu[j]-y)/(self.yu[j-1]-y) 127 | 128 | index+=1 129 | 130 | # tagsX 131 | if outside(self.xv[i], self.yv[j]) and not outside(self.xv[i-1], self.yv[j]): 132 | x = pointOfIntersectionX(self.xv[i-1], self.xv[i], self.yv[j]) 133 | self.tagsX[index] = index+2 134 | self.coeffsX[index] = (self.xv[i]-x)/(self.xv[i+1]-x) 135 | elif outside(self.xv[i], self.yv[j]) and not outside(self.xv[i+1], self.yv[j]): 136 | x = pointOfIntersectionX(self.xv[i], self.xv[i+1], self.yv[j]) 137 | self.tagsX[index] = index-2 138 | self.coeffsX[index] = (self.xv[i]-x)/(self.xv[i-1]-x) 139 | 140 | # tagsY 141 | if outside(self.xv[i], self.yv[j]) and not outside(self.xv[i], self.yv[j-1]): 142 | y = pointOfIntersectionY(self.yv[j-1], self.yv[j], self.xv[i]) 143 | self.tagsY[index] = index+2*N 144 | self.coeffsY[index] = (self.yv[j]-y)/(self.yv[j+1]-y) 145 | elif outside(self.xv[i], self.yv[j]) and not outside(self.xv[i], self.yv[j+1]): 146 | y = pointOfIntersectionY(self.yv[j], self.yv[j+1], self.xv[i]) 147 | self.tagsY[index] = index-2*N 148 | self.coeffsY[index] = (self.yv[j]-y)/(self.yv[j-1]-y) 149 | 150 | index+=1 151 | 152 | #print np.reshape(self.tagsX[::2], (N,N)) 153 | #print np.reshape(self.tagsX[1::2], (N,N)) 154 | #print np.reshape(self.tagsY[::2], (N,N)) 155 | #print np.reshape(self.tagsY[1::2], (N,N)) 156 | 157 | def tagInsidePoints(self): 158 | N = self.N 159 | h = self.h 160 | for j in xrange(1,N-1): 161 | for i in xrange(1,N-1): 162 | index = 2*(j*N+i) 163 | # tagsX 164 | if inside(self.xu[i], self.yu[j]) and not inside(self.xu[i-1], self.yu[j]): 165 | x = pointOfIntersectionX(self.xu[i-1], self.xu[i], self.yu[j]) 166 | self.tagsX[index] = index+2 167 | self.coeffsX[index] = (self.xu[i]-x)/(self.xu[i+1]-x) 168 | elif inside(self.xu[i], self.yu[j]) and not inside(self.xu[i+1], self.yu[j]): 169 | x = pointOfIntersectionX(self.xu[i], self.xu[i+1], self.yu[j]) 170 | self.tagsX[index] = index-2 171 | self.coeffsX[index] = (self.xu[i]-x)/(self.xu[i-1]-x) 172 | 173 | # tagsY 174 | if inside(self.xu[i], self.yu[j]) and not inside(self.xu[i], self.yu[j-1]): 175 | y = pointOfIntersectionY(self.yu[j-1], self.yu[j], self.xu[i]) 176 | self.tagsY[index] = index+2*N 177 | self.coeffsY[index] = (self.yu[j]-y)/(self.yu[j+1]-y) 178 | elif inside(self.xu[i], self.yu[j]) and not inside(self.xu[i], self.yu[j+1]): 179 | y = pointOfIntersectionY(self.yu[j], self.yu[j+1], self.xu[i]) 180 | self.tagsY[index] = index-2*N 181 | self.coeffsY[index] = (self.yu[j]-y)/(self.yu[j-1]-y) 182 | 183 | index+=1 184 | # tagsX 185 | if inside(self.xv[i], self.yv[j]) and not inside(self.xv[i-1], self.yv[j]): 186 | x = pointOfIntersectionX(self.xv[i-1], self.xv[i], self.yv[j]) 187 | self.tagsX[index] = index+2 188 | self.coeffsX[index] = (self.xv[i]-x)/(self.xv[i+1]-x) 189 | elif inside(self.xv[i], self.yv[j]) and not inside(self.xv[i+1], self.yv[j]): 190 | x = pointOfIntersectionX(self.xv[i], self.xv[i+1], self.yv[j]) 191 | self.tagsX[index] = index-2 192 | self.coeffsX[index] = (self.xv[i]-x)/(self.xv[i-1]-x) 193 | 194 | # tagsY 195 | if inside(self.xv[i], self.yv[j]) and not inside(self.xv[i], self.yv[j-1]): 196 | y = pointOfIntersectionY(self.yv[j-1], self.yv[j], self.xv[i]) 197 | self.tagsY[index] = index+2*N 198 | self.coeffsY[index] = (self.yv[j]-y)/(self.yv[j+1]-y) 199 | elif inside(self.xv[i], self.yv[j]) and not inside(self.xv[i], self.yv[j+1]): 200 | y = pointOfIntersectionY(self.yv[j], self.yv[j+1], self.xv[i]) 201 | self.tagsY[index] = index-2*N 202 | self.coeffsY[index] = (self.yv[j]-y)/(self.yv[j-1]-y) 203 | 204 | #print np.reshape(self.tagsX[::2], (N,N)) 205 | #print np.reshape(self.tagsX[1::2], (N,N)) 206 | #print np.reshape(self.tagsY[::2], (N,N)) 207 | #print np.reshape(self.tagsY[1::2], (N,N)) 208 | 209 | def plotTaggedPoints(self): 210 | N = self.N 211 | fig = plt.figure() 212 | ax = fig.add_subplot(111) 213 | indices = [i for i,tagX in enumerate(self.tagsX) if tagX>-1] 214 | x = np.zeros(len(indices)) 215 | y = np.zeros(len(indices)) 216 | for I, index in enumerate(indices): 217 | idx = index/2 218 | i = idx % N 219 | j = idx / N 220 | if index % 2 == 0: 221 | x[I] = self.xu[i] 222 | y[I] = self.yu[j] 223 | else: 224 | x[I] = self.xv[i] 225 | y[I] = self.yv[j] 226 | ax.plot(x, y, 'ob') 227 | 228 | indices = [i for i,tagY in enumerate(self.tagsY) if tagY>-1] 229 | x = np.zeros(len(indices)) 230 | y = np.zeros(len(indices)) 231 | for I, index in enumerate(indices): 232 | idx = index/2 233 | i = idx % N 234 | j = idx / N 235 | if index % 2 == 0: 236 | x[I] = self.xu[i] 237 | y[I] = self.yu[j] 238 | else: 239 | x[I] = self.xv[i] 240 | y[I] = self.yv[j] 241 | ax.plot(x, y, 'xr', mew=1.5) 242 | 243 | ax.axis([0, 2*np.pi, 0, 2*np.pi]) 244 | ax.grid(True) 245 | ax.set_xticks(np.linspace(0, 2*np.pi, N+1)) 246 | ax.set_yticks(np.linspace(0, 2*np.pi, N+1)) 247 | fig.gca().set_aspect('equal', adjustable='box') 248 | circ = plt.Circle((np.pi, np.pi), radius=np.pi/2., color='k', fill=False) 249 | ax.add_patch(circ) 250 | fig.savefig(self.folder+"/taggedPoints.png") 251 | fig.clf() 252 | 253 | def generateA(self): 254 | NavierStokesSolver.generateA(self) 255 | N = self.N 256 | index = 0 257 | for j in xrange(N): 258 | for i in xrange(N): 259 | if self.order == 'constant': 260 | # u 261 | if self.tagsX[index]>-1 or self.tagsY[index]>-1: 262 | start = self.A.indptr[index] 263 | self.A.data[start] = 0. 264 | self.A.data[start+1] = 0. 265 | self.A.data[start+2] = 1./self.dt 266 | self.A.data[start+3] = 0. 267 | self.A.data[start+4] = 0. 268 | index+=1 269 | 270 | # v 271 | if self.tagsX[index]>-1 or self.tagsY[index]>-1: 272 | start = self.A.indptr[index] 273 | self.A.data[start] = 0. 274 | self.A.data[start+1] = 0. 275 | self.A.data[start+2] = 1./self.dt 276 | self.A.data[start+3] = 0. 277 | self.A.data[start+4] = 0. 278 | index+=1 279 | 280 | if self.order == 'linear': 281 | # u 282 | start = self.A.indptr[index] 283 | if self.tagsX[index]>-1: 284 | self.A.data[start:start+5] = 0. 285 | self.A.data[start+2] = 1./self.dt 286 | for i,idx in enumerate(self.A.indices[start:start+5]): 287 | if idx==self.tagsX[index]: 288 | self.A.data[start+i] = -self.coeffsX[index]/self.dt 289 | #print "index:", index, "tagsX:", self.tagsX[index], "coeffsX:", self.coeffsX[index] 290 | elif self.tagsY[index]>-1: 291 | self.A.data[start:start+5] = 0. 292 | self.A.data[start+2] = 1./self.dt 293 | for i,idx in enumerate(self.A.indices[start:start+5]): 294 | if idx==self.tagsY[index]: 295 | self.A.data[start+i] = -self.coeffsY[index]/self.dt 296 | index+=1 297 | 298 | # v 299 | start = self.A.indptr[index] 300 | if self.tagsY[index]>-1: 301 | self.A.data[start:start+5] = 0. 302 | self.A.data[start+2] = 1./self.dt 303 | for i,idx in enumerate(self.A.indices[start:start+5]): 304 | if idx==self.tagsY[index]: 305 | self.A.data[start+i] = -self.coeffsY[index]/self.dt 306 | elif self.tagsX[index]>-1: 307 | self.A.data[start:start+5] = 0. 308 | self.A.data[start+2] = 1./self.dt 309 | for i,idx in enumerate(self.A.indices[start:start+5]): 310 | if idx==self.tagsX[index]: 311 | self.A.data[start+i] = -self.coeffsX[index]/self.dt 312 | index+=1 313 | #print self.A.data 314 | 315 | def calculateRN(self): 316 | NavierStokesSolver.calculateRN(self) 317 | N = self.N 318 | index = 0 319 | for j in xrange(N): 320 | for i in xrange(N): 321 | # u 322 | if self.tagsX[index]>-1 or self.tagsY[index]>-1: 323 | self.rn[index] = 0. 324 | index+=1 325 | 326 | # v 327 | if self.tagsX[index]>-1 or self.tagsY[index]>-1: 328 | self.rn[index] = 0. 329 | index+=1 330 | 331 | def generateBNQ(self): 332 | N = self.N 333 | rows = np.zeros(4*N*N, dtype=np.int) 334 | cols = np.zeros(4*N*N, dtype=np.int) 335 | vals = np.zeros(4*N*N, dtype=np.float) 336 | index = 0 337 | row_index = 0 338 | for j in xrange(N): 339 | for i in xrange(N): 340 | # u 341 | rows[index] = row_index 342 | cols[index] = j*N+i 343 | if self.tagsX[row_index]==-1 and self.tagsY[row_index]==-1: 344 | vals[index] = -1. 345 | else: 346 | vals[index] = 0. 347 | index+=1 348 | 349 | rows[index] = row_index 350 | cols[index] = j*N+i+1 if i