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 __init__( self, domain, geom, timestep, bbox=((-2,6),(-3,3)), video=False ): self.bbox = numpy.asarray(bbox) self.plotdomain = domain.select( function.piecewise( geom[0], self.bbox[0], 0, 1, 0 ) * function.piecewise( geom[1], self.bbox[1], 0, 1, 0 ), 'bezier3' ) self.geom = geom self.plt = video and plot.PyPlotVideo( 'flow' ) self.every = .01 self.index = 0 self.timestep = timestep self.spacing = .075 self.xy = util.regularize( self.bbox, self.spacing )
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 __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 __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 main(nelems: int, degree: int, reynolds: float, rotation: float, timestep: float, maxradius: float, seed: int, endtime: float): ''' Flow around a cylinder. .. arguments:: nelems [24] Element size expressed in number of elements along the cylinder wall. All elements have similar shape with approximately unit aspect ratio, with elements away from the cylinder wall growing exponentially. degree [3] Polynomial degree for velocity space; the pressure space is one degree less. reynolds [1000] Reynolds number, taking the cylinder radius as characteristic length. rotation [0] Cylinder rotation speed. timestep [.04] Time step maxradius [25] Target exterior radius; the actual domain size is subject to integer multiples of the configured element size. seed [0] Random seed for small velocity noise in the intial condition. endtime [inf] Stopping time. ''' elemangle = 2 * numpy.pi / nelems melems = int(numpy.log(2 * maxradius) / elemangle + .5) treelog.info('creating {}x{} mesh, outer radius {:.2f}'.format( melems, nelems, .5 * numpy.exp(elemangle * melems))) domain, geom = mesh.rectilinear([melems, nelems], periodic=(1, )) domain = domain.withboundary(inner='left', outer='right') ns = function.Namespace() ns.uinf = 1, 0 ns.r = .5 * function.exp(elemangle * geom[0]) ns.Re = reynolds ns.phi = geom[1] * elemangle # add small angle to break element symmetry ns.x_i = 'r <cos(phi), sin(phi)>_i' ns.J = ns.x.grad(geom) ns.unbasis, ns.utbasis, ns.pbasis = function.chain([ # compatible spaces domain.basis( 'spline', degree=(degree, degree - 1), removedofs=((0, ), None)), domain.basis('spline', degree=(degree - 1, degree)), domain.basis('spline', degree=degree - 1), ]) / function.determinant(ns.J) ns.ubasis_ni = 'unbasis_n J_i0 + utbasis_n J_i1' # piola transformation ns.u_i = 'ubasis_ni ?lhs_n' ns.p = 'pbasis_n ?lhs_n' ns.sigma_ij = '(u_i,j + u_j,i) / Re - p δ_ij' ns.h = .5 * elemangle ns.N = 5 * degree / ns.h ns.rotation = rotation ns.uwall_i = '0.5 rotation <-sin(phi), cos(phi)>_i' inflow = domain.boundary['outer'].select( -ns.uinf.dotnorm(ns.x), ischeme='gauss1') # upstream half of the exterior boundary sqr = inflow.integral('(u_i - uinf_i) (u_i - uinf_i)' @ ns, degree=degree * 2) cons = solver.optimize( 'lhs', sqr, droptol=1e-15) # constrain inflow semicircle to uinf sqr = domain.integral('(u_i - uinf_i) (u_i - uinf_i) + p^2' @ ns, degree=degree * 2) lhs0 = solver.optimize('lhs', sqr) # set initial condition to u=uinf, p=0 numpy.random.seed(seed) lhs0 *= numpy.random.normal(1, .1, lhs0.shape) # add small velocity noise res = domain.integral( '(ubasis_ni u_i,j u_j + ubasis_ni,j sigma_ij + pbasis_n u_k,k) d:x' @ ns, degree=9) res += domain.boundary['inner'].integral( '(N ubasis_ni - (ubasis_ni,j + ubasis_nj,i) n_j) (u_i - uwall_i) d:x / Re' @ ns, degree=9) inertia = domain.integral('ubasis_ni u_i d:x' @ ns, degree=9) bbox = numpy.array( [[-2, 46 / 9], [-2, 2]]) # bounding box for figure based on 16x9 aspect ratio bezier0 = domain.sample('bezier', 5) bezier = bezier0.subset((bezier0.eval( (ns.x - bbox[:, 0]) * (bbox[:, 1] - ns.x)) > 0).all(axis=1)) interpolate = util.tri_interpolator( bezier.tri, bezier.eval(ns.x), mergetol=1e-5) # interpolator for quivers spacing = .05 # initial quiver spacing xgrd = util.regularize(bbox, spacing) with treelog.iter.plain( 'timestep', solver.impliciteuler('lhs', residual=res, inertia=inertia, lhs0=lhs0, timestep=timestep, constrain=cons, newtontol=1e-10)) as steps: for istep, lhs in enumerate(steps): t = istep * timestep x, u, normu, p = bezier.eval( ['x_i', 'u_i', 'sqrt(u_k u_k)', 'p'] @ ns, lhs=lhs) ugrd = interpolate[xgrd](u) with export.mplfigure('flow.png', figsize=(12.8, 7.2)) as fig: ax = fig.add_axes([0, 0, 1, 1], yticks=[], xticks=[], frame_on=False, xlim=bbox[0], ylim=bbox[1]) im = ax.tripcolor(x[:, 0], x[:, 1], bezier.tri, p, shading='gouraud', cmap='jet') import matplotlib.collections ax.add_collection( matplotlib.collections.LineCollection(x[bezier.hull], colors='k', linewidths=.1, alpha=.5)) ax.quiver(xgrd[:, 0], xgrd[:, 1], ugrd[:, 0], ugrd[:, 1], angles='xy', width=1e-3, headwidth=3e3, headlength=5e3, headaxislength=2e3, zorder=9, alpha=.5) ax.plot(0, 0, 'k', marker=(3, 2, t * rotation * 180 / numpy.pi - 90), markersize=20) cax = fig.add_axes([0.9, 0.1, 0.01, 0.8]) cax.tick_params(labelsize='large') fig.colorbar(im, cax=cax) if t >= endtime: break xgrd = util.regularize(bbox, spacing, xgrd + ugrd * timestep) return lhs0, lhs