Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
def mk_mesh(nelems, radius, fname='NACA0015', cylrot=0.0):
    fname = path.join(path.dirname(__file__), f'../data/{fname}.cpts')
    cpts = np.loadtxt(fname) - (0.5, 0.0)

    pspace = np.linspace(0, 2 * np.pi, cpts.shape[0] + 1)
    rspace = np.linspace(0, 1, nelems + 1)
    domain, refgeom = mesh.rectilinear([rspace, pspace], periodic=(1, ))
    basis = domain.basis('spline', degree=3)

    angle = np.linspace(0, 2 * np.pi, cpts.shape[0], endpoint=False) - cylrot
    angle = np.hstack([[angle[-1]], angle[:-1]])
    upts = radius * np.vstack([np.cos(angle), np.sin(angle)]).T

    interp = np.linspace(0, 1, nelems + 3)**3
    cc = np.vstack([(1 - i) * cpts + i * upts for i in interp])
    geom = fn.asarray([basis.dot(cc[:, 0]), basis.dot(cc[:, 1])])

    return domain, refgeom, geom
Esempio n. 4
0
    def __init__(self,
                 refine=1,
                 degree=3,
                 nel_up=None,
                 nel_length=None,
                 stabilize=True):
        if nel_up is None:
            nel_up = int(10 * refine)
        if nel_length is None:
            nel_length = int(100 * refine)

        domain, geom = mesh.multipatch(
            patches=[[[0, 1], [3, 4]], [[3, 4], [6, 7]], [[2, 3], [5, 6]]],
            nelems={
                (0, 1): nel_up,
                (3, 4): nel_up,
                (6, 7): nel_up,
                (2, 5): nel_length,
                (3, 6): nel_length,
                (4, 7): nel_length,
                (0, 3): nel_up,
                (1, 4): nel_up,
                (2, 3): nel_up,
                (5, 6): nel_up,
            },
            patchverts=[[-1, 0], [-1, 1], [0, -1], [0, 0], [0, 1], [1, -1],
                        [1, 0], [1, 1]],
        )

        NutilsCase.__init__(self, 'Backward-facing step channel', domain, geom,
                            geom)

        NU = 1 / self.parameters.add('viscosity', 20, 50)
        L = self.parameters.add('length', 9, 12, 10)
        H = self.parameters.add('height', 0.3, 2, 1)
        V = self.parameters.add('velocity', 0.5, 1.2, 1)

        # Bases
        bases = [
            domain.basis('spline', degree=(degree, degree - 1)),  # vx
            domain.basis('spline', degree=(degree - 1, degree)),  # vy
            domain.basis('spline', degree=degree - 1),  # pressure
        ]
        if stabilize:
            bases.append([0] * 4)
        basis_lens = [len(b) for b in bases]
        vxbasis, vybasis, pbasis, *__ = fn.chain(bases)
        vbasis = vxbasis[:, _] * (1, 0) + vybasis[:, _] * (0, 1)

        self.bases.add('v', vbasis, length=sum(basis_lens[:2]))
        self.bases.add('p', pbasis, length=basis_lens[2])
        self.extra_dofs = 4 if stabilize else 0

        x, y = geom
        hx = fn.piecewise(x, (0, ), 0, x)
        hy = fn.piecewise(y, (0, ), y, 0)
        self.integrals['geometry'] = Affine(
            1.0,
            geom,
            (L - 1),
            fn.asarray((hx, 0)),
            (H - 1),
            fn.asarray((0, hy)),
        )

        self.constrain('v', 'patch0-bottom', 'patch0-top', 'patch0-left',
                       'patch1-top', 'patch2-bottom', 'patch2-left')

        vgrad = vbasis.grad(geom)

        # Lifting function
        profile = fn.max(0, y * (1 - y) * 4)[_] * (1, 0)
        self.integrals['lift'] = Affine(V, self.project_lift(profile, 'v'))

        # Characteristic functions
        cp0, cp1, cp2 = [characteristic(domain, (i, )) for i in range(3)]
        cp12 = cp1 + cp2

        # Stokes divergence term
        self.integrals['divergence'] = AffineIntegral(
            -(H - 1),
            fn.outer(vgrad[:, 0, 0], pbasis) * cp2,
            -(L - 1),
            fn.outer(vgrad[:, 1, 1], pbasis) * cp12,
            -1,
            fn.outer(vbasis.div(geom), pbasis),
        )

        # Stokes laplacian term
        self.integrals['laplacian'] = AffineIntegral(
            NU,
            fn.outer(vgrad).sum([-1, -2]) * cp0,
            NU / L,
            fn.outer(vgrad[:, :, 0]).sum(-1) * cp1,
            NU * L,
            fn.outer(vgrad[:, :, 1]).sum(-1) * cp1,
            NU * H / L,
            fn.outer(vgrad[:, :, 0]).sum(-1) * cp2,
            NU * L / H,
            fn.outer(vgrad[:, :, 1]).sum(-1) * cp2,
        )

        # Navier-stokes convective term
        args = ('ijk', 'wuv')
        kwargs = {'x': geom, 'w': vbasis, 'u': vbasis, 'v': vbasis}
        self.integrals['convection'] = AffineIntegral(
            H,
            NutilsDelayedIntegrand('c w_ia u_j0 v_ka,0',
                                   *args,
                                   **kwargs,
                                   c=cp2),
            L,
            NutilsDelayedIntegrand('c w_ia u_j1 v_ka,1',
                                   *args,
                                   **kwargs,
                                   c=cp12),
            1,
            NutilsDelayedIntegrand('c w_ia u_jb v_ka,b',
                                   *args,
                                   **kwargs,
                                   c=cp0),
            1,
            NutilsDelayedIntegrand('c w_ia u_j0 v_ka,0',
                                   *args,
                                   **kwargs,
                                   c=cp1),
        )

        # Norms
        self.integrals['v-h1s'] = self.integrals['laplacian'] / NU

        self.integrals['v-l2'] = AffineIntegral(
            1,
            fn.outer(vbasis).sum(-1) * cp0,
            L,
            fn.outer(vbasis).sum(-1) * cp1,
            L * H,
            fn.outer(vbasis).sum(-1) * cp2,
        )

        self.integrals['p-l2'] = AffineIntegral(
            1,
            fn.outer(pbasis) * cp0,
            L,
            fn.outer(pbasis) * cp1,
            L * H,
            fn.outer(pbasis) * cp2,
        )

        if not stabilize:
            self.verify
            return

        root = self.ndofs - self.extra_dofs
        terms = []

        points = [(0, (0, 0)), (nel_up - 1, (0, 1))]
        eqn = vbasis.laplace(geom)[:, 0, _]
        colloc = collocate(domain, eqn, points, root, self.ndofs)
        terms.extend([NU, (colloc + colloc.T)])
        eqn = -pbasis.grad(geom)[:, 0, _]
        colloc = collocate(domain, eqn, points, root, self.ndofs)
        terms.extend([1, colloc + colloc.T])

        points = [(nel_up**2 + nel_up * nel_length, (0, 0))]
        eqn = vbasis[:, 0].grad(geom).grad(geom)
        colloc = collocate(domain, eqn[:, 0, 0, _], points, root + 2,
                           self.ndofs)
        terms.extend([NU / L**2, colloc.T])
        colloc = collocate(domain, eqn[:, 1, 1, _], points, root + 2,
                           self.ndofs)
        terms.extend([NU / H**2, colloc])
        eqn = -pbasis.grad(geom)[:, 0, _]
        colloc = collocate(domain, -pbasis.grad(geom)[:, 0, _], points,
                           root + 2, self.ndofs)
        terms.extend([1 / L, colloc])

        points = [(nel_up * (nel_up - 1), (1, 0))]
        colloc = collocate(domain,
                           vbasis.laplace(geom)[:, 0, _], points, root + 3,
                           self.ndofs)
        terms.extend([NU, colloc])
        colloc = collocate(domain, -pbasis.grad(geom)[:, 0, _], points,
                           root + 3, self.ndofs)
        terms.extend([1, colloc])

        self.integrals['stab-lhs'] = AffineIntegral(*terms)

        self.verify()
Esempio n. 5
0
def rotmat(angle):
    return fn.asarray([
        [fn.cos(angle), -fn.sin(angle)],
        [fn.sin(angle), fn.cos(angle)],
    ])
Esempio n. 6
0
def geometry(mu, L, H, refgeom):
    x, y = refgeom
    hx = fn.piecewise(x, (0, ), 0, x)
    hy = fn.piecewise(y, (0, ), y, 0)
    return (refgeom + (L - 1)(mu) * fn.asarray(
        (hx, 0)) + (H - 1)(mu) * fn.asarray((0, hy)))
Esempio n. 7
0
    def __init__(self, refine=1, degree=4, nel=None):
        if nel is None:
            nel = int(10 * refine)

        pts = np.linspace(0, 1, nel + 1)
        domain, geom = mesh.rectilinear([pts, pts])

        NutilsCase.__init__(self, 'Cavity flow', domain, geom, geom)

        bases = [
            domain.basis('spline', degree=(degree, degree - 1)),  # vx
            domain.basis('spline', degree=(degree - 1, degree)),  # vy
            domain.basis('spline', degree=degree - 1),  # pressure
            [1],  # lagrange multiplier
            [0] * 4,  # stabilization terms
        ]
        basis_lens = [len(b) for b in bases]
        vxbasis, vybasis, pbasis, lbasis, __ = fn.chain(bases)
        vbasis = vxbasis[:, _] * (1, 0) + vybasis[:, _] * (0, 1)

        self.bases.add('v', vbasis, length=sum(basis_lens[:2]))
        self.bases.add('p', pbasis, length=basis_lens[2])
        self.extra_dofs = 5

        self.constrain('v', 'left', 'top', 'bottom', 'right')

        self.integrals['lift'] = Affine(1, np.zeros(vbasis.shape[0]))
        self.integrals['geometry'] = Affine(1, geom)

        x, y = geom
        f = 4 * (x - x**2)**2
        g = 4 * (y - y**2)**2
        d1f = f.grad(geom)[0]
        d1g = g.grad(geom)[1]
        velocity = fn.asarray((f * d1g, -d1f * g))
        pressure = d1f * d1g
        total = domain.integrate(pressure * fn.J(geom), ischeme='gauss9')
        pressure -= total / domain.volume(geometry=geom)
        force = pressure.grad(geom) - velocity.laplace(geom)

        self._exact_solutions = {'v': velocity, 'p': pressure}

        self.integrals['forcing'] = AffineIntegral(1, (vbasis *
                                                       force[_, :]).sum(-1))
        self.integrals['divergence'] = AffineIntegral(
            -1, fn.outer(vbasis.div(geom), pbasis))
        self.integrals['laplacian'] = AffineIntegral(
            1,
            fn.outer(vbasis.grad(geom)).sum((-1, -2)))
        self.integrals['v-h1s'] = AffineIntegral(
            1,
            fn.outer(vbasis.grad(geom)).sum([-1, -2]))
        self.integrals['p-l2'] = AffineIntegral(1, fn.outer(pbasis))

        root = self.ndofs - self.extra_dofs

        points = [(0, (0, 0)), (nel - 1, (0, 1)), (nel * (nel - 1), (1, 0)),
                  (nel**2 - 1, (1, 1))]
        eqn = (pbasis.grad(geom) - vbasis.laplace(geom))[:, 0, _]
        colloc = collocate(domain, eqn, points, root + 1, self.ndofs)
        self.integrals['stab-lhs'] = AffineIntegral(1, colloc, 1,
                                                    fn.outer(lbasis, pbasis))
        self.integrals['stab-rhs'] = AffineIntegral(
            1, collocate(domain, force[0, _], points, root + 1, self.ndofs))
Esempio n. 8
0
    def __init__(self, nelems=10, piola=False, degree=2):
        pts = np.linspace(0, 1, nelems + 1)
        domain, geom = mesh.rectilinear([pts, pts])
        NutilsCase.__init__(self, 'Abdulahque Manufactured Solution', domain,
                            geom)

        RE = 1 / self.parameters.add('re', 100.0, 150.0)
        T = self.parameters.add('time', 0.0, 10.0)

        # Add bases and construct a lift function
        vbasis, pbasis = mk_bases(self, piola, degree)
        self.constrain('v', 'bottom')
        # self.constrain('v', 'top')
        # self.constrain('v', 'left')
        # self.constrain('v', 'right')
        self.lift += 1, np.zeros(len(vbasis))

        self['divergence'] -= 1, fn.outer(vbasis.div(geom), pbasis)
        self['divergence'].freeze(lift=(1, ))
        self['laplacian'] += RE, fn.outer(vbasis.grad(geom)).sum((-1, -2))
        self['convection'] += 1, NutilsDelayedIntegrand('w_ia u_jb v_ka,b',
                                                        'ijk',
                                                        'wuv',
                                                        x=geom,
                                                        w=vbasis,
                                                        u=vbasis,
                                                        v=vbasis)

        self['v-h1s'] += 1, fn.outer(vbasis.grad(geom)).sum((-1, -2))
        self['v-l2'] += 1, fn.outer(vbasis).sum((-1, ))
        self['p-l2'] += 1, fn.outer(pbasis)

        # Body force
        x, y = geom
        h = T
        h1 = 1
        f = 4 * (x - x**2)**2
        f1 = f.grad(geom)[0]
        f2 = f1.grad(geom)[0]
        f3 = f2.grad(geom)[0]
        g = 4 * (y - y**2)**2
        g1 = g.grad(geom)[1]
        g2 = g1.grad(geom)[1]
        g3 = g2.grad(geom)[1]

        # Body force
        self['forcing'] += h**2, fn.matmat(
            vbasis,
            fn.asarray([
                (g1**2 - g * g2) * f * f1,
                (f1**2 - f * f2) * g * g1,
            ]))
        self['forcing'] += RE * h, fn.matmat(
            vbasis, fn.asarray([-f * g3, f3 * g + 2 * f1 * g2]))
        self['forcing'] += h1, fn.matmat(vbasis, fn.asarray([f * g1, -f1 * g]))

        # Neumann conditions
        mx = fn.asarray([[f1 * g1, f * g2], [-f2 * g, -f1 * g1]])
        hh = fn.matmat(mx, geom.normal()) - f1 * g1 * geom.normal()
        self['forcing'] += RE * h, NutilsArrayIntegrand(fn.matmat(
            vbasis,
            hh)).prop(domain=domain.boundary['left'] | domain.boundary['right']
                      | domain.boundary['top'])
Esempio n. 9
0
    def __init__(self, refine=1, degree=3, nel_up=None, nel_length=None, nel_up_mid=None,
                 nel_length_out=None, stabilize=True, override=True):
        if nel_up is None:
            nel_up = int(50 * refine)
        if nel_length is None:
            nel_length = int(50 * refine)
        if nel_up_mid is None:
            nel_up_mid = nel_up // 5
        if nel_length_out is None:
            nel_length_out = 2 * nel_length // 5

        domain, geom = mesh.multipatch(
            patches=[[[0,1],[4,5]], [[1,2],[5,6]], [[2,3],[6,7]], [[5,6],[8,9]]],
            nelems={
                (0,1): nel_up, (4,5): nel_up, (2,3): nel_up, (6,7): nel_up,
                (1,2): nel_up_mid, (5,6): nel_up_mid, (8,9): nel_up_mid,
                (0,4): nel_length, (1,5): nel_length, (2,6): nel_length, (3,7): nel_length,
                (5,8): nel_length_out, (6,9): nel_length_out,
            },
            patchverts=[
                [-5,0], [-5,1], [-5,2], [-5,3],
                [0,0], [0,1], [0,2], [0,3],
                [2,1], [2,2],
            ]
        )

        NutilsCase.__init__(self, 'T-shape channel', domain, geom, geom)

        NU = 1 / self.parameters.add('viscosity', 20, 50)
        H = self.parameters.add('height', 1, 5)
        V = self.parameters.add('velocity', 1, 5)

        bases = [
            domain.basis('spline', degree=(degree, degree-1)),  # vx
            domain.basis('spline', degree=(degree-1, degree)),  # vy
            domain.basis('spline', degree=degree-1)             # pressure
        ]
        if stabilize:
            bases.append([0] * 4)
        basis_lens = [len(b) for b in bases]
        vxbasis, vybasis, pbasis, *__ = fn.chain(bases)
        vbasis = vxbasis[:,_] * (1,0) + vybasis[:,_] * (0,1)

        self.bases.add('v', vbasis, length=sum(basis_lens[:2]))
        self.bases.add('p', pbasis, length=basis_lens[2])
        self.extra_dofs = 4 if stabilize else 0

        x, y = geom
        hy = fn.piecewise(y, (1,2), y-1, 0, y-2)
        self.integrals['geometry'] = Affine(1, geom, H - 1, fn.asarray((0, hy)))

        self.constrain(
            'v', 'patch0-bottom', 'patch0-left', 'patch0-right', 'patch1-left',
            'patch2-left', 'patch2-top', 'patch2-right', 'patch3-bottom', 'patch3-top',
        )

        vgrad = vbasis.grad(geom)

        # Lifting function
        profile = fn.max(0, y/3 * (1-y/3) * (1-x))[_] * (1, 0)
        self.integrals['lift'] = Affine(V, self.project_lift(profile, 'v'))

        # Characteristic functions
        cp0, cp1, cp2, cp3 = [characteristic(domain, (i,)) for i in range(4)]
        cp02 = cp0 + cp2
        cp13 = cp1 + cp3

        # Stokes divergence term
        self.integrals['divergence'] = AffineIntegral(
            -(H-1), fn.outer(vgrad[:,0,0], pbasis) * cp02,
            -1, fn.outer(vbasis.div(geom), pbasis),
        )

        # Stokes laplacian term
        self.integrals['laplacian'] = AffineIntegral(
            NU, fn.outer(vgrad).sum([-1,-2]) * cp13,
            NU*H, fn.outer(vgrad[:,:,0]).sum(-1) * cp02,
            NU/H, fn.outer(vgrad[:,:,1]).sum(-1) * cp02,
        )

        # Navier-Stokes convective term
        args = ('ijk', 'wuv')
        kwargs = {'x': geom, 'w': vbasis, 'u': vbasis, 'v': vbasis}
        self.integrals['convection'] = AffineIntegral(
            H, NutilsDelayedIntegrand('c w_ia u_j0 v_ka,0', *args, **kwargs, c=cp02),
            1, NutilsDelayedIntegrand('c w_ia u_j1 v_ka,1', *args, **kwargs, c=cp02),
            1, NutilsDelayedIntegrand('c w_ia u_jb v_ka,b', *args, **kwargs, c=cp13),
        )

        # Norms
        self.integrals['v-h1s'] = self.integrals['laplacian'] / NU
        self.integrals['v-l2'] = AffineIntegral(
            H, fn.outer(vbasis).sum(-1) * cp02,
            1, fn.outer(vbasis).sum(-1) * cp13,
        )
        self.integrals['p-l2'] = AffineIntegral(
            H, fn.outer(pbasis) * cp02,
            1, fn.outer(pbasis) * cp13,
        )

        if not stabilize:
            self.verify()
            return

        root = self.ndofs - self.extra_dofs

        points = [
            (0, (0, 0)),
            (nel_up*(nel_length-1), (1, 0)),
            (nel_up*nel_length + nel_up_mid*nel_length + nel_up - 1, (0, 1)),
            (nel_up*nel_length*2 + nel_up_mid*nel_length - 1, (1, 1))
        ]
        terms = []
        eqn = vbasis[:,0].grad(geom).grad(geom)
        colloc = collocate(domain, eqn[:,0,0,_], points, root, self.ndofs)
        terms.extend([NU, (colloc + colloc.T)])
        colloc = collocate(domain, eqn[:,1,1,_], points, root, self.ndofs)
        terms.extend([NU/H**2, (colloc + colloc.T)])
        eqn = -pbasis.grad(geom)[:,0,_]
        colloc = collocate(domain, eqn, points, root, self.ndofs)
        terms.extend([1, colloc + colloc.T])

        self.integrals['stab-lhs'] = AffineIntegral(*terms)

        self.verify()
Esempio n. 10
0
    def __init__(self, refine=1, degree=3, nel=None, power=3):
        if nel is None:
            nel = int(10 * refine)

        pts = np.linspace(0, 1, nel + 1)
        domain, geom = mesh.rectilinear([pts, pts])
        x, y = geom

        NutilsCase.__init__(self, 'Exact divergence-conforming flow', domain, geom, geom)

        w = self.parameters.add('w', 1, 2)
        h = self.parameters.add('h', 1, 2)

        bases = [
            domain.basis('spline', degree=(degree, degree-1)),  # vx
            domain.basis('spline', degree=(degree-1, degree)),  # vy
            domain.basis('spline', degree=degree-1),            # pressure
            [1],                                                # lagrange multiplier
            [0] * 4,                                            # stabilization terms
        ]
        basis_lens = [len(b) for b in bases]
        vxbasis, vybasis, pbasis, lbasis, __ = fn.chain(bases)
        vbasis = vxbasis[:,_] * (1,0) + vybasis[:,_] * (0,1)

        self.bases.add('v', vbasis, length=sum(basis_lens[:2]))
        self.bases.add('p', pbasis, length=basis_lens[2])
        self.extra_dofs = 5

        self.integrals['geometry'] = Affine(
            1, geom,
            w-1, fn.asarray((x,0)),
            h-1, fn.asarray((0,y)),
        )

        self.constrain('v', 'left', 'top', 'bottom', 'right')

        r = power
        self.power = power

        # Exact solution
        f = x**r
        g = y**r
        f1 = r * x**(r-1)
        g1 = r * y**(r-1)
        g2 = r*(r-1) * y**(r-2)
        f3 = r*(r-1)*(r-2) * x**(r-3)
        g3 = r*(r-1)*(r-2) * y**(r-3)

        self._exact_solutions = {'v': fn.asarray((f*g1, -f1*g)), 'p': f1*g1 - 1}

        # Awkward way of computing a solenoidal lift
        mdom, t = mesh.rectilinear([pts])
        hbasis = mdom.basis('spline', degree=degree)
        hcoeffs = mdom.project(t[0]**r, onto=hbasis, geometry=t, ischeme='gauss9')
        projtderiv = hbasis.dot(hcoeffs).grad(t)[0]
        zbasis = mdom.basis('spline', degree=degree-1)
        zcoeffs = mdom.project(projtderiv, onto=zbasis, geometry=t, ischeme='gauss9')
        q = np.hstack([
            np.outer(hcoeffs, zcoeffs).flatten(),
            - np.outer(zcoeffs, hcoeffs).flatten(),
            np.zeros((sum(basis_lens) - len(hcoeffs) * len(zcoeffs) * 2))
        ])
        self.integrals['lift'] = Affine(w**(r-1) * h**(r-1), q)

        self.integrals['forcing'] = AffineIntegral(
            w**(r-2) * h**(r+2), vybasis * (f3 * g)[_],
            w**r * h**r, 2*vybasis * (f1*g2)[_],
            w**(r+2) * h**(r-2), -vxbasis * (f*g3)[_],
        )

        vx_x = vxbasis.grad(geom)[:,0]
        vx_xx = vx_x.grad(geom)[:,0]
        vx_y = vxbasis.grad(geom)[:,1]
        vx_yy = vx_y.grad(geom)[:,1]
        vy_x = vybasis.grad(geom)[:,0]
        vy_y = vybasis.grad(geom)[:,1]
        p_x = pbasis.grad(geom)[:,0]

        self.integrals['laplacian'] = AffineIntegral(
            h * w, fn.outer(vx_x, vx_x),
            h**3 / w, fn.outer(vy_x, vy_x),
            w**3 / h, fn.outer(vx_y, vx_y),
            w * h, fn.outer(vy_y, vy_y),
        )

        self.integrals['divergence'] = AffineIntegral(
            h * w, (fn.outer(vx_x, pbasis) + fn.outer(vy_y, pbasis))
        )

        self['v-h1s'] = AffineIntegral(self.integrals['laplacian'])
        self['p-l2'] = AffineIntegral(h * w, fn.outer(pbasis, pbasis))

        root = self.ndofs - self.extra_dofs
        points = [(0, (0, 0)), (nel-1, (0, 1)), (nel*(nel-1), (1, 0)), (nel**2-1, (1, 1))]
        ca, cb, cc = [
            collocate(domain, eqn[:,_], points, root+1, self.ndofs)
            for eqn in [p_x, -vx_xx, -vx_yy]
        ]
        self.integrals['stab-lhs'] = AffineIntegral(
            1/w, ca, 1/w, cb, w/h**2, cc, 1, fn.outer(lbasis, pbasis),
            w**3 * h**(r-3), collocate(domain, -f*g3[_], points, root+1, self.ndofs),
        )

        self.integrals['v-trf'] = Affine(
            w, fn.asarray([[1,0], [0,0]]),
            h, fn.asarray([[0,0], [0,1]]),
        )
Esempio n. 11
0
 def exact(self, mu, field):
     scale = mu['w']**(self.power-1) * mu['h']**(self.power-1)
     retval = scale * self._exact_solutions[field]
     if field == 'v':
         return fn.matmat(fn.asarray([[mu['w'], 0], [0, mu['h']]]), retval)
     return retval
Esempio n. 12
0
def main(
    nelems: 'number of elements' = 12,
    viscosity: 'fluid viscosity' = 1e-3,
    density: 'fluid density' = 1,
    degree: 'polynomial degree' = 2,
    warp: 'warp domain (downward bend)' = False,
    tol: 'solver tolerance' = 1e-5,
    maxiter: 'maximum number if iterations, 0 for unlimited' = 0,
    withplots: 'create plots' = True,
  ):

  Re = density / viscosity # based on unit length and velocity
  log.user( 'reynolds number: {:.1f}'.format(Re) )

  # construct mesh
  verts = numpy.linspace( 0, 1, nelems+1 )
  domain, geom = mesh.rectilinear( [verts,verts] )

  # construct bases
  vxbasis, vybasis, pbasis, lbasis = function.chain([
    domain.basis( 'spline', degree=(degree+1,degree), removedofs=((0,-1),None) ),
    domain.basis( 'spline', degree=(degree,degree+1), removedofs=(None,(0,-1)) ),
    domain.basis( 'spline', degree=degree ),
    [1], # lagrange multiplier
  ])
  if not warp:
    vbasis = function.stack( [ vxbasis, vybasis ], axis=1 )
  else:
    gridgeom = geom
    xi, eta = gridgeom
    geom = (eta+2) * function.rotmat(xi*.4)[:,1] - (0,2) # slight downward bend
    J = geom.grad( gridgeom )
    detJ = function.determinant( J )
    vbasis = ( vxbasis[:,_] * J[:,0] + vybasis[:,_] * J[:,1] ) / detJ # piola transform
    pbasis /= detJ
  stressbasis = (2*viscosity) * vbasis.symgrad(geom) - (pbasis)[:,_,_] * function.eye( domain.ndims )

  # construct matrices
  A = function.outer( vbasis.grad(geom), stressbasis ).sum([2,3]) \
    + function.outer( pbasis, vbasis.div(geom)+lbasis ) \
    + function.outer( lbasis, pbasis )
  Ad = function.outer( vbasis.div(geom) )
  stokesmat, divmat = domain.integrate( [ A, Ad ], geometry=geom, ischeme='gauss9' )

  # define boundary conditions
  normal = geom.normal()
  utop = function.asarray([ normal[1], -normal[0] ])
  h = domain.boundary.elem_eval( 1, geometry=geom, ischeme='gauss9', asfunction=True )
  nietzsche = (2*viscosity) * ( ((degree+1)*2.5/h) * vbasis - vbasis.symgrad(geom).dotnorm(geom) )
  stokesmat += domain.boundary.integrate( function.outer( nietzsche, vbasis ).sum(-1), geometry=geom, ischeme='gauss9' )
  rhs = domain.boundary['top'].integrate( ( nietzsche * utop ).sum(-1), geometry=geom, ischeme='gauss9' )

  # prepare plotting
  makeplots = MakePlots( domain, geom ) if withplots else lambda *args: None

  # start picard iterations
  lhs = stokesmat.solve( rhs, tol=tol, solver='cg', precon='spilu' )
  for iiter in log.count( 'picard' ):
    log.info( 'velocity divergence:', divmat.matvec(lhs).dot(lhs) )
    makeplots( vbasis.dot(lhs), pbasis.dot(lhs) )
    ugradu = ( vbasis.grad(geom) * vbasis.dot(lhs) ).sum(-1)
    convection = density * function.outer( vbasis, ugradu ).sum(-1)
    matrix = stokesmat + domain.integrate( convection, ischeme='gauss9', geometry=geom )
    lhs, info = matrix.solve( rhs, lhs0=lhs, tol=tol, info=True, precon='spilu', restart=999 )
    if iiter == maxiter-1 or info.niter == 0:
      break

  return rhs, lhs