def test_resume_withscaling(self): _test_recursion_cache( self, lambda: map( types.frozenarray, solver.impliciteuler('dofs', residual=self.residual, inertia=self.inertia, lhs0=self.lhs0, timestep=100)))
def test_iters(self): it = iter( solver.impliciteuler( 'dofs', residual=self.residual, inertia=self.inertia, lhs0=self.lhs0, timestep=100)) # involves 2-level timestep scaling assert numpy.equal(next(it), self.lhs0).all() self.assertAlmostEqual64( next(it), 'eNpzNBA1NjHuNHQ3FDsTfCbAuNz4nUGZgeyZiDOZxlONmQwU9W3OFJ/pNQAADZIOPA==' )
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, 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: 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
def main(nelems: int, ndims: int, degree: int, timescale: float, newtontol: float, endtime: float): ''' Burgers equation on a 1D or 2D periodic domain. .. arguments:: nelems [20] Number of elements along a single dimension. ndims [1] Number of spatial dimensions. degree [1] Polynomial degree for discontinuous basis functions. timescale [.5] Fraction of timestep and element size: timestep=timescale/nelems. newtontol [1e-5] Newton tolerance. endtime [inf] Stopping time. ''' domain, geom = mesh.rectilinear([numpy.linspace(0, 1, nelems + 1)] * ndims, periodic=range(ndims)) ns = function.Namespace() ns.x = geom ns.basis = domain.basis('discont', degree=degree) ns.u = 'basis_n ?lhs_n' ns.f = '.5 u^2' ns.C = 1 res = domain.integral('-basis_n,0 f d:x' @ ns, degree=5) res += domain.interfaces.integral( '-[basis_n] n_0 ({f} - .5 C [u] n_0) d:x' @ ns, degree=degree * 2) inertia = domain.integral('basis_n u d:x' @ ns, degree=5) sqr = domain.integral( '(u - exp(-?y_i ?y_i)(y_i = 5 (x_i - 0.5_i)))^2 d:x' @ ns, degree=5) lhs0 = solver.optimize('lhs', sqr) timestep = timescale / nelems bezier = domain.sample('bezier', 7) with treelog.iter.plain( 'timestep', solver.impliciteuler('lhs', res, inertia, timestep=timestep, lhs0=lhs0, newtontol=newtontol)) as steps: for itime, lhs in enumerate(steps): x, u = bezier.eval(['x_i', 'u'] @ ns, lhs=lhs) export.triplot('solution.png', x, u, tri=bezier.tri, hull=bezier.hull, clim=(0, 1)) if itime * timestep >= endtime: break return lhs
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, withplots: 'create plots' = 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 withplots 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( 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', figures: 'create figures' = 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 figures 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 test_resume_withscaling(self): _test_recursion_cache(self, lambda: map(types.frozenarray, solver.impliciteuler('dofs', residual=self.residual, inertia=self.inertia, lhs0=self.lhs0, timestep=100)))
def test_iters(self): it = iter(solver.impliciteuler('dofs', residual=self.residual, inertia=self.inertia, lhs0=self.lhs0, timestep=100)) # involves 2-level timestep scaling assert numpy.equal(next(it), self.lhs0).all() numeric.assert_allclose64(next(it), 'eNpzNBA1NjHuNHQ3FDsTfCbAuNz4nUGZgeyZiDOZxlONmQwU9W3OFJ/pNQAADZIOPA==')
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( 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