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 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 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 rotmat(angle): return fn.asarray([ [fn.cos(angle), -fn.sin(angle)], [fn.sin(angle), fn.cos(angle)], ])
def main(etype: str, btype: str, degree: int, nrefine: int): ''' Adaptively refined Laplace problem on an L-shaped domain. .. arguments:: etype [square] Type of elements (square/triangle/mixed). btype [h-std] Type of basis function (h/th-std/spline), with availability depending on the configured element type. degree [2] Polynomial degree nrefine [5] Number of refinement steps to perform. ''' domain, geom = mesh.unitsquare(2, etype) x, y = geom - .5 exact = (x**2 + y**2)**(1 / 3) * function.cos( function.arctan2(y + x, y - x) * (2 / 3)) domain = domain.trim(exact - 1e-15, maxrefine=0) linreg = util.linear_regressor() with treelog.iter.fraction('level', range(nrefine + 1)) as lrange: for irefine in lrange: if irefine: refdom = domain.refined ns.refbasis = refdom.basis(btype, degree=degree) indicator = refdom.integral( 'd(refbasis_n, x_k) d(u, x_k) J(x)' @ ns, degree=degree * 2).eval(lhs=lhs) indicator -= refdom.boundary.integral( 'refbasis_n d(u, x_k) n(x_k) J(x)' @ ns, degree=degree * 2).eval(lhs=lhs) supp = ns.refbasis.get_support( indicator**2 > numpy.mean(indicator**2)) domain = domain.refined_by(refdom.transforms[supp]) ns = function.Namespace() ns.x = geom ns.basis = domain.basis(btype, degree=degree) ns.u = 'basis_n ?lhs_n' ns.du = ns.u - exact sqr = domain.boundary['trimmed'].integral('u^2 J(x)' @ ns, degree=degree * 2) cons = solver.optimize('lhs', sqr, droptol=1e-15) sqr = domain.boundary.integral('du^2 J(x)' @ ns, degree=7) cons = solver.optimize('lhs', sqr, droptol=1e-15, constrain=cons) res = domain.integral('d(basis_n, x_k) d(u, x_k) J(x)' @ ns, degree=degree * 2) lhs = solver.solve_linear('lhs', res, constrain=cons) ndofs = len(ns.basis) error = domain.integral('<du^2, sum:k(d(du, x_k)^2)>_i J(x)' @ ns, degree=7).eval(lhs=lhs)**.5 rate, offset = linreg.add(numpy.log(len(ns.basis)), numpy.log(error)) treelog.user( 'ndofs: {ndofs}, L2 error: {error[0]:.2e} ({rate[0]:.2f}), H1 error: {error[1]:.2e} ({rate[1]:.2f})' .format(ndofs=len(ns.basis), error=error, rate=rate)) bezier = domain.sample('bezier', 9) x, u, du = bezier.eval(['x', 'u', 'du'] @ ns, lhs=lhs) export.triplot('sol.png', x, u, tri=bezier.tri, hull=bezier.hull) export.triplot('err.png', x, du, tri=bezier.tri, hull=bezier.hull) return ndofs, error, lhs
def main(nelems: int, etype: str, btype: str, degree: int, epsilon: typing.Optional[float], contactangle: float, timestep: float, mtol: float, seed: int, circle: bool, stab: stab): ''' Cahn-Hilliard equation on a unit square/circle. .. arguments:: nelems [20] Number of elements along domain edge. etype [square] Type of elements (square/triangle/mixed). btype [std] Type of basis function (std/spline), with availability depending on the configured element type. degree [2] Polynomial degree. epsilon [] Interface thickness; defaults to an automatic value based on the configured mesh density if left unspecified. contactangle [90] Wall contact angle in degrees. timestep [.01] Time step. mtol [.01] Threshold value for chemical potential peak to peak difference, used as a stop criterion. seed [0] Random seed for the initial condition. circle [no] Select circular domain as opposed to a unit square. stab [linear] Stabilization method (linear/optimal/none). ''' mineps = 1. / nelems if epsilon is None: treelog.info('setting epsilon={}'.format(mineps)) epsilon = mineps elif epsilon < mineps: treelog.warning('epsilon under crititical threshold: {} < {}'.format( epsilon, mineps)) domain, geom = mesh.unitsquare(nelems, etype) bezier = domain.sample('bezier', 5) # sample for plotting ns = function.Namespace() if not circle: ns.x = geom else: angle = (geom - .5) * (numpy.pi / 2) ns.x = function.sin(angle) * function.cos(angle)[[1, 0 ]] / numpy.sqrt(2) ns.epsilon = epsilon ns.ewall = .5 * numpy.cos(contactangle * numpy.pi / 180) ns.cbasis = ns.mbasis = domain.basis('std', degree=degree) ns.c = 'cbasis_n ?c_n' ns.dc = 'cbasis_n (?c_n - ?c0_n)' ns.m = 'mbasis_n ?m_n' ns.F = '.5 (c^2 - 1)^2 / epsilon^2' ns.dF = stab.value ns.dt = timestep nrg_mix = domain.integral('F J(x)' @ ns, degree=7) nrg_iface = domain.integral('.5 sum:k(d(c, x_k)^2) J(x)' @ ns, degree=7) nrg_wall = domain.boundary.integral('(abs(ewall) + c ewall) J(x)' @ ns, degree=7) nrg = nrg_mix + nrg_iface + nrg_wall + domain.integral( '(dF - m dc - .5 dt epsilon^2 sum:k(d(m, x_k)^2)) J(x)' @ ns, degree=7) numpy.random.seed(seed) state = dict(c=numpy.random.normal(0, .5, ns.cbasis.shape), m=numpy.random.normal(0, .5, ns.mbasis.shape)) # initial condition with treelog.iter.plain('timestep', itertools.count()) as steps: for istep in steps: E = sample.eval_integrals(nrg_mix, nrg_iface, nrg_wall, **state) treelog.user( 'energy: {0:.3f} ({1[0]:.0f}% mixture, {1[1]:.0f}% interface, {1[2]:.0f}% wall)' .format(sum(E), 100 * numpy.array(E) / sum(E))) x, c, m = bezier.eval(['x', 'c', 'm'] @ ns, **state) export.triplot('phase.png', x, c, tri=bezier.tri, clim=(-1, 1)) export.triplot('chempot.png', x, m, tri=bezier.tri) if numpy.ptp(m) < mtol: break state['c0'] = state['c'] state = solver.optimize(['c', 'm'], nrg, arguments=state, tol=1e-10) return state