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 convergence(nrefine=5): err, h = numpy.array([main(nr=irefine) for irefine in log.range('refine', nrefine)]).T with plot.PyPlot( 'convergence' ) as plt: plt.loglog(h, err, 'k*--') plt.slope_triangle(h, err) plt.ylabel('L2 error of stress') plt.grid(True)
def qgplot(self, **plotkwargs): assert len(self) == 2, NotImplementedError plt = plot.PyPlot('I am a dummy', **plotkwargs) domain = self.domain points = domain.elem_eval(self.geom, ischeme='bezier5', separate=True) plt.mesh(points) plt.show()
def plot_function(self, func=[], ischeme='bezier5', ref=0, boundary=False, show=True, **plotkwargs): assert self.targetspace == 2, NotImplementedError plt = plot.PyPlot('I am a dummy', **plotkwargs) domain = self.domain if not boundary else self.domain.boundary func = [self.mapping] + func points = domain.refine(ref).elem_eval(func, ischeme=ischeme, separate=True) if domain.ndims == 2: plt.mesh(*points) elif domain.ndims == 1: assert len(func) == 1 plt.segments(np.asarray(*points)) plt.aspect('equal') plt.autoscale(enable=True, axis='both', tight=True) else: raise NotImplementedError if show: plt.show()
def __call__(self, lhs): ns = self.namespace(lhs=lhs) self.energies[self.index, :2] = self.domain.integrate( ['(c^2 - 1)^2 / 2 epsilon^2' @ ns, '.5 c_,k c_,k' @ ns], geometry=ns.x, degree=4) self.energies[self.index, 2] = self.domain.boundary.integrate( 'abs(ewall) + ewall c' @ ns, geometry=ns.x, degree=4) self.energies[self.index, 3] = self.energies[self.index, :3].sum() x, c = self.domain.elem_eval([ns.x, ns.c], ischeme='bezier4', separate=True) with plot.PyPlot('flow', index=self.index) as plt: plt.axes(yticks=[], xticks=[]) plt.mesh(x, c) plt.colorbar() plt.clim(-1, 1) plt.axes([.07, .05, .35, .25], yticks=[], xticks=[], axisbg='w').patch.set_alpha(.8) for energy, name in zip(self.energies[:self.index + 1].T, ['mixture', 'interface', 'wall', 'total']): plt.plot(numpy.arange(len(energy))[::-1], energy[::-1], '-o', markevery=self.index + 1, label=name) plt.legend(numpoints=1, frameon=False, fontsize=8) plt.xlim(0, len(self.energies)) plt.ylim(0, self.energies[0, 3]) plt.xlabel('time') plt.ylabel('energy') self.index += 1
def __call__(self, lhs): angle = self.index * self.timestep * self.rotation ns = self.ns(lhs=lhs) x, u, normu, p = self.plotdomain.elem_eval( [ns.x, ns.u, function.norm2(ns.u), ns.p], ischeme='bezier9', separate=True) with plot.PyPlot('flow', index=self.index) as plt: plt.axes([0, 0, 1, 1], yticks=[], xticks=[], frame_on=False) tri = plt.mesh(x, normu, mergetol=1e-5, cmap='jet') plt.clim(0, 1.5) plt.tricontour(tri, p, every=self.every, cmap='gray', linestyles='solid', alpha=.8) uv = plot.interpolate(tri, self.xy, u) plt.vectors(self.xy, uv, zorder=9, pivot='mid', stems=False) plt.plot(0, 0, 'k', marker=(3, 2, angle * 180 / numpy.pi - 90), markersize=20) plt.xlim(self.bbox[0]) plt.ylim(self.bbox[1]) self.xy = util.regularize(self.bbox, self.spacing, self.xy + uv * self.timestep) self.index += 1
def __call__(self, c, mu, *energies): self.energies[self.index] = energies self.index += 1 xpnt, cpnt = self.domain.elem_eval([self.geom, c], ischeme='bezier4', separate=True) I = numpy.arange(self.index - 1, -1, -1) E = self.energies[self.index - 1::-1].T with self.plt if self.plt else plot.PyPlot('flow', index=self.index) as plt: plt.axes(yticks=[], xticks=[]) plt.mesh(xpnt, cpnt) plt.colorbar() plt.clim(-1, 1) plt.axes([.07, .05, .35, .25], yticks=[], xticks=[], axisbg='w').patch.set_alpha(.8) for i, name in enumerate(['mixture', 'interface', 'wall', 'total']): plt.plot(I, E[i] if i < len(E) else E.sum(0), '-o', markevery=self.index, label=name) plt.legend(numpoints=1, frameon=False, fontsize=8) plt.xlim(0, len(self.energies)) plt.ylim(0, self.energies[0].sum()) plt.xlabel('time') plt.ylabel('energy')
def makeplots(domain, geom, stress): points, colors = domain.elem_eval([geom, stress[0, 1]], ischeme='bezier3', separate=True) with plot.PyPlot('stress', ndigits=0) as plt: plt.mesh(points, colors, tight=False) plt.colorbar()
def __call__( self, velo, pres ): self.index += 1 points, velo, pres = self.domain.elem_eval( [ self.geom, velo, pres ], ischeme='bezier9', separate=True ) with plot.PyPlot( 'flow', index=self.index, ndigits=4 ) as plt: tri = plt.mesh( points, mergetol=1e-5 ) plt.tricontour( tri, pres, every=self.dpres, linestyles='solid', alpha=.333 ) plt.colorbar() plt.streamplot( tri, velo, spacing=.01, linewidth=-10, color='k', zorder=9 )
def __call__(self, ns): self.index += 1 xp, up = self.domain.elem_eval([ns.x, ns.u], ischeme='bezier7', separate=True) with plot.PyPlot('solution', index=self.index) as plt: plt.mesh(xp, up) plt.clim(0, 1) plt.colorbar()
def plotpng(self,k,i): with plot.PyPlot(self.name[k] + '{}'.format("%04d", self.ii) + '{}'.format("%04d", i)) as plt: plt.title(self.name[k] + ' at t={:5.1f}'.format(i*self.prop.timestep)) plt.mesh(self.Total_eval[0], self.Total_eval[i+1+k*self.leni]) plt.colorbar(orientation = 'horizontal') plt.clim(self.clim[k][0],self.clim[k][1]) plt.ylabel('Height in [m]') plt.xlabel('Width in [m]') plt.savefig(self.prop.dir + '2. Figures/' + self.name[k] + str(self.ii) + ' {}'.format(i),bbox_inches='tight', dpi = self.prop.dpi)
def __call__(self, u): self.index += 1 xp, up = self.domain.elem_eval([self.geom, u], ischeme='bezier7', separate=True) with self.plt if self.plt else plot.PyPlot('solution', index=self.index) as plt: plt.mesh(xp, up) plt.clim(0, 1) plt.colorbar()
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 convergence( degree = 2 , nrefine = 6, maxrefine = 7 ): """Performs convergence study for the example Parameters ---------- degree : int b-spline degree nrefine : int level of h-refinement maxrefine : int bisectioning steps """ l2err, h1err, errh = numpy.array([main(nelems=2**(1+irefine), maxrefine = nmaxrefine, degree=degree)[1] for nmaxrefine in range(1,maxrefine+1) for irefine in log.range('refine', nrefine)]).T h = .5**numpy.arange(nrefine) clrstr = ['k*--','ks--','k^--','ko--','k--','k+--','kv--','k<--','kX--','k>--'] # ploting errors with plot.PyPlot('L2error',ndigits=0) as plt: for m in range(0,maxrefine): plt.loglog(h, l2err[nrefine*m:nrefine*(m+1)], clrstr[m],label='maxrefine ={}'.format(m)) plt.slope_triangle(h, l2err[nrefine*m:nrefine*(m+1)]) plt.legend() plt.ylabel('L2 error') plt.grid(True) with plot.PyPlot('H1error',ndigits=0) as plt: for m in range(0,maxrefine): plt.loglog(h, h1err[nrefine*m:nrefine*(m+1)], clrstr[m],label='maxrefine ={}'.format(m)) plt.slope_triangle(h, h1err[nrefine*m:nrefine*(m+1)]) plt.legend() plt.ylabel('H1 error') plt.grid(True) with plot.PyPlot('Energy_error',ndigits=0) as plt: for m in range(0,maxrefine): plt.loglog(h, errh[nrefine*m:nrefine*(m+1)], clrstr[m],label='maxrefine ={}'.format(m)) plt.slope_triangle(h, errh[nrefine*m:nrefine*(m+1)]) plt.legend() plt.ylabel('Energy error') plt.grid(True)
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 __call__( self, velo, pres, angle ): self.index += 1 points, velo, flow, pres = self.plotdomain.elem_eval( [ self.geom, velo, function.norm2(velo), pres ], ischeme='bezier9', separate=True ) with self.plt if self.plt else plot.PyPlot( 'flow', index=self.index ) as plt: plt.axes( [0,0,1,1], yticks=[], xticks=[], frame_on=False ) tri = plt.mesh( points, flow, mergetol=1e-5 ) plt.clim( 0, 1.5 ) plt.tricontour( tri, pres, every=self.every, cmap='gray', linestyles='solid', alpha=.8 ) uv = plot.interpolate( tri, self.xy, velo ) plt.vectors( self.xy, uv, zorder=9, pivot='mid', stems=False ) plt.plot( 0, 0, 'k', marker=(3,2,angle*180/numpy.pi-90), markersize=20 ) plt.xlim( self.bbox[0] ) plt.ylim( self.bbox[1] ) self.xy = util.regularize( self.bbox, self.spacing, self.xy + uv * self.timestep )
def postprocess(domain, ns): # confirm that velocity is pointwise divergence-free div = domain.integrate('(u_k,k)^2' @ ns, geometry=ns.x, degree=9)**.5 log.info('velocity divergence: {:.2e}'.format(div)) # plot velocity field as streamlines, pressure field as contours x, u, p = domain.elem_eval([ns.x, ns.u, ns.p], ischeme='bezier9', separate=True) with plot.PyPlot('flow') as plt: tri = plt.mesh(x, mergetol=1e-5) plt.tricontour(tri, p, every=.01, linestyles='solid', alpha=.333) plt.colorbar() plt.streamplot(tri, u, spacing=.01, linewidth=-10, color='k', zorder=9)
def convergence(nrefine=5): err = [] h = [] for irefine in log.range('refine', nrefine): serr, hmax = main(nr=irefine) err.append(serr) h.append(hmax) with plot.PyPlot('convergence') as plt: plt.loglog(h, err, 'k*--') plt.slope_triangle(h, err) plt.ylabel('L2 error of stress') plt.grid(True)
def makeplots(domain, ns): # velocity field evaluation points, vals = domain.simplex.elem_eval([ns.x, ns.u], ischeme='bezier5', separate=True) # trimming curve evaluation tpoints = domain.boundary['trimmed'].elem_eval(ns.x, ischeme='bezier5', separate=True) # background domain evaluation background_domain = topology.UnstructuredTopology(ndims=2, elements=[element.Element(element.LineReference()**2,elem.transform) for elem in domain]) bpoints = background_domain.simplex.elem_eval(ns.x, ischeme='bezier2', separate=True) with plot.PyPlot('cylinder', ndigits=1) as plt: plt.mesh(points , vals, edgecolors='none') plt.mesh(bpoints, edgecolors='r', edgewidth=1.5, mergetol=1e-6) plt.segments( tpoints , color='g', lw=2 ) plt.gca().axis('off') plt.axis('equal')
def __init__(self, domain, ns, timestep, rotation, bbox=((-2,6),(-3,3))): self.bbox = numpy.asarray(bbox) self.plotdomain = domain.select(function.min(*(ns.x-self.bbox[:,0])*(self.bbox[:,1]-ns.x)), 'bezier3') self.ns = ns self.every = .01 self.index = 0 self.timestep = timestep self.rotation = rotation self.spacing = .075 self.xy = util.regularize(self.bbox, self.spacing) x = domain.elem_eval(ns.x, ischeme='bezier5', separate=True) inflow = domain.boundary['inflow'].elem_eval(ns.x, ischeme='bezier5', separate=True) with plot.PyPlot('mesh', ndigits=0) as plt: plt.mesh(x) plt.rectangle(self.bbox[:,0], *(self.bbox[:,1] - self.bbox[:,0]), ec='green') plt.segments(inflow, colors='red')
def main(nelems=8, degree=2, diffusion_over_h=0.5): # construct geometry and initial topology verts = numpy.linspace(0, 1, nelems + 1) domain, geom = mesh.rectilinear([verts, verts]) # common integration arguments int_kwargs = dict(geometry=geom, ischeme='gauss{}'.format(degree * 2 + 1)) for i in log.range('refinement', 4): # create domain and basis for global refinement step `i` if i > 0: domain = domain.refined φ = domain.basis('spline', degree=degree) # compute an initial guess based on the previous iteration, if any if i > 0: u_hat = domain.project(u, onto=φ, **int_kwargs) else: u_hat = numpy.zeros(φ.shape) # solve R = functools.partial(residual, diffusion=diffusion_over_h / (nelems * 2**i), geom=geom, domain=domain, φ=φ, **int_kwargs) u_hat = newton(R, x0=u_hat, maxiter=20, restol=1e-8, lintol=0) # expand solution u = φ.dot(u_hat) # plot points, colors = domain.elem_eval([geom, u], ischeme='bezier3', separate=True) with plot.PyPlot('solution') as plt: plt.title('nelems={}'.format(nelems * 2**i)) plt.mesh(points, colors) plt.colorbar() plt.clim(0, 1) plt.xlabel('t') plt.ylabel('x')
def main( nelems: 'number of elements' = 10, degree: 'polynomial degree' = 1, basistype: 'basis function' = 'spline', solvetol: 'solver tolerance' = 1e-10, figures: 'create figures' = True, ): # construct mesh verts = numpy.linspace(0, numpy.pi/2, nelems+1) domain, geom = mesh.rectilinear([verts, verts]) # create namespace ns = function.Namespace() ns.x = geom ns.basis = domain.basis(basistype, degree=degree) ns.u = 'basis_n ?lhs_n' ns.fx = 'sin(x_0)' ns.fy = 'exp(x_1)' # construct residual res = domain.integral('-basis_n,i u_,i' @ ns, geometry=ns.x, degree=degree*2) res += domain.boundary['top'].integral('basis_n fx fy' @ ns, geometry=ns.x, degree=degree*2) # construct dirichlet constraints sqr = domain.boundary['left'].integral('u^2' @ ns, geometry=ns.x, degree=degree*2) sqr += domain.boundary['bottom'].integral('(u - fx)^2' @ ns, geometry=ns.x, degree=degree*2) cons = solver.optimize('lhs', sqr, droptol=1e-15) # find lhs such that res == 0 and substitute this lhs in the namespace lhs = solver.solve_linear('lhs', res, constrain=cons) ns = ns(lhs=lhs) # plot solution if figures: points, colors = domain.elem_eval([ns.x, ns.u], ischeme='bezier9', separate=True) with plot.PyPlot('solution', index=nelems) as plt: plt.mesh(points, colors, cmap='jet') plt.colorbar() # evaluate error against exact solution fx fy err = domain.integrate('(u - fx fy)^2' @ ns, geometry=ns.x, degree=degree*2)**.5 log.user('L2 error: {:.2e}'.format(err)) return cons, lhs, err
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, withplots: 'create plots' = 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 |= dict(lhs=lhs) # post-processing if withplots: 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
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, withplots: 'create plots' = True, ): #Create the coarsest level parameter domain domain, geometry = mesh.rectilinear([1, 2]) #Define the control points and control point weights controlpoints = numpy.array([[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]]) weights = numpy.array( [1, .5 + .5 / 2**.5, .5 + .5 / 2**.5, 1, 1, 1, 1, 1, 1, 1, 1, 1]) #Create the second-order B-spline basis over the coarsest domain bsplinebasis = domain.basis('spline', degree=2) #Create the NURBS basis weightfunc = bsplinebasis.dot(weights) nurbsbasis = (bsplinebasis * weights) / weightfunc #Create the isogeometric map geometry = (nurbsbasis[:, _] * controlpoints).sum(0) #Create the computational domain by h-refinement domain = domain.refine(nr) #Create the B-spline basis bsplinebasis = domain.basis('spline', degree=2) #Create the NURBS basis weights = domain.project(weightfunc, onto=bsplinebasis, geometry=geometry, ischeme='gauss9') nurbsbasis = (bsplinebasis * weights) / weightfunc #Create the displacement field basis ubasis = nurbsbasis.vector(2) #Define the plane stress function stress = library.Hooke(lmbda=E * nu / (1 - nu**2), mu=.5 * E / (1 + nu)) #Get the exact solution uexact = exact_solution(geometry, T, R, E, nu) sigmaexact = stress(uexact.symgrad(geometry)) #Define the linear and bilinear forms mat_func = function.outer(ubasis.symgrad(geometry), stress(ubasis.symgrad(geometry))).sum([2, 3]) rhs_func = (ubasis * sigmaexact.dotnorm(geometry)).sum(-1) #Compute the matrix and rhs mat = domain.integrate(mat_func, geometry=geometry, ischeme='gauss9') rhs = domain.boundary['right'].integrate(rhs_func, geometry=geometry, ischeme='gauss9') #Compute the constraints vector for the symmetry conditions cons = domain.boundary['top,bottom'].project(0, onto=ubasis.dotnorm(geometry), geometry=geometry, ischeme='gauss9') #Solve the system of equations sol = mat.solve(rhs=rhs, constrain=cons) #Compute the approximate displacement and stress functions u = ubasis.dot(sol) sigma = stress(u.symgrad(geometry)) #Post-processing if withplots: points, colors = domain.simplex.elem_eval([geometry, sigma[0, 0]], ischeme='bezier8', separate=True) with plot.PyPlot('solution', index=nr) as plt: plt.mesh(points, colors) plt.colorbar() #Compute the L2-norm of the error in the stress err = numpy.sqrt( domain.integrate( ((sigma - sigmaexact) * (sigma - sigmaexact)).sum([0, 1]), geometry=geometry, ischeme='gauss9')) #Compute the mesh parameter (maximum physical distance between diagonally opposite knot locations) hmax = numpy.max([ max(numpy.linalg.norm(verts[0] - verts[3]), numpy.linalg.norm(verts[1] - verts[2])) for verts in domain.elem_eval(geometry, ischeme='bezier2', separate=True) ]) return err, hmax
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, withplots: 'create plots' = True, ): uinf = numpy.array([ 1, 0 ]) log.user( 'reynolds number:', density/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, gridgeom = mesh.rectilinear( [range(melems+1),numpy.linspace(0,2*numpy.pi,2*nelems+1)], periodic=(1,) ) rho, phi = gridgeom phi += 1e-3 # tiny nudge (0.057 deg) to break element symmetry cylvelo = -.5 * rotation * function.trignormal(phi) radius = .5 * function.exp( rscale * rho ) geom = radius * function.trigtangent(phi) # prepare bases J = geom.grad( gridgeom ) detJ = function.determinant( J ) vnbasis, vtbasis, pbasis = function.chain([ # compatible spaces using piola transformation domain.basis( 'spline', degree=(3,2), removedofs=((0,),None) )[:,_] * J[:,0] / detJ, domain.basis( 'spline', degree=(2,3) )[:,_] * J[:,1] / detJ, domain.basis( 'spline', degree=2 ) / detJ, ]) vbasis = vnbasis + vtbasis stressbasis = (2*viscosity) * vbasis.symgrad(geom) - pbasis[:,_,_] * function.eye( domain.ndims ) # prepare matrices A = function.outer( vbasis.grad(geom), stressbasis ).sum([2,3]) + function.outer( pbasis, vbasis.div(geom) ) Ao = function.outer( vbasis, density * ( vbasis.grad(geom) * uinf ).sum(-1) ).sum(-1) At = (density/timestep) * function.outer( vbasis ).sum(-1) Ad = function.outer( vbasis.div(geom) ) stokesmat, uniconvec, inertmat, divmat = domain.integrate( [ A, Ao, At, Ad ], geometry=geom, ischeme='gauss9' ) # interior boundary condition (weak imposition of shear verlocity component) inner = domain.boundary['left'] h = inner.elem_eval( 1, geometry=geom, ischeme='gauss9', asfunction=True ) nietzsche = (2*viscosity) * ( (7.5/h) * vbasis - vbasis.symgrad(geom).dotnorm(geom) ) B = function.outer( nietzsche, vbasis ).sum(-1) b = ( nietzsche * cylvelo ).sum(-1) bcondmat, rhs = inner.integrate( [ B, b ], geometry=geom, ischeme='gauss9' ) stokesmat += bcondmat # exterior boundary condition (full velocity vector imposed at inflow) inflow = domain.boundary['right'].select( -( uinf * geom.normal() ).sum(-1), ischeme='gauss1' ) cons = inflow.project( uinf, onto=vbasis, geometry=geom, ischeme='gauss9', tol=1e-12 ) # initial condition (stationary oseen flow) lhs = (stokesmat+uniconvec).solve( rhs, constrain=cons, tol=0 ) # prepare plotting if not withplots: makeplots = lambda *args: None else: makeplots = MakePlots( domain, geom, video=withplots=='video', timestep=timestep ) mesh_ = domain.elem_eval( geom, ischeme='bezier5', separate=True ) inflow_ = inflow.elem_eval( geom, ischeme='bezier5', separate=True ) with plot.PyPlot( 'mesh', ndigits=0 ) as plt: plt.mesh( mesh_ ) plt.rectangle( makeplots.bbox[:,0], *( makeplots.bbox[:,1] - makeplots.bbox[:,0] ), ec='green' ) plt.segments( inflow_, colors='red' ) # start time stepping stokesmat += inertmat precon = (stokesmat+uniconvec).getprecon( 'splu', constrain=cons ) for istep in log.count( 'timestep', start=1 ): log.info( 'velocity divergence:', divmat.matvec(lhs).dot(lhs) ) convection = density * ( vbasis.grad(geom) * vbasis.dot(lhs) ).sum(-1) matrix = stokesmat + domain.integrate( function.outer( vbasis, convection ).sum(-1), ischeme='gauss9', geometry=geom ) lhs = matrix.solve( rhs + inertmat.matvec(lhs), lhs0=lhs, constrain=cons, tol=tol, restart=9999, precon=precon ) makeplots( vbasis.dot(lhs), pbasis.dot(lhs), istep*timestep*rotation ) if istep*timestep > tmax: break return lhs