def mk_case(override): pspace = np.linspace(0, 2*np.pi, 4) rspace = np.linspace(0, 1, 3) domain, refgeom = mesh.rectilinear([rspace, pspace], periodic=(1,)) r, ang = refgeom geom = fn.asarray(( (1 + 10 * r) * fn.cos(ang), (1 + 10 * r) * fn.sin(ang), )) case = cases.airfoil(mesh=(domain, refgeom, geom), lift=False, amax=10, rmax=10, piola=True) case.precompute(force=override) return case
def mk_mesh(nang, nrad, rmin, rmax): aspace = np.linspace(0, 2 * np.pi, nang + 1) rspace = np.linspace(0, 1, nrad + 1) domain, refgeom = mesh.rectilinear([rspace, aspace], periodic=(1, )) rad, theta = refgeom K = 5 rad = (fn.exp(K * rad) - 1) / (np.exp(K) - 1) x = (rad * (rmax - rmin) + rmin) * fn.cos(theta) y = (rad * (rmax - rmin) + rmin) * fn.sin(theta) geom = fn.asarray([x, y]) return domain, refgeom, geom
def mk_mesh(nelems, radius, fname='NACA0015', cylrot=0.0): fname = path.join(path.dirname(__file__), f'../data/{fname}.cpts') cpts = np.loadtxt(fname) - (0.5, 0.0) pspace = np.linspace(0, 2 * np.pi, cpts.shape[0] + 1) rspace = np.linspace(0, 1, nelems + 1) domain, refgeom = mesh.rectilinear([rspace, pspace], periodic=(1, )) basis = domain.basis('spline', degree=3) angle = np.linspace(0, 2 * np.pi, cpts.shape[0], endpoint=False) - cylrot angle = np.hstack([[angle[-1]], angle[:-1]]) upts = radius * np.vstack([np.cos(angle), np.sin(angle)]).T interp = np.linspace(0, 1, nelems + 3)**3 cc = np.vstack([(1 - i) * cpts + i * upts for i in interp]) geom = fn.asarray([basis.dot(cc[:, 0]), basis.dot(cc[:, 1])]) return domain, refgeom, geom
def __init__(self, refine=1, degree=3, nel_up=None, nel_length=None, stabilize=True): if nel_up is None: nel_up = int(10 * refine) if nel_length is None: nel_length = int(100 * refine) domain, geom = mesh.multipatch( patches=[[[0, 1], [3, 4]], [[3, 4], [6, 7]], [[2, 3], [5, 6]]], nelems={ (0, 1): nel_up, (3, 4): nel_up, (6, 7): nel_up, (2, 5): nel_length, (3, 6): nel_length, (4, 7): nel_length, (0, 3): nel_up, (1, 4): nel_up, (2, 3): nel_up, (5, 6): nel_up, }, patchverts=[[-1, 0], [-1, 1], [0, -1], [0, 0], [0, 1], [1, -1], [1, 0], [1, 1]], ) NutilsCase.__init__(self, 'Backward-facing step channel', domain, geom, geom) NU = 1 / self.parameters.add('viscosity', 20, 50) L = self.parameters.add('length', 9, 12, 10) H = self.parameters.add('height', 0.3, 2, 1) V = self.parameters.add('velocity', 0.5, 1.2, 1) # Bases bases = [ domain.basis('spline', degree=(degree, degree - 1)), # vx domain.basis('spline', degree=(degree - 1, degree)), # vy domain.basis('spline', degree=degree - 1), # pressure ] if stabilize: bases.append([0] * 4) basis_lens = [len(b) for b in bases] vxbasis, vybasis, pbasis, *__ = fn.chain(bases) vbasis = vxbasis[:, _] * (1, 0) + vybasis[:, _] * (0, 1) self.bases.add('v', vbasis, length=sum(basis_lens[:2])) self.bases.add('p', pbasis, length=basis_lens[2]) self.extra_dofs = 4 if stabilize else 0 x, y = geom hx = fn.piecewise(x, (0, ), 0, x) hy = fn.piecewise(y, (0, ), y, 0) self.integrals['geometry'] = Affine( 1.0, geom, (L - 1), fn.asarray((hx, 0)), (H - 1), fn.asarray((0, hy)), ) self.constrain('v', 'patch0-bottom', 'patch0-top', 'patch0-left', 'patch1-top', 'patch2-bottom', 'patch2-left') vgrad = vbasis.grad(geom) # Lifting function profile = fn.max(0, y * (1 - y) * 4)[_] * (1, 0) self.integrals['lift'] = Affine(V, self.project_lift(profile, 'v')) # Characteristic functions cp0, cp1, cp2 = [characteristic(domain, (i, )) for i in range(3)] cp12 = cp1 + cp2 # Stokes divergence term self.integrals['divergence'] = AffineIntegral( -(H - 1), fn.outer(vgrad[:, 0, 0], pbasis) * cp2, -(L - 1), fn.outer(vgrad[:, 1, 1], pbasis) * cp12, -1, fn.outer(vbasis.div(geom), pbasis), ) # Stokes laplacian term self.integrals['laplacian'] = AffineIntegral( NU, fn.outer(vgrad).sum([-1, -2]) * cp0, NU / L, fn.outer(vgrad[:, :, 0]).sum(-1) * cp1, NU * L, fn.outer(vgrad[:, :, 1]).sum(-1) * cp1, NU * H / L, fn.outer(vgrad[:, :, 0]).sum(-1) * cp2, NU * L / H, fn.outer(vgrad[:, :, 1]).sum(-1) * cp2, ) # Navier-stokes convective term args = ('ijk', 'wuv') kwargs = {'x': geom, 'w': vbasis, 'u': vbasis, 'v': vbasis} self.integrals['convection'] = AffineIntegral( H, NutilsDelayedIntegrand('c w_ia u_j0 v_ka,0', *args, **kwargs, c=cp2), L, NutilsDelayedIntegrand('c w_ia u_j1 v_ka,1', *args, **kwargs, c=cp12), 1, NutilsDelayedIntegrand('c w_ia u_jb v_ka,b', *args, **kwargs, c=cp0), 1, NutilsDelayedIntegrand('c w_ia u_j0 v_ka,0', *args, **kwargs, c=cp1), ) # Norms self.integrals['v-h1s'] = self.integrals['laplacian'] / NU self.integrals['v-l2'] = AffineIntegral( 1, fn.outer(vbasis).sum(-1) * cp0, L, fn.outer(vbasis).sum(-1) * cp1, L * H, fn.outer(vbasis).sum(-1) * cp2, ) self.integrals['p-l2'] = AffineIntegral( 1, fn.outer(pbasis) * cp0, L, fn.outer(pbasis) * cp1, L * H, fn.outer(pbasis) * cp2, ) if not stabilize: self.verify return root = self.ndofs - self.extra_dofs terms = [] points = [(0, (0, 0)), (nel_up - 1, (0, 1))] eqn = vbasis.laplace(geom)[:, 0, _] colloc = collocate(domain, eqn, points, root, self.ndofs) terms.extend([NU, (colloc + colloc.T)]) eqn = -pbasis.grad(geom)[:, 0, _] colloc = collocate(domain, eqn, points, root, self.ndofs) terms.extend([1, colloc + colloc.T]) points = [(nel_up**2 + nel_up * nel_length, (0, 0))] eqn = vbasis[:, 0].grad(geom).grad(geom) colloc = collocate(domain, eqn[:, 0, 0, _], points, root + 2, self.ndofs) terms.extend([NU / L**2, colloc.T]) colloc = collocate(domain, eqn[:, 1, 1, _], points, root + 2, self.ndofs) terms.extend([NU / H**2, colloc]) eqn = -pbasis.grad(geom)[:, 0, _] colloc = collocate(domain, -pbasis.grad(geom)[:, 0, _], points, root + 2, self.ndofs) terms.extend([1 / L, colloc]) points = [(nel_up * (nel_up - 1), (1, 0))] colloc = collocate(domain, vbasis.laplace(geom)[:, 0, _], points, root + 3, self.ndofs) terms.extend([NU, colloc]) colloc = collocate(domain, -pbasis.grad(geom)[:, 0, _], points, root + 3, self.ndofs) terms.extend([1, colloc]) self.integrals['stab-lhs'] = AffineIntegral(*terms) self.verify()
def rotmat(angle): return fn.asarray([ [fn.cos(angle), -fn.sin(angle)], [fn.sin(angle), fn.cos(angle)], ])
def geometry(mu, L, H, refgeom): x, y = refgeom hx = fn.piecewise(x, (0, ), 0, x) hy = fn.piecewise(y, (0, ), y, 0) return (refgeom + (L - 1)(mu) * fn.asarray( (hx, 0)) + (H - 1)(mu) * fn.asarray((0, hy)))
def __init__(self, refine=1, degree=4, nel=None): if nel is None: nel = int(10 * refine) pts = np.linspace(0, 1, nel + 1) domain, geom = mesh.rectilinear([pts, pts]) NutilsCase.__init__(self, 'Cavity flow', domain, geom, geom) bases = [ domain.basis('spline', degree=(degree, degree - 1)), # vx domain.basis('spline', degree=(degree - 1, degree)), # vy domain.basis('spline', degree=degree - 1), # pressure [1], # lagrange multiplier [0] * 4, # stabilization terms ] basis_lens = [len(b) for b in bases] vxbasis, vybasis, pbasis, lbasis, __ = fn.chain(bases) vbasis = vxbasis[:, _] * (1, 0) + vybasis[:, _] * (0, 1) self.bases.add('v', vbasis, length=sum(basis_lens[:2])) self.bases.add('p', pbasis, length=basis_lens[2]) self.extra_dofs = 5 self.constrain('v', 'left', 'top', 'bottom', 'right') self.integrals['lift'] = Affine(1, np.zeros(vbasis.shape[0])) self.integrals['geometry'] = Affine(1, geom) x, y = geom f = 4 * (x - x**2)**2 g = 4 * (y - y**2)**2 d1f = f.grad(geom)[0] d1g = g.grad(geom)[1] velocity = fn.asarray((f * d1g, -d1f * g)) pressure = d1f * d1g total = domain.integrate(pressure * fn.J(geom), ischeme='gauss9') pressure -= total / domain.volume(geometry=geom) force = pressure.grad(geom) - velocity.laplace(geom) self._exact_solutions = {'v': velocity, 'p': pressure} self.integrals['forcing'] = AffineIntegral(1, (vbasis * force[_, :]).sum(-1)) self.integrals['divergence'] = AffineIntegral( -1, fn.outer(vbasis.div(geom), pbasis)) self.integrals['laplacian'] = AffineIntegral( 1, fn.outer(vbasis.grad(geom)).sum((-1, -2))) self.integrals['v-h1s'] = AffineIntegral( 1, fn.outer(vbasis.grad(geom)).sum([-1, -2])) self.integrals['p-l2'] = AffineIntegral(1, fn.outer(pbasis)) root = self.ndofs - self.extra_dofs points = [(0, (0, 0)), (nel - 1, (0, 1)), (nel * (nel - 1), (1, 0)), (nel**2 - 1, (1, 1))] eqn = (pbasis.grad(geom) - vbasis.laplace(geom))[:, 0, _] colloc = collocate(domain, eqn, points, root + 1, self.ndofs) self.integrals['stab-lhs'] = AffineIntegral(1, colloc, 1, fn.outer(lbasis, pbasis)) self.integrals['stab-rhs'] = AffineIntegral( 1, collocate(domain, force[0, _], points, root + 1, self.ndofs))
def __init__(self, nelems=10, piola=False, degree=2): pts = np.linspace(0, 1, nelems + 1) domain, geom = mesh.rectilinear([pts, pts]) NutilsCase.__init__(self, 'Abdulahque Manufactured Solution', domain, geom) RE = 1 / self.parameters.add('re', 100.0, 150.0) T = self.parameters.add('time', 0.0, 10.0) # Add bases and construct a lift function vbasis, pbasis = mk_bases(self, piola, degree) self.constrain('v', 'bottom') # self.constrain('v', 'top') # self.constrain('v', 'left') # self.constrain('v', 'right') self.lift += 1, np.zeros(len(vbasis)) self['divergence'] -= 1, fn.outer(vbasis.div(geom), pbasis) self['divergence'].freeze(lift=(1, )) self['laplacian'] += RE, fn.outer(vbasis.grad(geom)).sum((-1, -2)) self['convection'] += 1, NutilsDelayedIntegrand('w_ia u_jb v_ka,b', 'ijk', 'wuv', x=geom, w=vbasis, u=vbasis, v=vbasis) self['v-h1s'] += 1, fn.outer(vbasis.grad(geom)).sum((-1, -2)) self['v-l2'] += 1, fn.outer(vbasis).sum((-1, )) self['p-l2'] += 1, fn.outer(pbasis) # Body force x, y = geom h = T h1 = 1 f = 4 * (x - x**2)**2 f1 = f.grad(geom)[0] f2 = f1.grad(geom)[0] f3 = f2.grad(geom)[0] g = 4 * (y - y**2)**2 g1 = g.grad(geom)[1] g2 = g1.grad(geom)[1] g3 = g2.grad(geom)[1] # Body force self['forcing'] += h**2, fn.matmat( vbasis, fn.asarray([ (g1**2 - g * g2) * f * f1, (f1**2 - f * f2) * g * g1, ])) self['forcing'] += RE * h, fn.matmat( vbasis, fn.asarray([-f * g3, f3 * g + 2 * f1 * g2])) self['forcing'] += h1, fn.matmat(vbasis, fn.asarray([f * g1, -f1 * g])) # Neumann conditions mx = fn.asarray([[f1 * g1, f * g2], [-f2 * g, -f1 * g1]]) hh = fn.matmat(mx, geom.normal()) - f1 * g1 * geom.normal() self['forcing'] += RE * h, NutilsArrayIntegrand(fn.matmat( vbasis, hh)).prop(domain=domain.boundary['left'] | domain.boundary['right'] | domain.boundary['top'])
def __init__(self, refine=1, degree=3, nel_up=None, nel_length=None, nel_up_mid=None, nel_length_out=None, stabilize=True, override=True): if nel_up is None: nel_up = int(50 * refine) if nel_length is None: nel_length = int(50 * refine) if nel_up_mid is None: nel_up_mid = nel_up // 5 if nel_length_out is None: nel_length_out = 2 * nel_length // 5 domain, geom = mesh.multipatch( patches=[[[0,1],[4,5]], [[1,2],[5,6]], [[2,3],[6,7]], [[5,6],[8,9]]], nelems={ (0,1): nel_up, (4,5): nel_up, (2,3): nel_up, (6,7): nel_up, (1,2): nel_up_mid, (5,6): nel_up_mid, (8,9): nel_up_mid, (0,4): nel_length, (1,5): nel_length, (2,6): nel_length, (3,7): nel_length, (5,8): nel_length_out, (6,9): nel_length_out, }, patchverts=[ [-5,0], [-5,1], [-5,2], [-5,3], [0,0], [0,1], [0,2], [0,3], [2,1], [2,2], ] ) NutilsCase.__init__(self, 'T-shape channel', domain, geom, geom) NU = 1 / self.parameters.add('viscosity', 20, 50) H = self.parameters.add('height', 1, 5) V = self.parameters.add('velocity', 1, 5) bases = [ domain.basis('spline', degree=(degree, degree-1)), # vx domain.basis('spline', degree=(degree-1, degree)), # vy domain.basis('spline', degree=degree-1) # pressure ] if stabilize: bases.append([0] * 4) basis_lens = [len(b) for b in bases] vxbasis, vybasis, pbasis, *__ = fn.chain(bases) vbasis = vxbasis[:,_] * (1,0) + vybasis[:,_] * (0,1) self.bases.add('v', vbasis, length=sum(basis_lens[:2])) self.bases.add('p', pbasis, length=basis_lens[2]) self.extra_dofs = 4 if stabilize else 0 x, y = geom hy = fn.piecewise(y, (1,2), y-1, 0, y-2) self.integrals['geometry'] = Affine(1, geom, H - 1, fn.asarray((0, hy))) self.constrain( 'v', 'patch0-bottom', 'patch0-left', 'patch0-right', 'patch1-left', 'patch2-left', 'patch2-top', 'patch2-right', 'patch3-bottom', 'patch3-top', ) vgrad = vbasis.grad(geom) # Lifting function profile = fn.max(0, y/3 * (1-y/3) * (1-x))[_] * (1, 0) self.integrals['lift'] = Affine(V, self.project_lift(profile, 'v')) # Characteristic functions cp0, cp1, cp2, cp3 = [characteristic(domain, (i,)) for i in range(4)] cp02 = cp0 + cp2 cp13 = cp1 + cp3 # Stokes divergence term self.integrals['divergence'] = AffineIntegral( -(H-1), fn.outer(vgrad[:,0,0], pbasis) * cp02, -1, fn.outer(vbasis.div(geom), pbasis), ) # Stokes laplacian term self.integrals['laplacian'] = AffineIntegral( NU, fn.outer(vgrad).sum([-1,-2]) * cp13, NU*H, fn.outer(vgrad[:,:,0]).sum(-1) * cp02, NU/H, fn.outer(vgrad[:,:,1]).sum(-1) * cp02, ) # Navier-Stokes convective term args = ('ijk', 'wuv') kwargs = {'x': geom, 'w': vbasis, 'u': vbasis, 'v': vbasis} self.integrals['convection'] = AffineIntegral( H, NutilsDelayedIntegrand('c w_ia u_j0 v_ka,0', *args, **kwargs, c=cp02), 1, NutilsDelayedIntegrand('c w_ia u_j1 v_ka,1', *args, **kwargs, c=cp02), 1, NutilsDelayedIntegrand('c w_ia u_jb v_ka,b', *args, **kwargs, c=cp13), ) # Norms self.integrals['v-h1s'] = self.integrals['laplacian'] / NU self.integrals['v-l2'] = AffineIntegral( H, fn.outer(vbasis).sum(-1) * cp02, 1, fn.outer(vbasis).sum(-1) * cp13, ) self.integrals['p-l2'] = AffineIntegral( H, fn.outer(pbasis) * cp02, 1, fn.outer(pbasis) * cp13, ) if not stabilize: self.verify() return root = self.ndofs - self.extra_dofs points = [ (0, (0, 0)), (nel_up*(nel_length-1), (1, 0)), (nel_up*nel_length + nel_up_mid*nel_length + nel_up - 1, (0, 1)), (nel_up*nel_length*2 + nel_up_mid*nel_length - 1, (1, 1)) ] terms = [] eqn = vbasis[:,0].grad(geom).grad(geom) colloc = collocate(domain, eqn[:,0,0,_], points, root, self.ndofs) terms.extend([NU, (colloc + colloc.T)]) colloc = collocate(domain, eqn[:,1,1,_], points, root, self.ndofs) terms.extend([NU/H**2, (colloc + colloc.T)]) eqn = -pbasis.grad(geom)[:,0,_] colloc = collocate(domain, eqn, points, root, self.ndofs) terms.extend([1, colloc + colloc.T]) self.integrals['stab-lhs'] = AffineIntegral(*terms) self.verify()
def __init__(self, refine=1, degree=3, nel=None, power=3): if nel is None: nel = int(10 * refine) pts = np.linspace(0, 1, nel + 1) domain, geom = mesh.rectilinear([pts, pts]) x, y = geom NutilsCase.__init__(self, 'Exact divergence-conforming flow', domain, geom, geom) w = self.parameters.add('w', 1, 2) h = self.parameters.add('h', 1, 2) bases = [ domain.basis('spline', degree=(degree, degree-1)), # vx domain.basis('spline', degree=(degree-1, degree)), # vy domain.basis('spline', degree=degree-1), # pressure [1], # lagrange multiplier [0] * 4, # stabilization terms ] basis_lens = [len(b) for b in bases] vxbasis, vybasis, pbasis, lbasis, __ = fn.chain(bases) vbasis = vxbasis[:,_] * (1,0) + vybasis[:,_] * (0,1) self.bases.add('v', vbasis, length=sum(basis_lens[:2])) self.bases.add('p', pbasis, length=basis_lens[2]) self.extra_dofs = 5 self.integrals['geometry'] = Affine( 1, geom, w-1, fn.asarray((x,0)), h-1, fn.asarray((0,y)), ) self.constrain('v', 'left', 'top', 'bottom', 'right') r = power self.power = power # Exact solution f = x**r g = y**r f1 = r * x**(r-1) g1 = r * y**(r-1) g2 = r*(r-1) * y**(r-2) f3 = r*(r-1)*(r-2) * x**(r-3) g3 = r*(r-1)*(r-2) * y**(r-3) self._exact_solutions = {'v': fn.asarray((f*g1, -f1*g)), 'p': f1*g1 - 1} # Awkward way of computing a solenoidal lift mdom, t = mesh.rectilinear([pts]) hbasis = mdom.basis('spline', degree=degree) hcoeffs = mdom.project(t[0]**r, onto=hbasis, geometry=t, ischeme='gauss9') projtderiv = hbasis.dot(hcoeffs).grad(t)[0] zbasis = mdom.basis('spline', degree=degree-1) zcoeffs = mdom.project(projtderiv, onto=zbasis, geometry=t, ischeme='gauss9') q = np.hstack([ np.outer(hcoeffs, zcoeffs).flatten(), - np.outer(zcoeffs, hcoeffs).flatten(), np.zeros((sum(basis_lens) - len(hcoeffs) * len(zcoeffs) * 2)) ]) self.integrals['lift'] = Affine(w**(r-1) * h**(r-1), q) self.integrals['forcing'] = AffineIntegral( w**(r-2) * h**(r+2), vybasis * (f3 * g)[_], w**r * h**r, 2*vybasis * (f1*g2)[_], w**(r+2) * h**(r-2), -vxbasis * (f*g3)[_], ) vx_x = vxbasis.grad(geom)[:,0] vx_xx = vx_x.grad(geom)[:,0] vx_y = vxbasis.grad(geom)[:,1] vx_yy = vx_y.grad(geom)[:,1] vy_x = vybasis.grad(geom)[:,0] vy_y = vybasis.grad(geom)[:,1] p_x = pbasis.grad(geom)[:,0] self.integrals['laplacian'] = AffineIntegral( h * w, fn.outer(vx_x, vx_x), h**3 / w, fn.outer(vy_x, vy_x), w**3 / h, fn.outer(vx_y, vx_y), w * h, fn.outer(vy_y, vy_y), ) self.integrals['divergence'] = AffineIntegral( h * w, (fn.outer(vx_x, pbasis) + fn.outer(vy_y, pbasis)) ) self['v-h1s'] = AffineIntegral(self.integrals['laplacian']) self['p-l2'] = AffineIntegral(h * w, fn.outer(pbasis, pbasis)) root = self.ndofs - self.extra_dofs points = [(0, (0, 0)), (nel-1, (0, 1)), (nel*(nel-1), (1, 0)), (nel**2-1, (1, 1))] ca, cb, cc = [ collocate(domain, eqn[:,_], points, root+1, self.ndofs) for eqn in [p_x, -vx_xx, -vx_yy] ] self.integrals['stab-lhs'] = AffineIntegral( 1/w, ca, 1/w, cb, w/h**2, cc, 1, fn.outer(lbasis, pbasis), w**3 * h**(r-3), collocate(domain, -f*g3[_], points, root+1, self.ndofs), ) self.integrals['v-trf'] = Affine( w, fn.asarray([[1,0], [0,0]]), h, fn.asarray([[0,0], [0,1]]), )
def exact(self, mu, field): scale = mu['w']**(self.power-1) * mu['h']**(self.power-1) retval = scale * self._exact_solutions[field] if field == 'v': return fn.matmat(fn.asarray([[mu['w'], 0], [0, mu['h']]]), retval) return retval
def main( nelems: 'number of elements' = 12, viscosity: 'fluid viscosity' = 1e-3, density: 'fluid density' = 1, degree: 'polynomial degree' = 2, warp: 'warp domain (downward bend)' = False, tol: 'solver tolerance' = 1e-5, maxiter: 'maximum number if iterations, 0 for unlimited' = 0, withplots: 'create plots' = True, ): Re = density / viscosity # based on unit length and velocity log.user( 'reynolds number: {:.1f}'.format(Re) ) # construct mesh verts = numpy.linspace( 0, 1, nelems+1 ) domain, geom = mesh.rectilinear( [verts,verts] ) # construct bases vxbasis, vybasis, pbasis, lbasis = function.chain([ domain.basis( 'spline', degree=(degree+1,degree), removedofs=((0,-1),None) ), domain.basis( 'spline', degree=(degree,degree+1), removedofs=(None,(0,-1)) ), domain.basis( 'spline', degree=degree ), [1], # lagrange multiplier ]) if not warp: vbasis = function.stack( [ vxbasis, vybasis ], axis=1 ) else: gridgeom = geom xi, eta = gridgeom geom = (eta+2) * function.rotmat(xi*.4)[:,1] - (0,2) # slight downward bend J = geom.grad( gridgeom ) detJ = function.determinant( J ) vbasis = ( vxbasis[:,_] * J[:,0] + vybasis[:,_] * J[:,1] ) / detJ # piola transform pbasis /= detJ stressbasis = (2*viscosity) * vbasis.symgrad(geom) - (pbasis)[:,_,_] * function.eye( domain.ndims ) # construct matrices A = function.outer( vbasis.grad(geom), stressbasis ).sum([2,3]) \ + function.outer( pbasis, vbasis.div(geom)+lbasis ) \ + function.outer( lbasis, pbasis ) Ad = function.outer( vbasis.div(geom) ) stokesmat, divmat = domain.integrate( [ A, Ad ], geometry=geom, ischeme='gauss9' ) # define boundary conditions normal = geom.normal() utop = function.asarray([ normal[1], -normal[0] ]) h = domain.boundary.elem_eval( 1, geometry=geom, ischeme='gauss9', asfunction=True ) nietzsche = (2*viscosity) * ( ((degree+1)*2.5/h) * vbasis - vbasis.symgrad(geom).dotnorm(geom) ) stokesmat += domain.boundary.integrate( function.outer( nietzsche, vbasis ).sum(-1), geometry=geom, ischeme='gauss9' ) rhs = domain.boundary['top'].integrate( ( nietzsche * utop ).sum(-1), geometry=geom, ischeme='gauss9' ) # prepare plotting makeplots = MakePlots( domain, geom ) if withplots else lambda *args: None # start picard iterations lhs = stokesmat.solve( rhs, tol=tol, solver='cg', precon='spilu' ) for iiter in log.count( 'picard' ): log.info( 'velocity divergence:', divmat.matvec(lhs).dot(lhs) ) makeplots( vbasis.dot(lhs), pbasis.dot(lhs) ) ugradu = ( vbasis.grad(geom) * vbasis.dot(lhs) ).sum(-1) convection = density * function.outer( vbasis, ugradu ).sum(-1) matrix = stokesmat + domain.integrate( convection, ischeme='gauss9', geometry=geom ) lhs, info = matrix.solve( rhs, lhs0=lhs, tol=tol, info=True, precon='spilu', restart=999 ) if iiter == maxiter-1 or info.niter == 0: break return rhs, lhs