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 newton(f, x0, maxiter, restol, lintol): '''find x such that f(x) = 0, starting at x0''' for i in log.range('newton', maxiter + 1): if i > 0: # solve system linearised around `x`, solution in `direction` J = f(x, jacobian=True) direction = -J.solve(residual, tol=lintol) xprev = x residual_norm_prev = residual_norm # line search, stop if there is convergence w.r.t. iteration `i-1` for j in range(4): x = xprev + (0.5)**j * direction residual = f(x) residual_norm = numpy.linalg.norm(residual, 2) if residual_norm < residual_norm_prev: break # else: no convergence, repeat and reduce step size by one half else: log.warning('divergence') else: # before first iteration, compute initial residual x = x0 residual = f(x) residual_norm = numpy.linalg.norm(residual, 2) log.info('residual norm: {:.5e}'.format(residual_norm)) if residual_norm < restol: break else: raise ValueError( 'newton did not converge in {} iterations'.format(maxiter)) return x
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(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 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 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' = 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=%f' % mineps) epsilon = mineps elif epsilon < mineps: log.warning('epsilon under crititical threshold: %f < %f' % (epsilon, mineps)) ewall = .5 * numpy.cos(theta * numpy.pi / 180) # construct mesh xnodes = ynodes = numpy.linspace(0, 1, nelems + 1) domain, geom = mesh.rectilinear([xnodes, ynodes]) # prepare bases cbasis, mubasis = function.chain( [domain.basis('spline', degree=2), domain.basis('spline', degree=2)]) # define mixing energy and splitting: F' = f_p - f_n F = lambda c_: (.5 / epsilon**2) * (c_**2 - 1)**2 f_p = lambda c_: (1. / epsilon**2) * 4 * c_ f_n = lambda c_: (1. / epsilon**2) * (6 * c_ - 2 * c_**3) # prepare matrix A = function.outer( cbasis ) \ + (timestep*epsilon**2) * function.outer( cbasis.grad(geom), mubasis.grad(geom) ).sum(-1) \ + function.outer( mubasis, mubasis - f_p(cbasis) ) \ - function.outer( mubasis.grad(geom), cbasis.grad(geom) ).sum(-1) matrix = domain.integrate(A, geometry=geom, ischeme='gauss4') # prepare wall energy right hand side rhs0 = domain.boundary.integrate(mubasis * ewall, geometry=geom, ischeme='gauss4') # construct initial condition if init == 'random': numpy.random.seed(0) c = cbasis.dot(numpy.random.normal(0, .5, cbasis.shape)) elif init == 'bubbles': R1 = .25 R2 = numpy.sqrt(.5) * R1 # area2 = .5 * area1 c = 1 + function.tanh( (R1-function.norm2(geom-(.5+R2/numpy.sqrt(2)+.8*epsilon)))/epsilon ) \ + function.tanh( (R2-function.norm2(geom-(.5-R1/numpy.sqrt(2)-.8*epsilon)))/epsilon ) else: raise Exception('unknown init %r' % init) # prepare plotting nsteps = numeric.round(maxtime / timestep) makeplots = MakePlots(domain, geom, nsteps, video=withplots == 'video') if withplots else lambda *args: None # start time stepping for istep in log.range('timestep', nsteps): Emix = F(c) Eiface = .5 * (c.grad(geom)**2).sum(-1) Ewall = (abs(ewall) + ewall * c) b = cbasis * c - mubasis * f_n(c) rhs, total, energy_mix, energy_iface = domain.integrate( [b, c, Emix, Eiface], geometry=geom, ischeme='gauss4') energy_wall = domain.boundary.integrate(Ewall, geometry=geom, ischeme='gauss4') log.user('concentration {}, energy {}'.format( total, energy_mix + energy_iface + energy_wall)) lhs = matrix.solve(rhs0 + rhs, tol=1e-12, restart=999) c = cbasis.dot(lhs) mu = mubasis.dot(lhs) makeplots(c, mu, energy_mix, energy_iface, energy_wall) return lhs, energy_mix, energy_iface, energy_wall