def example(): verts = 0,1,3,4,10 domain, geom = mesh.rectilinear( [ verts ] ) basis = BSpline( degree=2, knotvalues=verts, knotmultiplicities=[1,2,3,1,1] ).build(domain) x, y = domain.elem_eval( [ geom[0], basis ], ischeme='bezier9' ) with plot.PyPlot( '1D' ) as plt: plt.plot( x, y, '-' ) verts = numpy.arange(10) domain, geom = mesh.rectilinear( [ verts ] ) basis = Mod( Mod( Spline( degree=2, rmlast=True ), 2 ), -3 ).build(domain) x, y = domain.elem_eval( [ geom[0], basis ], ischeme='bezier9' ) with plot.PyPlot( '1D' ) as plt: plt.plot( x, y, '-' ) verts = numpy.arange(10) domain, geom = mesh.rectilinear( [ verts ] ) basis = Mod( Mod( Spline( degree=2, periodic=True ), 2 ), 4 ).build(domain) x, y = domain.elem_eval( [ geom[0], basis ], ischeme='bezier9' ) with plot.PyPlot( '1D' ) as plt: plt.plot( x, y, '-' ) domain, geom = mesh.rectilinear( [ numpy.arange(5) ] * 2 ) basis = ( Spline( degree=1, rmfirst=True ) * Mod( Spline( degree=2, periodic=True ), 2 ) ).build(domain) x, y = domain.elem_eval( [ geom, basis ], ischeme='bezier5' ) with plot.PyPlot( '2D' ) as plt: for i, yi in enumerate( y.T ): plt.subplot( 4, 4, i+1 ) plt.mesh( x, yi ) plt.gca().set_axis_off()
def test_discontinuous(self): pdomain, pgeom = mesh.rectilinear([3], periodic=[0]) rdomain, rgeom = mesh.rectilinear([3]) pbasis = pdomain.basis('spline', degree=2, knotmultiplicities=[[3,1,2,3]]) rbasis = rdomain.basis('spline', degree=2, knotmultiplicities=[[1,1,2,1]]) psampled = pdomain.sample('gauss', 2).eval(pbasis) rsampled = rdomain.sample('gauss', 2).eval(rbasis) self.assertAllAlmostEqual(psampled, rsampled)
def setUp(self): super().setUp() if not self.product: self.domain, self.geom = mesh.rectilinear([2,3]) else: domain1, geom1 = mesh.rectilinear([2]) domain2, geom2 = mesh.rectilinear([3]) self.domain = domain1 * domain2 self.geom = function.concatenate(function.bifurcate(geom1, geom2), axis=0)
def setUp(self): super().setUp() domain, geom = mesh.rectilinear([numpy.linspace(0, 1, 9)] * 2) ubasis = domain.basis('std', degree=2) if self.vector: u = ubasis.vector(2).dot( function.Argument('dofs', [len(ubasis) * 2])) else: u = (ubasis[:, numpy.newaxis] * function.Argument('dofs', [len(ubasis), 2])).sum(0) Geom = geom * [1.1, 1] + u self.cons = solver.optimize('dofs', domain.boundary['left,right'].integral( (u**2).sum(0), degree=4), droptol=1e-15) self.boolcons = ~numpy.isnan(self.cons) strain = .5 * (function.outer(Geom.grad(geom), axis=1).sum(0) - function.eye(2)) self.energy = domain.integral( ((strain**2).sum([0, 1]) + 20 * (function.determinant(Geom.grad(geom)) - 1)**2) * function.J(geom), degree=6) self.residual = self.energy.derivative('dofs') self.tol = 1e-10
def setUp(self): super().setUp() verts = numpy.linspace(0, 1, self.nelems + 1) self.domain, self.geom = mesh.rectilinear( [verts], periodic=(0, ) if self.periodic else ()) self.basis = self.domain.basis(self.btype, degree=self.degree) if self.btype != 'spline' \ else self.domain.basis(self.btype, degree=self.degree, continuity=self.continuity)
def test_sparsity(self): topo, geom = mesh.rectilinear([6] * self.ndim) topo = topo.refined_by( set( map( topo.transforms.index, itertools.chain(topo[1:3].transforms, topo[-2:].transforms)))) ns = function.Namespace() ns.x = geom ns.tbasis = topo.basis('th-spline', degree=2, truncation_tolerance=1e-14) ns.tnotol = topo.basis('th-spline', degree=2, truncation_tolerance=0) ns.hbasis = topo.basis('h-spline', degree=2) tA, tA_tol, hA = topo.sample('gauss', 5).integrate_sparse([ ns.eval_ij('tbasis_i,k tbasis_j,k'), ns.eval_ij('tnotol_i,k tnotol_j,k'), ns.eval_ij('hbasis_i,k hbasis_j,k') ]) tA_nnz, tA_tol_nnz, hA_nnz = self.vals[self.ndim] self.assertEqual(len(sparse.prune(sparse.dedup(tA))), tA_nnz) self.assertEqual(len(sparse.prune(sparse.dedup(tA_tol))), tA_tol_nnz) self.assertEqual(len(sparse.prune(sparse.dedup(hA))), hA_nnz)
def setUp(self): super().setUp() domain, geom = mesh.rectilinear([numpy.linspace(0,1,9)] * 2) gauss = domain.sample('gauss', 5) uin = geom[1] * (1-geom[1]) dx = function.J(geom, 2) ubasis = domain.basis('std', degree=2) pbasis = domain.basis('std', degree=1) if self.single: ubasis, pbasis = function.chain([ubasis.vector(2), pbasis]) dofs = function.Argument('dofs', [len(ubasis)]) u = ubasis.dot(dofs) p = pbasis.dot(dofs) dofs = 'dofs' ures = gauss.integral((self.viscosity * (ubasis.grad(geom) * (u.grad(geom) + u.grad(geom).T)).sum([-1,-2]) - ubasis.div(geom) * p) * dx) dres = gauss.integral((ubasis * (u.grad(geom) * u).sum(-1)).sum(-1) * dx) else: u = (ubasis[:,numpy.newaxis] * function.Argument('dofs', [len(ubasis), 2])).sum(0) p = (pbasis * function.Argument('pdofs', [len(pbasis)])).sum(0) dofs = 'dofs', 'pdofs' ures = gauss.integral((self.viscosity * (ubasis[:,numpy.newaxis].grad(geom) * (u.grad(geom) + u.grad(geom).T)).sum(-1) - ubasis.grad(geom) * p) * dx) dres = gauss.integral(ubasis[:,numpy.newaxis] * (u.grad(geom) * u).sum(-1) * dx) pres = gauss.integral((pbasis * u.div(geom)) * dx) cons = solver.optimize('dofs', domain.boundary['top,bottom'].integral((u**2).sum(), degree=4), droptol=1e-10) cons = solver.optimize('dofs', domain.boundary['left'].integral((u[0]-uin)**2 + u[1]**2, degree=4), droptol=1e-10, constrain=cons) self.cons = cons if self.single else {'dofs': cons} stokes = solver.solve_linear(dofs, residual=ures + pres if self.single else [ures, pres], constrain=self.cons) self.arguments = dict(dofs=stokes) if self.single else stokes self.residual = ures + dres + pres if self.single else [ures + dres, pres] inertia = gauss.integral(.5 * (u**2).sum(-1) * dx).derivative('dofs') self.inertia = inertia if self.single else [inertia, None] self.tol = 1e-10 self.dofs = dofs self.frozen = types.frozenarray if self.single else solver.argdict
def setUp(self): super().setUp() self.ns = function.Namespace() self.domain, self.ns.geom = mesh.rectilinear([2,2]) self.ns.ubasis = self.domain.basis('std', degree=1) self.ns.u = 'ubasis_n ?dofs_n' self.optimize = solver.optimize if not self.minimize else lambda *args, newtontol=0, **kwargs: solver.minimize(*args, **kwargs).solve(newtontol)
def test_nonlinear_diagonalshift(self): nelems = 10 domain, geom = mesh.rectilinear([nelems, 1]) geom *= [2 * numpy.pi / nelems, 1] ubasis = domain.basis('spline', degree=2).vector(2) u = ubasis.dot(function.Argument('dofs', [len(ubasis)])) Geom = [.5 * geom[0], geom[1] + function.cos(geom[0]) ] + u # compress by 50% and buckle cons = solver.minimize('dofs', domain.boundary['left,right'].integral( (u**2).sum(0), degree=4), droptol=1e-15).solve() strain = .5 * (function.outer(Geom.grad(geom), axis=1).sum(0) - function.eye(2)) energy = domain.integral( ((strain**2).sum([0, 1]) + 150 * (function.determinant(Geom.grad(geom)) - 1)**2) * function.J(geom), degree=6) nshift = 0 for iiter, (lhs, info) in enumerate( solver.minimize('dofs', energy, constrain=cons)): self.assertLess(iiter, 38) if info.shift: nshift += 1 if info.resnorm < self.tol: break self.assertEqual(nshift, 9)
def navierstokes(): domain, geom = mesh.rectilinear( [numpy.linspace(0,1,9)] * 2 ) ubasis, pbasis = function.chain([ domain.basis( 'std', degree=2 ).vector(2), domain.basis( 'std', degree=1 ), ]) dofs = function.DerivativeTarget( [len(ubasis)] ) u = ubasis.dot( dofs ) p = pbasis.dot( dofs ) viscosity = 1 inertia = model.Integral( (ubasis * u).sum(-1), domain=domain, geometry=geom, degree=5 ) stokesres = model.Integral( viscosity * ubasis['ni,j'] * (u['i,j']+u['j,i']) - ubasis['nk,k'] * p + pbasis['n'] * u['k,k'], domain=domain, geometry=geom, degree=5 ) residual = stokesres + model.Integral( ubasis['ni'] * u['i,j'] * u['j'], domain=domain, geometry=geom, degree=5 ) cons = domain.boundary['top,bottom'].project( [0,0], onto=ubasis, geometry=geom, ischeme='gauss2' ) \ | domain.boundary['left'].project( [geom[1]*(1-geom[1]),0], onto=ubasis, geometry=geom, ischeme='gauss2' ) lhs0 = model.solve_linear( dofs, residual=stokesres, constrain=cons ) for name in 'direct', 'newton', 'pseudotime': @unittest( name=name, raises=name=='direct' and model.ModelError) def res(): tol = 1e-10 if name == 'direct': lhs = model.solve_linear( dofs, residual=residual, constrain=cons ) elif name == 'newton': lhs = model.newton( dofs, residual=residual, lhs0=lhs0, freezedofs=cons.where ).solve( tol=tol, maxiter=2 ) else: lhs = model.pseudotime( dofs, residual=residual, lhs0=lhs0, freezedofs=cons.where, inertia=inertia, timestep=1 ).solve( tol=tol, maxiter=3 ) res = residual.replace( dofs, lhs ).eval() resnorm = numpy.linalg.norm( res[~cons.where] ) assert resnorm < tol
def main(viscosity=1.3e-3, density=1e3, pout=223e5, uw=-0.01, nelems=10): # viscosity = 1.3e-3 # density = 1e3 # pout = 223e5 # nelems = 10 # uw = -0.01 domain, geom = mesh.rectilinear([numpy.linspace(0, 1, nelems), numpy.linspace(1, 2, nelems), [0, 2 * numpy.pi]], periodic=[2]) domain = domain.withboundary(inner='bottom', outer='top') ns = function.Namespace() ns.y, ns.r, ns.θ = geom ns.x_i = '<r cos(θ), y, r sin(θ)>_i' ns.uybasis, ns.urbasis, ns.pbasis = function.chain([ domain.basis('std', degree=3, removedofs=((0,-1), None, None)), # remove normal component at y=0 and y=1 domain.basis('std', degree=3, removedofs=((0,-1), None, None)), # remove tangential component at y=0 (no slip) domain.basis('std', degree=2)]) ns.ubasis_ni = '<urbasis_n cos(θ), uybasis_n, urbasis_n sin(θ)>_i' ns.viscosity = viscosity ns.density = density ns.u_i = 'ubasis_ni ?lhs_n' ns.p = 'pbasis_n ?lhs_n' ns.sigma_ij = 'viscosity (u_i,j + u_j,i) - p δ_ij' ns.pout = pout ns.uw = uw ns.uw_i = 'uw <cos(phi), 0, sin(phi)>_i' ns.tout_i = '-pout n_i' ns.uw_i = 'uw n_i' # uniform outflow res = domain.integral('(viscosity ubasis_ni,j u_i,j - p ubasis_ni,i + pbasis_n u_k,k) d:x' @ ns, degree=6) # res -= domain[1].boundary['inner'].integral('ubasis_ni tout_i d:x' @ ns, degree=6) sqr = domain.boundary['inner'].integral('(u_i - uw_i) (u_i - uw_i) d:x' @ ns, degree=6) # sqr = domain.boundary['outer'].integral('(u_i - uin_i) (u_i - uin_i) d:x' @ ns, degree=6) sqr -= domain.boundary['outer'].integral('(p - pout) (p - pout) d:x' @ ns, degree=6) cons = solver.optimize('lhs', sqr, droptol=1e-15) lhs = solver.solve_linear('lhs', res, constrain=cons) plottopo = domain[:, :, 0:].boundary['back'] bezier = plottopo.sample('bezier', 10) r, y, p, u = bezier.eval([ns.r, ns.y, ns.p, function.norm2(ns.u)], lhs=lhs) with export.mplfigure('pressure.png', dpi=800) as fig: ax = fig.add_subplot(111, title='pressure', aspect=1) ax.autoscale(enable=True, axis='both', tight=True) im = ax.tripcolor(r, y, bezier.tri, p, shading='gouraud', cmap='jet') ax.add_collection( collections.LineCollection(numpy.array([y, r]).T[bezier.hull], colors='k', linewidths=0.2, alpha=0.2)) fig.colorbar(im) uniform = plottopo.sample('uniform', 1) r_, y_, uv = uniform.eval([ns.r, ns.y, ns.u], lhs=lhs) with export.mplfigure('velocity.png', dpi=800) as fig: ax = fig.add_subplot(111, title='Velocity', aspect=1) ax.autoscale(enable=True, axis='both', tight=True) im = ax.tripcolor(r, y, bezier.tri, u, shading='gouraud', cmap='jet') ax.quiver(r_, y_, uv[:, 0], uv[:, 1], angles='xy', scale_units='xy') fig.colorbar(im)
def laplace(): domain, geom = mesh.rectilinear([8, 8]) basis = domain.basis('std', degree=1) cons = domain.boundary['left'].project(0, onto=basis, geometry=geom, ischeme='gauss2') dofs = function.DerivativeTarget([len(basis)]) u = basis.dot(dofs) residual = model.Integral( ( basis.grad(geom) * u.grad(geom) ).sum(-1), domain=domain, geometry=geom, degree=2 ) \ + model.Integral( basis, domain=domain.boundary['top'], geometry=geom, degree=2 ) for name in 'direct', 'newton': @unittest(name=name) def res(): if name == 'direct': lhs = model.solve_linear(dofs, residual=residual, constrain=cons) else: lhs = model.newton(dofs, residual=residual, lhs0=cons | 0, freezedofs=cons.where).solve(tol=1e-10, maxiter=0) res = residual.replace(dofs, lhs).eval() resnorm = numpy.linalg.norm(res[~cons.where]) assert resnorm < 1e-13
def test(self): for knotmultiplicities, ndofs in [([3,1,3], 4), ([3,2,1,3], 6)]: domain, geom = mesh.rectilinear([len(knotmultiplicities)-1], periodic=[0]) basis = domain.basis('spline', degree=3, knotmultiplicities=[knotmultiplicities]) self.assertEqual(len(basis), ndofs) self.assertContinuous(topo=domain, geom=geom, basis=basis, continuity=0) self.assertPartitionOfUnity(topo=domain, basis=basis)
def setUp(self): super().setUp() domain, geom = mesh.rectilinear([numpy.linspace(0, 1, 9)] * 2) ubasis, pbasis = function.chain([ domain.basis('std', degree=2).vector(2), domain.basis('std', degree=1), ]) dofs = function.Argument('dofs', [len(ubasis)]) u = ubasis.dot(dofs) p = pbasis.dot(dofs) viscosity = 1e-3 self.inertia = domain.integral((ubasis * u).sum(-1) * function.J(geom), degree=5) stokesres = domain.integral( (viscosity * (ubasis.grad(geom) * (u.grad(geom) + u.grad(geom).T)).sum([-1, -2]) - ubasis.div(geom) * p + pbasis * u.div(geom)) * function.J(geom), degree=5) self.residual = stokesres + domain.integral( (ubasis * (u.grad(geom) * u).sum(-1) * u).sum(-1) * function.J(geom), degree=5) self.cons = domain.boundary['top,bottom'].project([0,0], onto=ubasis, geometry=geom, ischeme='gauss4') \ | domain.boundary['left'].project([geom[1]*(1-geom[1]),0], onto=ubasis, geometry=geom, ischeme='gauss4') self.lhs0 = solver.solve_linear('dofs', residual=stokesres, constrain=self.cons) self.tol = 1e-10
def setUp(self): super().setUp() if self.ndims == 2: domain, geom = mesh.unitsquare(4, self.variant) nverts = 25 elif self.variant == 'tensor': structured, geom = mesh.rectilinear( [numpy.linspace(0, 1, 5 - i) for i in range(self.ndims)]) domain = topology.ConnectedTopology(structured.references, structured.transforms, structured.opposites, structured.connectivity) nverts = numpy.product([5 - i for i in range(self.ndims)]) elif self.variant == 'simplex': numpy.random.seed(0) nverts = 20 simplices = numeric.overlapping(numpy.arange(nverts), n=self.ndims + 1) coords = numpy.random.normal(size=(nverts, self.ndims)) root = transform.Identifier(self.ndims, 'test') transforms = transformseq.PlainTransforms( [(root, transform.Square((c[1:] - c[0]).T, c[0])) for c in coords[simplices]], self.ndims) domain = topology.SimplexTopology(simplices, transforms, transforms) geom = function.rootcoords(self.ndims) else: raise NotImplementedError self.domain = domain self.basis = domain.basis( self.btype) if self.btype == 'bubble' else domain.basis( self.btype, degree=self.degree) self.geom = geom self.nverts = nverts
def poisson_patch(bottom, right, top, left): from nutils import version if version != '3.0': raise ImportError('Outdated nutils version detected, only v3.0 supported. Upgrade by \"pip install --upgrade nutils\"') from nutils import mesh, function as fn from nutils import _, log # error test input if left.rational or right.rational or top.rational or bottom.rational: raise RuntimeError('poisson_patch not supported for rational splines') # these are given as a oriented loop, so make all run in positive parametric direction top.reverse() left.reverse() # in order to add spline surfaces, they need identical parametrization Curve.make_splines_identical(top, bottom) Curve.make_splines_identical(left, right) # create computational (nutils) mesh p1 = bottom.order(0) p2 = left.order(0) n1 = len(bottom) n2 = len(left) dim= left.dimension k1 = bottom.knots(0) k2 = left.knots(0) m1 = [bottom.order(0) - bottom.continuity(k) - 1 for k in k1] m2 = [left.order(0) - left.continuity(k) - 1 for k in k2] domain, geom = mesh.rectilinear([k1, k2]) basis = domain.basis('spline', [p1-1, p2-1], knotmultiplicities=[m1,m2]) # assemble system matrix grad = basis.grad(geom) outer = fn.outer(grad,grad) integrand = outer.sum(-1) matrix = domain.integrate(integrand, geometry=geom, ischeme='gauss'+str(max(p1,p2)+1)) # initialize variables controlpoints = np.zeros((n1,n2,dim)) rhs = np.zeros((n1*n2)) constraints = np.array([[np.nan]*n2]*n1) # treat all dimensions independently for d in range(dim): # add boundary conditions constraints[ 0, :] = left[ :,d] constraints[-1, :] = right[ :,d] constraints[ :, 0] = bottom[:,d] constraints[ :,-1] = top[ :,d] # solve system lhs = matrix.solve(rhs, constrain=np.ndarray.flatten(constraints), solver='cg', tol=state.controlpoint_absolute_tolerance) # wrap results into splipy datastructures controlpoints[:,:,d] = np.reshape(lhs, (n1,n2), order='C') return Surface(bottom.bases[0], left.bases[0], controlpoints, bottom.rational, raw=True)
def main(nelems: int, degree: int, reynolds: float): ''' Driven cavity benchmark problem using compatible spaces. .. arguments:: nelems [12] Number of elements along edge. degree [2] Polynomial degree for velocity; the pressure space is one degree less. reynolds [1000] Reynolds number, taking the domain size as characteristic length. ''' verts = numpy.linspace(0, 1, nelems + 1) domain, geom = mesh.rectilinear([verts, verts]) ns = function.Namespace() ns.x = geom ns.Re = reynolds ns.ubasis = function.vectorize([ domain.basis('spline', degree=(degree, degree - 1), removedofs=((0, -1), None)), domain.basis('spline', degree=(degree - 1, degree), removedofs=(None, (0, -1))) ]) ns.pbasis = domain.basis('spline', degree=degree - 1) ns.u_i = 'ubasis_ni ?u_n' ns.p = 'pbasis_n ?p_n' ns.stress_ij = '(d(u_i, x_j) + d(u_j, x_i)) / Re - p δ_ij' ns.uwall = domain.boundary.indicator('top'), 0 ns.N = 5 * degree * nelems # nitsche constant based on element size = 1/nelems ns.nitsche_ni = '(N ubasis_ni - (d(ubasis_ni, x_j) + d(ubasis_nj, x_i)) n(x_j)) / Re' ures = domain.integral('d(ubasis_ni, x_j) stress_ij d:x' @ ns, degree=2 * degree) ures += domain.boundary.integral( '(nitsche_ni (u_i - uwall_i) - ubasis_ni stress_ij n(x_j)) d:x' @ ns, degree=2 * degree) pres = domain.integral('pbasis_n (d(u_k, x_k) + ?lm) d:x' @ ns, degree=2 * degree) lres = domain.integral('p d:x' @ ns, degree=2 * degree) with treelog.context('stokes'): state0 = solver.solve_linear(['u', 'p', 'lm'], [ures, pres, lres]) postprocess(domain, ns, **state0) ures += domain.integral('ubasis_ni d(u_i, x_j) u_j d:x' @ ns, degree=3 * degree) with treelog.context('navierstokes'): state1 = solver.newton(('u', 'p', 'lm'), (ures, pres, lres), arguments=state0).solve(tol=1e-10) postprocess(domain, ns, **state1) return state0, state1
def __init__(self, refine=1, degree=3, nel=None): if nel is None: nel = int(10 * refine) xpts = np.linspace(0, 2, 2 * nel + 1) ypts = np.linspace(0, 1, nel + 1) domain, geom = mesh.rectilinear([xpts, ypts]) NutilsCase.__init__(self, 'Channel 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 [0] * 2, # stabilization terms ] 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 = 2 self.constrain('v', 'left', 'top', 'bottom') x, y = geom profile = (y * (1 - y))[_] * (1, 0) self.integrals['lift'] = Affine(1, self.project_lift(profile, 'v')) self.integrals['geometry'] = Affine(1, geom) self._exact_solutions = {'v': profile, 'p': 4 - 2 * x} 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)) self.integrals['convection'] = AffineIntegral( 1, NutilsDelayedIntegrand('w_ia u_jb v_ka,b', 'ijk', 'wuv', x=geom, w=vbasis, u=vbasis, v=vbasis)) points = [(0, (0, 0)), (nel - 1, (0, 1))] eqn = (vbasis.laplace(geom) - pbasis.grad(geom))[:, 0, _] self.integrals['stab-lhs'] = AffineIntegral( 1, collocate(domain, eqn, points, self.ndofs - self.extra_dofs, self.ndofs))
def setUp(self): super().setUp() domain, geom = mesh.rectilinear([8,8]) basis = domain.basis('std', degree=1) self.cons = domain.boundary['left'].project(0, onto=basis, geometry=geom, ischeme='gauss2') dofs = function.Argument('dofs', [len(basis)]) u = basis.dot(dofs) self.residual = domain.integral((basis.grad(geom) * u.grad(geom)).sum(-1), geometry=geom, degree=2) \ + domain.boundary['top'].integral(basis, geometry=geom, degree=2)
def setUp(self): super().setUp() self.domain, self.geom = mesh.rectilinear([max(1, self.nelems-n) for n in range(self.ndims)], periodic=[0] if self.periodic else []) for iref in range(self.nrefine): self.domain = self.domain.refined_by([len(self.domain)-1]) if self.boundary: self.domain = self.domain.boundary[self.boundary] self.basis = self.domain.basis(self.btype, degree=self.degree) self.gauss = 'gauss{}'.format(2*self.degree)
def main( nelems: 'number of elements' = 20, degree: 'polynomial degree' = 1, timescale: 'time scale (timestep=timescale/nelems)' = .5, tol: 'solver tolerance' = 1e-5, ndims: 'spatial dimension' = 1, endtime: 'end time, 0 for no end time' = 0, withplots: 'create plots' = True, ): # construct mesh domain, geom = mesh.rectilinear([numpy.linspace(0, 1, nelems + 1)] * ndims, periodic=range(ndims)) basis = domain.basis('discont', degree=degree) # construct initial condition (centered gaussian) u = function.exp(-(((geom - .5) * 5)**2).sum(-1)) lhs = domain.project(u, onto=basis, geometry=geom, ischeme='gauss5') # prepare matrix timestep = timescale / nelems At = (1 / timestep) * function.outer(basis) matrix0 = domain.integrate(At, geometry=geom, ischeme='gauss5') # prepare plotting makeplots = MakePlots(domain, geom, video=withplots == 'video') if withplots else lambda *args: None # start time stepping for itime in log.count('timestep'): makeplots(u) if endtime and itime * timestep >= endtime: break rhs = matrix0.matvec(lhs) for ipicard in log.count('picard'): u = basis.dot(lhs) beta = function.repeat(u[_], ndims, axis=0) Am = -function.outer((basis[:, _] * beta).div(geom), basis) dmatrix = domain.integrate(Am, geometry=geom, ischeme='gauss5') alpha = .5 * function.sign(function.mean(beta).dotnorm(geom)) Ai = function.outer( function.jump(basis), (alpha * function.jump(basis[:, _] * beta) - function.mean(basis[:, _] * beta)).dotnorm(geom)) dmatrix += domain.interfaces.integrate(Ai, geometry=geom, ischeme='gauss5') lhs, info = (matrix0 + dmatrix).solve(rhs, lhs0=lhs, tol=tol, restart=999, precon='spilu', info=True) if info.niter == 0: break return rhs, lhs
def setUp(self): super().setUp() domain, geom = mesh.rectilinear([8,8]) basis = domain.basis('std', degree=1) self.cons = domain.boundary['left'].project(0, onto=basis, geometry=geom, ischeme='gauss2') dofs = function.Argument('dofs', [len(basis)]) u = basis.dot(dofs) self.residual = domain.integral((basis.grad(geom) * u.grad(geom)).sum(-1)*function.J(geom), degree=2) \ + domain.boundary['top'].integral(basis*function.J(geom), degree=2)
def splipy_to_nutils(spline): """ Returns nutils domain and geometry object for spline mapping given by the argument """ from nutils import mesh, function domain, geom = mesh.rectilinear(spline.knots()) cp = controlpoints(spline) basis = domain.basis('spline', degree=degree(spline), knotmultiplicities=multiplicities(spline)) geom = function.matmat(basis, cp) #TODO: add correct behaviour for rational and/or periodic geometries return domain, geom
def setUp(self): ns = function.Namespace() domain, ns.x = mesh.rectilinear([10], periodic=(0,)) ns.basis = domain.basis('discont', degree=1) ns.u = 'basis_n ?dofs_n' ns.f = '.5 u^2' self.residual = domain.integral('-basis_n,0 f d:x' @ ns, degree=2) self.residual += domain.interfaces.integral('-[basis_n] n_0 ({f} - .5 [u] n_0) d:x' @ ns, degree=4) self.inertia = domain.integral('basis_n u d:x' @ ns, degree=5) self.lhs0 = numpy.sin(numpy.arange(len(ns.basis))) # "random" initial vector
def main(alpha=0.01, nelems=64, degree=2, dt=0.01, tend=1): # construct topology, geometry and basis verts = numpy.linspace(0, 1, nelems + 1) domain, geom = mesh.rectilinear([verts, verts]) basis = domain.basis('spline', degree=degree) ischeme = 'gauss4' print(basis) exit() # construct matrices A = 1 / dt * basis['i'] * basis['j'] + alpha / 2 * basis['i,k'] * basis[ 'j,k'] B = 1 / dt * basis['i'] * basis['j'] - alpha / 2 * basis['i,k'] * basis[ 'j,k'] A, B = domain.integrate([A, B], geometry=geom, ischeme=ischeme) # construct dirichlet boundary constraints cons = domain.boundary.project(0, onto=basis, geometry=geom, ischeme=ischeme) # construct initial condition x0, x1 = geom l = function.max( # level set of a square centred at (0.3,0.4) 0.15 - (abs(0.3 - x0) + abs(0.4 - x1)), # level set of a circle centred at (0.7,0.6) 0.15 - ((0.7 - x0)**2 + (0.6 - x1)**2)**0.5, ) # smooth heaviside of level set u0 = 0.5 + 0.5 * function.tanh(nelems / 2 * l) for n in log.range('timestep', round(tend / dt) + 1): if n == 0: # project initial condition on `basis` w = domain.project(u0, onto=basis, geometry=geom, ischeme=ischeme) else: # time step w = A.solve(B.matvec(w), constrain=cons) # construct solution u = basis.dot(w) # plot points, colors = domain.elem_eval([geom, u], ischeme='bezier3', separate=True) with plot.PyPlot('temperature') as plt: plt.title('t={:5.2f}'.format(n * dt)) plt.mesh(points, colors) plt.colorbar() plt.clim(0, 1)
def main(nelems: int, degree: int, reynolds: float): ''' Driven cavity benchmark problem using compatible spaces. .. arguments:: nelems [12] Number of elements along edge. degree [2] Polynomial degree for velocity; the pressure space is one degree less. reynolds [1000] Reynolds number, taking the domain size as characteristic length. ''' verts = numpy.linspace(0, 1, nelems + 1) domain, geom = mesh.rectilinear([verts, verts]) ns = function.Namespace() ns.x = geom ns.Re = reynolds ns.uxbasis, ns.uybasis, ns.pbasis, ns.lbasis = function.chain([ domain.basis('spline', degree=(degree, degree - 1), removedofs=((0, -1), None)), domain.basis('spline', degree=(degree - 1, degree), removedofs=(None, (0, -1))), domain.basis('spline', degree=degree - 1), [1], # lagrange multiplier ]) ns.ubasis_ni = '<uxbasis_n, uybasis_n>_i' ns.u_i = 'ubasis_ni ?lhs_n' ns.p = 'pbasis_n ?lhs_n' ns.l = 'lbasis_n ?lhs_n' ns.stress_ij = '(u_i,j + u_j,i) / Re - p δ_ij' ns.uwall = domain.boundary.indicator('top'), 0 ns.N = 5 * degree * nelems # nitsche constant based on element size = 1/nelems ns.nitsche_ni = '(N ubasis_ni - (ubasis_ni,j + ubasis_nj,i) n_j) / Re' res = domain.integral( '(ubasis_ni,j stress_ij + pbasis_n (u_k,k + l) + lbasis_n p) d:x' @ ns, degree=2 * degree) res += domain.boundary.integral( '(nitsche_ni (u_i - uwall_i) - ubasis_ni stress_ij n_j) d:x' @ ns, degree=2 * degree) with treelog.context('stokes'): lhs0 = solver.solve_linear('lhs', res) postprocess(domain, ns, lhs=lhs0) res += domain.integral('ubasis_ni u_i,j u_j d:x' @ ns, degree=3 * degree) with treelog.context('navierstokes'): lhs1 = solver.newton('lhs', res, lhs0=lhs0).solve(tol=1e-10) postprocess(domain, ns, lhs=lhs1) return lhs0, lhs1
def __init__(self, physical, n, p): """ __init__(self, physical, n, p) Constructor for finite element object :param physical : (width, height) of physical domain :param n : (n1,n2), number of elements in computational domain :param p : (p1,p2), polynomial degree of compuational discretization """ # create splipy object splinesurf = splines.square() * physical splinesurf.reparam((0, physical[0]), (0, physical[1])) splinesurf.raise_order(p[0] - 1, p[1] - 1) splinesurf.refine(n[0] - 1, n[1] - 1) # create nutils mesh domain, geom = mesh.rectilinear(splinesurf.knots()) basis = domain.basis('spline', degree=p) # pre-compute all system matrices derivs = function.outer(basis.grad(geom), basis.grad(geom)) laplace = derivs[:, :, 0] + derivs[:, :, 1] A = domain.integrate(laplace, geometry=geom, ischeme='gauss3') M = domain.integrate(function.outer(basis, basis), geometry=geom, ischeme='gauss3') # print(M.toarray()) # pre-compute evaluation matrices self.Nu = splinesurf.bases[0].evaluate( np.linspace(splinesurf.start('u'), splinesurf.end('u'), physical[0])) self.Nv = splinesurf.bases[1].evaluate( np.linspace(splinesurf.start('v'), splinesurf.end('v'), physical[1])) # store all nutils object as class variables self.splinesurf = splinesurf self.domain = domain self.geom = geom self.basis = basis self.A = A.toscipy() * 1e2 self.M = M.toscipy() self.u = np.matrix(np.zeros((A.shape[0], 1))) self.b = np.matrix(np.zeros((A.shape[0], 1))) self.n = np.array(n) self.p = np.array(p) self.physical = np.array(physical) self.time = { 'add_smoke': 0, 'get_img': 0, 'stop_smoke': 0, 'diffuse': 0, 'solve': 0 }
def test_nutils_tensor(): domain, geom = mesh.rectilinear([[0, 1], [0, 1]]) basis = domain.basis('spline', degree=1) itg = basis[:, _, _] * basis[_, :, _] * basis[_, _, :] a = AffineIntegral(1, itg) a.prop(domain=domain, geometry=geom, ischeme='gauss9') a = a.cache_main(force=True)(None, {}) b = domain.integrate(itg * fn.J(geom), ischeme='gauss9') np.testing.assert_almost_equal(a, b)
def navierstokes(): domain, geom = mesh.rectilinear([numpy.linspace(0, 1, 9)] * 2) ubasis, pbasis = function.chain([ domain.basis('std', degree=2).vector(2), domain.basis('std', degree=1), ]) dofs = function.DerivativeTarget([len(ubasis)]) u = ubasis.dot(dofs) p = pbasis.dot(dofs) viscosity = 1 inertia = model.Integral((ubasis * u).sum(-1), domain=domain, geometry=geom, degree=5) stokesres = model.Integral(viscosity * ubasis['ni,j'] * (u['i,j'] + u['j,i']) - ubasis['nk,k'] * p + pbasis['n'] * u['k,k'], domain=domain, geometry=geom, degree=5) residual = stokesres + model.Integral(ubasis['ni'] * u['i,j'] * u['j'], domain=domain, geometry=geom, degree=5) cons = domain.boundary['top,bottom'].project( [0,0], onto=ubasis, geometry=geom, ischeme='gauss2' ) \ | domain.boundary['left'].project( [geom[1]*(1-geom[1]),0], onto=ubasis, geometry=geom, ischeme='gauss2' ) lhs0 = model.solve_linear(dofs, residual=stokesres, constrain=cons) for name in 'direct', 'newton', 'pseudotime': @unittest(name=name, raises=name == 'direct' and model.ModelError) def res(): tol = 1e-10 if name == 'direct': lhs = model.solve_linear(dofs, residual=residual, constrain=cons) elif name == 'newton': lhs = model.newton(dofs, residual=residual, lhs0=lhs0, freezedofs=cons.where).solve(tol=tol, maxiter=2) else: lhs = model.pseudotime(dofs, residual=residual, lhs0=lhs0, freezedofs=cons.where, inertia=inertia, timestep=1).solve(tol=tol, maxiter=3) res = residual.replace(dofs, lhs).eval() resnorm = numpy.linalg.norm(res[~cons.where]) assert resnorm < tol
def setUp(self): super().setUp() domain, geom = mesh.rectilinear([numpy.linspace(0,1,9)] * 2) ubasis = domain.basis('std', degree=2).vector(2) u = ubasis.dot(function.Argument('dofs', [len(ubasis)])) Geom = geom * [1.1, 1] + u self.cons = solver.minimize('dofs', domain.boundary['left,right'].integral((u**2).sum(0), degree=4), droptol=1e-15).solve() self.boolcons = ~numpy.isnan(self.cons) strain = .5 * (function.outer(Geom.grad(geom), axis=1).sum(0) - function.eye(2)) self.energy = domain.integral(((strain**2).sum([0,1]) + 20*(function.determinant(Geom.grad(geom))-1)**2)*function.J(geom), degree=6) self.residual = self.energy.derivative('dofs') self.tol = 1e-10
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 main( nelems: 'number of elements' = 12, lmbda: 'first lamé constant' = 1., mu: 'second lamé constant' = 1., degree: 'polynomial degree' = 2, withplots: 'create plots' = True, solvetol: 'solver tolerance' = 1e-10, ): # construct mesh verts = numpy.linspace(0, 1, nelems + 1) domain, geom = mesh.rectilinear([verts, verts]) # create namespace ns = function.Namespace(default_geometry_name='x0') ns.x0 = geom ns.basis = domain.basis('spline', degree=degree).vector(2) ns.u_i = 'basis_ni ?lhs_n' ns.x_i = 'x0_i + u_i' ns.lmbda = lmbda ns.mu = mu ns.strain_ij = '(u_i,j + u_j,i) / 2' ns.stress_ij = 'lmbda strain_kk δ_ij + 2 mu strain_ij' # construct dirichlet boundary constraints sqr = domain.boundary['left'].integral('u_k u_k' @ ns, geometry=ns.x0, degree=2) sqr += domain.boundary['right'].integral('(u_0 - .5)^2' @ ns, geometry=ns.x0, degree=2) cons = solver.optimize('lhs', sqr, droptol=1e-15) # construct residual res = domain.integral('basis_ni,j stress_ij' @ ns, geometry=ns.x0, degree=2) # solve system and substitute the solution in the namespace lhs = solver.solve_linear('lhs', res, constrain=cons) ns |= dict(lhs=lhs) # plot solution if withplots: points, colors = domain.elem_eval([ns.x, ns.stress[0, 1]], ischeme='bezier3', separate=True) with plot.PyPlot('stress', ndigits=0) as plt: plt.mesh(points, colors, tight=False) plt.colorbar() return lhs, cons
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 test_nonlinear_diagonalshift(self): nelems = 10 domain, geom = mesh.rectilinear([nelems,1]) geom *= [2*numpy.pi/nelems, 1] ubasis = domain.basis('spline', degree=2).vector(2) u = ubasis.dot(function.Argument('dofs', [len(ubasis)])) Geom = [.5 * geom[0], geom[1] + function.cos(geom[0])] + u # compress by 50% and buckle cons = solver.minimize('dofs', domain.boundary['left,right'].integral((u**2).sum(0), degree=4), droptol=1e-15).solve() strain = .5 * (function.outer(Geom.grad(geom), axis=1).sum(0) - function.eye(2)) energy = domain.integral(((strain**2).sum([0,1]) + 150*(function.determinant(Geom.grad(geom))-1)**2)*function.J(geom), degree=6) nshift = 0 for iiter, (lhs, info) in enumerate(solver.minimize('dofs', energy, constrain=cons)): self.assertLess(iiter, 90) if info.shift: nshift += 1 if info.resnorm < self.tol: break self.assertEqual(nshift, 60)
def setUp(self): super().setUp() domain, geom = mesh.rectilinear([numpy.linspace(0,1,9)] * 2) ubasis, pbasis = function.chain([ domain.basis('std', degree=2).vector(2), domain.basis('std', degree=1), ]) dofs = function.Argument('dofs', [len(ubasis)]) u = ubasis.dot(dofs) p = pbasis.dot(dofs) viscosity = 1 self.inertia = domain.integral((ubasis * u).sum(-1), geometry=geom, degree=5) stokesres = domain.integral(viscosity * (ubasis.grad(geom) * (u.grad(geom)+u.grad(geom).T)).sum([-1,-2]) - ubasis.div(geom) * p + pbasis * u.div(geom), geometry=geom, degree=5) self.residual = stokesres + domain.integral((ubasis * (u.grad(geom) * u).sum(-1) * u).sum(-1), geometry=geom, degree=5) self.cons = domain.boundary['top,bottom'].project([0,0], onto=ubasis, geometry=geom, ischeme='gauss2') \ | domain.boundary['left'].project([geom[1]*(1-geom[1]),0], onto=ubasis, geometry=geom, ischeme='gauss2') self.lhs0 = solver.solve_linear('dofs', residual=stokesres, constrain=self.cons) self.tol = 1e-10
def main( nelems: 'number of elements' = 12, lmbda: 'first lamé constant' = 1., mu: 'second lamé constant' = 1., degree: 'polynomial degree' = 2, withplots: 'create plots' = True, solvetol: 'solver tolerance' = 1e-10, ): # construct mesh verts = numpy.linspace(0, 1, nelems+1) domain, geom = mesh.rectilinear([verts,verts]) # create namespace ns = function.Namespace(default_geometry_name='x0') ns.x0 = geom ns.basis = domain.basis('spline', degree=degree).vector(2) ns.u_i = 'basis_ni ?lhs_n' ns.x_i = 'x0_i + u_i' ns.lmbda = lmbda ns.mu = mu ns.strain_ij = '(u_i,j + u_j,i) / 2' ns.stress_ij = 'lmbda strain_kk δ_ij + 2 mu strain_ij' # construct dirichlet boundary constraints sqr = domain.boundary['left'].integral('u_k u_k' @ ns, geometry=ns.x0, degree=2) sqr += domain.boundary['right'].integral('(u_0 - .5)^2' @ ns, geometry=ns.x0, degree=2) cons = solver.optimize('lhs', sqr, droptol=1e-15) # construct residual res = domain.integral('basis_ni,j stress_ij' @ ns, geometry=ns.x0, degree=2) # solve system and substitute the solution in the namespace lhs = solver.solve_linear('lhs', res, constrain=cons) ns |= dict(lhs=lhs) # plot solution if withplots: points, colors = domain.elem_eval([ns.x, ns.stress[0,1]], ischeme='bezier3', separate=True) with plot.PyPlot('stress', ndigits=0) as plt: plt.mesh(points, colors, tight=False) plt.colorbar() return lhs, cons
def laplace(): domain, geom = mesh.rectilinear( [8,8] ) basis = domain.basis( 'std', degree=1 ) cons = domain.boundary['left'].project( 0, onto=basis, geometry=geom, ischeme='gauss2' ) dofs = function.DerivativeTarget( [len(basis)] ) u = basis.dot( dofs ) residual = model.Integral( ( basis.grad(geom) * u.grad(geom) ).sum(-1), domain=domain, geometry=geom, degree=2 ) \ + model.Integral( basis, domain=domain.boundary['top'], geometry=geom, degree=2 ) for name in 'direct', 'newton': @unittest( name=name ) def res(): if name == 'direct': lhs = model.solve_linear( dofs, residual=residual, constrain=cons ) else: lhs = model.newton( dofs, residual=residual, lhs0=cons|0, freezedofs=cons.where ).solve( tol=1e-10, maxiter=0 ) res = residual.replace( dofs, lhs ).eval() resnorm = numpy.linalg.norm( res[~cons.where] ) assert resnorm < 1e-13
def main( nelems: 'number of elements' = 20, degree: 'polynomial degree' = 1, timescale: 'time scale (timestep=timescale/nelems)' = .5, tol: 'solver tolerance' = 1e-5, ndims: 'spatial dimension' = 1, endtime: 'end time, 0 for no end time' = 0, withplots: 'create plots' = True, ): # construct mesh, basis ns = function.Namespace() domain, ns.x = mesh.rectilinear([numpy.linspace(0,1,nelems+1)]*ndims, periodic=range(ndims)) ns.basis = domain.basis('discont', degree=degree) ns.u = 'basis_n ?lhs_n' # construct initial condition (centered gaussian) lhs0 = domain.project('exp(-?y_i ?y_i) | ?y_i = 5 (x_i - 0.5_i)' @ ns, onto=ns.basis, geometry=ns.x, degree=5) # prepare residual ns.f = '.5 u^2' ns.C = 1 res = domain.integral('-basis_n,0 f' @ ns, geometry=ns.x, degree=5) res += domain.interfaces.integral('-[basis_n] n_0 ({f} - .5 C [u] n_0)' @ ns, geometry=ns.x, degree=5) inertia = domain.integral('basis_n u' @ ns, geometry=ns.x, degree=5) # prepare plotting makeplots = MakePlots(domain, video=withplots=='video') if withplots else lambda ns: None # start time stepping timestep = timescale/nelems for itime, lhs in log.enumerate('timestep', solver.impliciteuler('lhs', res, inertia, timestep, lhs0, newtontol=tol)): makeplots(ns | dict(lhs=lhs)) if endtime and itime * timestep >= endtime: break return res.eval(arguments=dict(lhs=lhs)), lhs
def main( nelems: 'number of elements' = 20, epsilon: 'epsilon, 0 for automatic (based on nelems)' = 0, timestep: 'time step' = .01, maxtime: 'end time' = 1., theta: 'contact angle (degrees)' = 90, init: 'initial condition (random/bubbles)' = 'random', withplots: 'create plots' = True, ): mineps = 1./nelems if not epsilon: log.info('setting epsilon={}'.format(mineps)) epsilon = mineps elif epsilon < mineps: log.warning('epsilon under crititical threshold: {} < {}'.format(epsilon, mineps)) # create namespace ns = function.Namespace() ns.epsilon = epsilon ns.ewall = .5 * numpy.cos( theta * numpy.pi / 180 ) # construct mesh xnodes = ynodes = numpy.linspace(0,1,nelems+1) domain, ns.x = mesh.rectilinear( [ xnodes, ynodes ] ) # prepare bases ns.cbasis, ns.mubasis = function.chain([ domain.basis('spline', degree=2), domain.basis('spline', degree=2) ]) # polulate namespace ns.c = 'cbasis_n ?lhs_n' ns.c0 = 'cbasis_n ?lhs0_n' ns.mu = 'mubasis_n ?lhs_n' ns.f = '(6 c0 - 2 c0^3 - 4 c) / epsilon^2' # construct initial condition if init == 'random': numpy.random.seed(0) lhs0 = numpy.random.normal(0, .5, ns.cbasis.shape) elif init == 'bubbles': R1 = .25 R2 = numpy.sqrt(.5) * R1 # area2 = .5 * area1 ns.cbubble1 = function.tanh((R1-function.norm2(ns.x-(.5+R2/numpy.sqrt(2)+.8*ns.epsilon)))/ns.epsilon) ns.cbubble2 = function.tanh((R2-function.norm2(ns.x-(.5-R1/numpy.sqrt(2)-.8*ns.epsilon)))/ns.epsilon) sqr = domain.integral('(c - cbubble1 - cbubble2 - 1)^2 + mu^2' @ ns, geometry=ns.x, degree=4) lhs0 = solver.optimize('lhs', sqr) else: raise Exception( 'unknown init %r' % init ) # construct residual res = domain.integral('epsilon^2 cbasis_n,k mu_,k + mubasis_n (mu + f) - mubasis_n,k c_,k' @ ns, geometry=ns.x, degree=4) res -= domain.boundary.integral('mubasis_n ewall' @ ns, geometry=ns.x, degree=4) inertia = domain.integral('cbasis_n c' @ ns, geometry=ns.x, degree=4) # solve time dependent problem nsteps = numeric.round(maxtime/timestep) makeplots = MakePlots(domain, nsteps, ns) if withplots else lambda *args: None for istep, lhs in log.enumerate('timestep', solver.impliciteuler('lhs', target0='lhs0', residual=res, inertia=inertia, timestep=timestep, lhs0=lhs0)): makeplots(lhs) if istep == nsteps: break return lhs0, lhs
def setUp(self): super().setUp() self.ns = function.Namespace() self.domain, self.ns.geom = mesh.rectilinear([2,2]) self.ns.ubasis = self.domain.basis('std', degree=1)
def main( nelems: 'number of elements' = 12, viscosity: 'fluid viscosity' = 1e-2, density: 'fluid density' = 1, tol: 'solver tolerance' = 1e-12, rotation: 'cylinder rotation speed' = 0, timestep: 'time step' = 1/24, maxradius: 'approximate domain size' = 25, tmax: 'end time' = numpy.inf, degree: 'polynomial degree' = 2, figures: 'create figures' = True, ): log.user('reynolds number: {:.1f}'.format(density / viscosity)) # based on unit length and velocity # create namespace ns = function.Namespace() ns.uinf = 1, 0 ns.density = density ns.viscosity = viscosity # construct mesh rscale = numpy.pi / nelems melems = numpy.ceil(numpy.log(2*maxradius) / rscale).astype(int) log.info('creating {}x{} mesh, outer radius {:.2f}'.format(melems, 2*nelems, .5*numpy.exp(rscale*melems))) domain, x0 = mesh.rectilinear([range(melems+1),numpy.linspace(0,2*numpy.pi,2*nelems+1)], periodic=(1,)) rho, phi = x0 phi += 1e-3 # tiny nudge (0.057 deg) to break element symmetry radius = .5 * function.exp(rscale * rho) ns.x = radius * function.trigtangent(phi) domain = domain.withboundary(inner='left', inflow=domain.boundary['right'].select(-ns.uinf.dotnorm(ns.x), ischeme='gauss1')) # prepare bases (using piola transformation to maintain u/p compatibility) J = ns.x.grad(x0) detJ = function.determinant(J) ns.unbasis, ns.utbasis, ns.pbasis = function.chain([ # compatible spaces using piola transformation domain.basis('spline', degree=(degree+1,degree), removedofs=((0,),None))[:,_] * J[:,0] / detJ, domain.basis('spline', degree=(degree,degree+1))[:,_] * J[:,1] / detJ, domain.basis('spline', degree=degree) / detJ, ]) ns.ubasis_ni = 'unbasis_ni + utbasis_ni' # populate namespace ns.u_i = 'ubasis_ni ?lhs_n' ns.p = 'pbasis_n ?lhs_n' ns.sigma_ij = 'viscosity (u_i,j + u_j,i) - p δ_ij' ns.hinner = 2 * numpy.pi / nelems ns.c = 5 * (degree+1) / ns.hinner ns.nietzsche_ni = 'viscosity (c ubasis_ni - (ubasis_ni,j + ubasis_nj,i) n_j)' ns.ucyl = -.5 * rotation * function.trignormal(phi) # create residual vector components res = domain.integral('ubasis_ni,j sigma_ij + pbasis_n u_k,k' @ ns, geometry=ns.x, degree=2*(degree+1)) res += domain.boundary['inner'].integral('nietzsche_ni (u_i - ucyl_i)' @ ns, geometry=ns.x, degree=2*(degree+1)) oseen = domain.integral('density ubasis_ni u_i,j uinf_j' @ ns, geometry=ns.x, degree=2*(degree+1)) convec = domain.integral('density ubasis_ni u_i,j u_j' @ ns, geometry=ns.x, degree=3*(degree+1)) inertia = domain.integral('density ubasis_ni u_i' @ ns, geometry=ns.x, degree=2*(degree+1)) # constrain full velocity vector at inflow sqr = domain.boundary['inflow'].integral('(u_i - uinf_i) (u_i - uinf_i)' @ ns, geometry=ns.x, degree=9) cons = solver.optimize('lhs', sqr, droptol=1e-15) # solve unsteady navier-stokes equations, starting from stationary oseen flow lhs0 = solver.solve_linear('lhs', res+oseen, constrain=cons) makeplots = MakePlots(domain, ns, timestep=timestep, rotation=rotation) if figures else lambda *args: None for istep, lhs in log.enumerate('timestep', solver.impliciteuler('lhs', residual=res+convec, inertia=inertia, lhs0=lhs0, timestep=timestep, constrain=cons, newtontol=1e-10)): makeplots(lhs) if istep * timestep >= tmax: break return lhs0, lhs
def main( L: 'domain size' = 4., R: 'hole radius' = 1., E: "young's modulus" = 1e5, nu: "poisson's ratio" = 0.3, T: 'far field traction' = 10, nr: 'number of h-refinements' = 2, figures: 'create figures' = True, ): ns = function.Namespace() ns.lmbda = E*nu/(1-nu**2) ns.mu = .5*E/(1+nu) # create the coarsest level parameter domain domain0, geometry = mesh.rectilinear( [1,2] ) # create the second-order B-spline basis over the coarsest domain ns.bsplinebasis = domain0.basis('spline', degree=2) ns.controlweights = 1,.5+.5/2**.5,.5+.5/2**.5,1,1,1,1,1,1,1,1,1 ns.weightfunc = 'bsplinebasis_n controlweights_n' ns.nurbsbasis = ns.bsplinebasis * ns.controlweights / ns.weightfunc # create the isogeometric map ns.controlpoints = [0,R],[R*(1-2**.5),R],[-R,R*(2**.5-1)],[-R,0],[0,.5*(R+L)],[-.15*(R+L),.5*(R+L)],[-.5*(R+L),.15*(R*L)],[-.5*(R+L),0],[0,L],[-L,L],[-L,L],[-L,0] ns.x_i = 'nurbsbasis_n controlpoints_ni' # create the computational domain by h-refinement domain = domain0.refine(nr) # create the second-order B-spline basis over the refined domain ns.bsplinebasis = domain.basis('spline', degree=2) sqr = domain.integral('(bsplinebasis_n ?lhs_n - weightfunc)^2' @ ns, geometry=ns.x, degree=9) ns.controlweights = solver.optimize('lhs', sqr) ns.nurbsbasis = ns.bsplinebasis * ns.controlweights / ns.weightfunc # prepare the displacement field ns.ubasis = ns.nurbsbasis.vector(2) ns.u_i = 'ubasis_ni ?lhs_n' ns.strain_ij = '(u_i,j + u_j,i) / 2' ns.stress_ij = 'lmbda strain_kk δ_ij + 2 mu strain_ij' # construct the exact solution ns.r2 = 'x_k x_k' ns.R2 = R**2 ns.T = T ns.k = (3-nu) / (1+nu) # plane stress parameter ns.uexact_i = '''(T / 4 mu) <x_0 ((k + 1) / 2 + (1 + k) R2 / r2 + (1 - R2 / r2) (x_0^2 - 3 x_1^2) R2 / r2^2), x_1 ((k - 3) / 2 + (1 - k) R2 / r2 + (1 - R2 / r2) (3 x_0^2 - x_1^2) R2 / r2^2)>_i''' ns.strainexact_ij = '(uexact_i,j + uexact_j,i) / 2' ns.stressexact_ij = 'lmbda strainexact_kk δ_ij + 2 mu strainexact_ij' # define the linear and bilinear forms res = domain.integral('ubasis_ni,j stress_ij' @ ns, geometry=ns.x, degree=9) res -= domain.boundary['right'].integral('ubasis_ni stressexact_ij n_j' @ ns, geometry=ns.x, degree=9) # compute the constraints vector for the symmetry conditions sqr = domain.boundary['top,bottom'].integral('(u_i n_i)^2' @ ns, degree=9) cons = solver.optimize('lhs', sqr, droptol=1e-15) # solve the system of equations lhs = solver.solve_linear('lhs', res, constrain=cons) ns = ns(lhs=lhs) # post-processing if figures: geom, stressxx = domain.simplex.elem_eval([ns.x, 'stress_00' @ ns], ischeme='bezier8', separate=True) with plot.PyPlot( 'solution', index=nr ) as plt: plt.mesh( geom, stressxx ) plt.colorbar() # compute the L2-norm of the error in the stress err = domain.integrate('(?dstress_ij ?dstress_ij)(dstress_ij = stress_ij - stressexact_ij)' @ ns, geometry=ns.x, ischeme='gauss9')**.5 # compute the mesh parameter (maximum physical distance between knots) hmax = max(numpy.linalg.norm(v[:,numpy.newaxis]-v, axis=2).max() for v in domain.elem_eval(ns.x, ischeme='bezier2', separate=True)) return err, hmax