Esempio n. 1
0
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
    domain, geom = mesh.rectilinear([numpy.linspace(0, 1, nelems + 1)] * ndims,
                                    periodic=range(ndims))
    basis = domain.basis('discont', degree=degree)

    # construct initial condition (centered gaussian)
    u = function.exp(-(((geom - .5) * 5)**2).sum(-1))
    lhs = domain.project(u, onto=basis, geometry=geom, ischeme='gauss5')

    # prepare matrix
    timestep = timescale / nelems
    At = (1 / timestep) * function.outer(basis)
    matrix0 = domain.integrate(At, geometry=geom, ischeme='gauss5')

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

    # start time stepping
    for itime in log.count('timestep'):
        makeplots(u)
        if endtime and itime * timestep >= endtime:
            break
        rhs = matrix0.matvec(lhs)
        for ipicard in log.count('picard'):
            u = basis.dot(lhs)
            beta = function.repeat(u[_], ndims, axis=0)
            Am = -function.outer((basis[:, _] * beta).div(geom), basis)
            dmatrix = domain.integrate(Am, geometry=geom, ischeme='gauss5')
            alpha = .5 * function.sign(function.mean(beta).dotnorm(geom))
            Ai = function.outer(
                function.jump(basis),
                (alpha * function.jump(basis[:, _] * beta) -
                 function.mean(basis[:, _] * beta)).dotnorm(geom))
            dmatrix += domain.interfaces.integrate(Ai,
                                                   geometry=geom,
                                                   ischeme='gauss5')
            lhs, info = (matrix0 + dmatrix).solve(rhs,
                                                  lhs0=lhs,
                                                  tol=tol,
                                                  restart=999,
                                                  precon='spilu',
                                                  info=True)
            if info.niter == 0:
                break

    return rhs, lhs
Esempio n. 2
0
    def __init__(self, refine=1, degree=3, nel=None):
        if nel is None:
            nel = int(10 * refine)

        xpts = np.linspace(0, 2, 2 * nel + 1)
        ypts = np.linspace(0, 1, nel + 1)
        domain, geom = mesh.rectilinear([xpts, ypts])

        NutilsCase.__init__(self, 'Channel 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
            [0] * 2,  # stabilization terms
        ]
        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 = 2

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

        x, y = geom
        profile = (y * (1 - y))[_] * (1, 0)
        self.integrals['lift'] = Affine(1, self.project_lift(profile, 'v'))
        self.integrals['geometry'] = Affine(1, geom)

        self._exact_solutions = {'v': profile, 'p': 4 - 2 * x}

        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))
        self.integrals['convection'] = AffineIntegral(
            1,
            NutilsDelayedIntegrand('w_ia u_jb v_ka,b',
                                   'ijk',
                                   'wuv',
                                   x=geom,
                                   w=vbasis,
                                   u=vbasis,
                                   v=vbasis))

        points = [(0, (0, 0)), (nel - 1, (0, 1))]
        eqn = (vbasis.laplace(geom) - pbasis.grad(geom))[:, 0, _]
        self.integrals['stab-lhs'] = AffineIntegral(
            1,
            collocate(domain, eqn, points, self.ndofs - self.extra_dofs,
                      self.ndofs))
Esempio n. 3
0
    def __init__(self, physical, n, p):
        """ __init__(self, physical, n, p)
        Constructor for finite element object
        :param physical : (width, height) of physical domain
        :param n        : (n1,n2), number of elements in computational domain
        :param p        : (p1,p2), polynomial degree of compuational discretization
        """
        # create splipy object
        splinesurf = splines.square() * physical
        splinesurf.reparam((0, physical[0]), (0, physical[1]))
        splinesurf.raise_order(p[0] - 1, p[1] - 1)
        splinesurf.refine(n[0] - 1, n[1] - 1)

        # create nutils mesh
        domain, geom = mesh.rectilinear(splinesurf.knots())
        basis = domain.basis('spline', degree=p)

        # pre-compute all system matrices
        derivs = function.outer(basis.grad(geom), basis.grad(geom))
        laplace = derivs[:, :, 0] + derivs[:, :, 1]
        A = domain.integrate(laplace, geometry=geom, ischeme='gauss3')
        M = domain.integrate(function.outer(basis, basis),
                             geometry=geom,
                             ischeme='gauss3')
        # print(M.toarray())

        # pre-compute evaluation matrices
        self.Nu = splinesurf.bases[0].evaluate(
            np.linspace(splinesurf.start('u'), splinesurf.end('u'),
                        physical[0]))
        self.Nv = splinesurf.bases[1].evaluate(
            np.linspace(splinesurf.start('v'), splinesurf.end('v'),
                        physical[1]))

        # store all nutils object as class variables
        self.splinesurf = splinesurf
        self.domain = domain
        self.geom = geom
        self.basis = basis
        self.A = A.toscipy() * 1e2
        self.M = M.toscipy()
        self.u = np.matrix(np.zeros((A.shape[0], 1)))
        self.b = np.matrix(np.zeros((A.shape[0], 1)))

        self.n = np.array(n)
        self.p = np.array(p)
        self.physical = np.array(physical)
        self.time = {
            'add_smoke': 0,
            'get_img': 0,
            'stop_smoke': 0,
            'diffuse': 0,
            'solve': 0
        }
Esempio n. 4
0
class Mass(MuCallable):

    _ident_ = 'Mass'

    def __init__(self, n, basisname, *deps, scale=1):
        super().__init__((n, n), deps, scale=scale)
        self.basisname = basisname

    def write(self, group):
        super().write(group)
        util.to_dataset(self.basisname, group, 'basisname')

    def _read(self, group):
        super()._read(group)
        self.basisname = util.from_dataset(group['basisname'])

    def evaluate(self, case, mu, cont):
        geom = case['geometry'](mu)
        basis = case.basis(self.basisname, mu)
        itg = fn.outer(basis)
        if basis.ndim > 1:
            itg = itg.sum([-1])
        itg = util.contract(itg, cont)
        with matrix.Scipy():
            return unwrap(case.domain.integrate(itg * fn.J(geom), ischeme='gauss9'))
Esempio n. 5
0
 def setUp(self):
     super().setUp()
     domain, geom = mesh.rectilinear([numpy.linspace(0, 1, 9)] * 2)
     ubasis = domain.basis('std', degree=2)
     if self.vector:
         u = ubasis.vector(2).dot(
             function.Argument('dofs', [len(ubasis) * 2]))
     else:
         u = (ubasis[:, numpy.newaxis] *
              function.Argument('dofs', [len(ubasis), 2])).sum(0)
     Geom = geom * [1.1, 1] + u
     self.cons = solver.optimize('dofs',
                                 domain.boundary['left,right'].integral(
                                     (u**2).sum(0), degree=4),
                                 droptol=1e-15)
     self.boolcons = ~numpy.isnan(self.cons)
     strain = .5 * (function.outer(Geom.grad(geom), axis=1).sum(0) -
                    function.eye(2))
     self.energy = domain.integral(
         ((strain**2).sum([0, 1]) + 20 *
          (function.determinant(Geom.grad(geom)) - 1)**2) *
         function.J(geom),
         degree=6)
     self.residual = self.energy.derivative('dofs')
     self.tol = 1e-10
Esempio n. 6
0
 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)
Esempio n. 7
0
def poisson_patch(bottom, right, top, left):
    from nutils import version
    if version != '3.0':
        raise ImportError('Outdated nutils version detected, only v3.0 supported. Upgrade by \"pip install --upgrade nutils\"')

    from nutils import mesh, function as fn
    from nutils import _, log

    # error test input
    if left.rational or right.rational or top.rational or bottom.rational:
        raise RuntimeError('poisson_patch not supported for rational splines')

    # these are given as a oriented loop, so make all run in positive parametric direction
    top.reverse()
    left.reverse()

    # in order to add spline surfaces, they need identical parametrization
    Curve.make_splines_identical(top, bottom)
    Curve.make_splines_identical(left, right)

    # create computational (nutils) mesh
    p1 = bottom.order(0)
    p2 = left.order(0)
    n1 = len(bottom)
    n2 = len(left)
    dim= left.dimension
    k1 = bottom.knots(0)
    k2 = left.knots(0)
    m1 = [bottom.order(0) - bottom.continuity(k) - 1 for k in k1]
    m2 = [left.order(0)   - left.continuity(k)   - 1 for k in k2]
    domain, geom = mesh.rectilinear([k1, k2])
    basis = domain.basis('spline', [p1-1, p2-1], knotmultiplicities=[m1,m2])

    # assemble system matrix
    grad      = basis.grad(geom)
    outer     = fn.outer(grad,grad)
    integrand = outer.sum(-1)
    matrix = domain.integrate(integrand, geometry=geom, ischeme='gauss'+str(max(p1,p2)+1))

    # initialize variables
    controlpoints = np.zeros((n1,n2,dim))
    rhs           = np.zeros((n1*n2))
    constraints = np.array([[np.nan]*n2]*n1)

    # treat all dimensions independently
    for d in range(dim):
        # add boundary conditions
        constraints[ 0, :] = left[  :,d]
        constraints[-1, :] = right[ :,d]
        constraints[ :, 0] = bottom[:,d]
        constraints[ :,-1] = top[   :,d]

        # solve system
        lhs = matrix.solve(rhs, constrain=np.ndarray.flatten(constraints), solver='cg', tol=state.controlpoint_absolute_tolerance)

        # wrap results into splipy datastructures
        controlpoints[:,:,d] = np.reshape(lhs, (n1,n2), order='C')

    return Surface(bottom.bases[0], left.bases[0], controlpoints, bottom.rational, raw=True)
Esempio n. 8
0
    def __init__(self, nelems=60, rmin=1, rmax=10, piola=True):
        domain, refgeom, geom = mk_mesh(nelems, nelems, rmin, rmax)
        NutilsCase.__init__(self, 'ALE Flow around cylinder', domain, geom)
        self._refgeom = refgeom

        V = self.parameters.add('velocity', 1.0, 20.0)
        NU = 1 / self.parameters.add('viscosity', 100.0, 150.0)
        TIME = self.parameters.add('time', 0.0, 25.0, default=0.0)

        self.geometry += 1, geom

        # Add bases and construct a lift function
        vbasis, pbasis = mk_bases(self, piola)
        mk_lift(self, V, None, TIME)

        self['divergence'] -= 1, fn.outer(vbasis.div(geom), pbasis)
        self['divergence'].freeze(lift=(1, ))
        self['laplacian'] += NU, 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['convection'] += 0.5, NutilsDelayedIntegrand(
        #     'w_ia u_jb v_ka,b - w_ia,b u_jb v_ka', 'ijk', 'wuv',
        #     x=geom, w=vbasis, u=vbasis, v=vbasis
        # )

        # self['convection'] += 0.5, NutilsDelayedIntegrand(
        #     '(w_il v_kl) u_jm n_m', 'ijk', 'wuv',
        #     n=geom.normal(), x=geom, w=vbasis, u=vbasis, v=vbasis,
        # ).prop(domain=domain.boundary['left'])

        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)

        # forcing = fn.matmat(vbasis, fn.asarray([0, 1]))
        # self['forcing'] += FREQ**2 * (FREQ * TIME).sin(), forcing

        mk_force(self, geom, vbasis, pbasis)
Esempio n. 9
0
def test_laplacian_matrix(mu, case):
    vbasis, pbasis = case.bases['v'].obj, case.bases['p'].obj
    trfgeom = case.geometry(mu)

    itg = fn.outer(vbasis.grad(trfgeom)).sum([-1, -2])
    phys_mx = case.domain.integrate(itg * fn.J(trfgeom), ischeme='gauss9')

    test_mx = case['laplacian'](mu)
    np.testing.assert_almost_equal(phys_mx.export('dense'), test_mx.toarray())
Esempio n. 10
0
def test_divergence_matrix(mu, case):
    vbasis, pbasis = case.bases['v'].obj, case.bases['p'].obj
    trfgeom = case.geometry(mu)

    itg = -fn.outer(vbasis.div(trfgeom), pbasis)
    phys_mx = case.domain.integrate(itg * fn.J(trfgeom), ischeme='gauss9')

    test_mx = case['divergence'](mu)
    np.testing.assert_almost_equal(phys_mx.export('dense'), test_mx.toarray())
Esempio n. 11
0
def test_mass_matrix(mu, case):
    p_vbasis, p_pbasis = piola_bases(mu, case)
    trfgeom = case.geometry(mu)

    itg = fn.outer(p_vbasis.grad(trfgeom)).sum([-1, -2])
    phys_mx = case.domain.integrate(itg * fn.J(trfgeom), ischeme='gauss9')

    test_mx = case['v-h1s'](mu)
    np.testing.assert_almost_equal(phys_mx.export('dense'), test_mx.toarray())
Esempio n. 12
0
 def setUp(self):
   super().setUp()
   domain, geom = mesh.rectilinear([numpy.linspace(0,1,9)] * 2)
   ubasis = domain.basis('std', degree=2).vector(2)
   u = ubasis.dot(function.Argument('dofs', [len(ubasis)]))
   Geom = geom * [1.1, 1] + u
   self.cons = solver.minimize('dofs', domain.boundary['left,right'].integral((u**2).sum(0), degree=4), droptol=1e-15).solve()
   self.boolcons = ~numpy.isnan(self.cons)
   strain = .5 * (function.outer(Geom.grad(geom), axis=1).sum(0) - function.eye(2))
   self.energy = domain.integral(((strain**2).sum([0,1]) + 20*(function.determinant(Geom.grad(geom))-1)**2)*function.J(geom), degree=6)
   self.residual = self.energy.derivative('dofs')
   self.tol = 1e-10
Esempio n. 13
0
class NSDivergence(MuCallable):

    _ident_ = 'NSDivergence'

    def __init__(self, n, *deps, scale=1):
        super().__init__((n, n), deps, scale=scale)

    def evaluate(self, case, mu, cont):
        geom = case['geometry'](mu)
        vbasis = case.basis('v', mu)
        pbasis = case.basis('p', mu)
        itg = -fn.outer(vbasis.div(geom), pbasis)
        itg = util.contract(itg, cont)
        with matrix.Scipy():
            return unwrap(case.domain.integrate(itg * fn.J(geom), ischeme='gauss9'))
Esempio n. 14
0
 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)
Esempio n. 15
0
def main(
    nelems: 'number of elements' = 12,
    lmbda: 'first lamé constant' = 1.,
    mu: 'second lamé constant' = 1.,
    degree: 'polynomial degree' = 2,
    withplots: 'create plots' = True,
    solvetol: 'solver tolerance' = 1e-10,
):

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

    # prepare basis
    dbasis = domain.basis('spline', degree=degree).vector(2)

    # construct matrix
    stress = library.Hooke(lmbda=lmbda, mu=mu)
    elasticity = function.outer(dbasis.grad(geom),
                                stress(dbasis.symgrad(geom))).sum([2, 3])
    matrix = domain.integrate(elasticity, geometry=geom, ischeme='gauss2')

    # construct dirichlet boundary constraints
    cons = domain.boundary['left'].project( 0, geometry=geom, onto=dbasis, ischeme='gauss2' ) \
         | domain.boundary['right'].project( .5, geometry=geom, onto=dbasis.dotnorm(geom), ischeme='gauss2' )

    # solve system
    lhs = matrix.solve(constrain=cons,
                       tol=solvetol,
                       symmetric=True,
                       precon='diag')

    # construct solution function
    disp = dbasis.dot(lhs)

    # plot solution
    if withplots:
        makeplots(domain, geom + disp, stress(disp.symgrad(geom)))

    return lhs, cons
Esempio n. 16
0
        npts = len(velocity) // 2
        velocity = velocity[:npts]
        pressure = pressure[:npts]

        linbasis = case.domain.basis('spline', degree=1)
        vsol = linbasis.dot(velocity[:,0])[_] * (1,0) + linbasis.dot(velocity[:,1])[_] * (0,1)
        psol = linbasis.dot(pressure)
        geom = case.physical_geometry(param)

        vbasis = case.basis('v', param)
        vgrad = vbasis.grad(geom)
        pbasis = case.basis('p', param)
        lhs = case.domain.project(psol, onto=pbasis, geometry=geom, ischeme='gauss9')

        vind = case.basis_indices('v')
        itg = fn.outer(vbasis).sum([-1]) + fn.outer(vgrad).sum([-1,-2])
        with matrix.Scipy():
            mx = case.domain.integrate(itg * fn.J(geom), ischeme='gauss9').core[np.ix_(vind,vind)]
        itg = (vbasis * vsol[_,:]).sum([-1]) + (vgrad * vsol.grad(geom)[_,:,:]).sum([-1,-2])
        rhs = case.domain.integrate(itg * fn.J(geom), ischeme='gauss9')[vind]
        lhs[vind] = matrix.ScipyMatrix(mx).solve(rhs)

        lift = case._lift(param)
        solutions.append((lhs - lift) * weight)

    solutions = np.array(solutions)
    supremizers = ens.make_ensemble(
        case, solvers.supremizer, scheme, weights=False, parallel=False, args=[solutions],
    )
    return scheme, solutions, supremizers
Esempio n. 17
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. 18
0
    def __init__(self,
                 nel=10,
                 L=15,
                 penalty=1e10,
                 ratio=1000,
                 override=False,
                 finalize=True):
        L /= 5
        hnel = int(L * 5 * nel // 2)

        xpts = np.linspace(0, L, 2 * hnel + 1)
        yzpts = np.linspace(0, 0.2, nel + 1)
        domain, geom = mesh.rectilinear([xpts, yzpts])
        dom1 = domain[:hnel, :]
        dom2 = domain[hnel:, :]

        NutilsCase.__init__(self, 'Elastic split beam', domain, geom)

        E1 = self.parameters.add('ymod1', 1e10, 9e10)
        E2 = self.parameters.add('ymod2', 1e10 / ratio, 9e10 / ratio)
        NU = self.parameters.add('prat', 0.25, 0.42)
        F1 = self.parameters.add('force1', -1e8, 1e8)

        mults = [[2] + [1] * (hnel - 1) + [2] + [1] * (hnel - 1) + [2],
                 [2] + [1] * (nel - 1) + [2]]
        basis = domain.basis('spline', degree=1,
                             knotmultiplicities=mults).vector(2)
        blen = len(basis)
        basis, *__ = fn.chain([basis, [0] * (2 * (nel + 1))])
        self.bases.add('u', basis, length=blen)
        self.extra_dofs = (nel + 1) * 2

        self.lift += 1, np.zeros((len(basis), ))
        self.constrain('u', 'left')
        self.constrain('u', 'right')

        MU1 = E1 / (1 + NU)
        MU2 = E2 / (1 + NU)
        LAMBDA1 = E1 * NU / (1 + NU) / (1 - 2 * NU)
        LAMBDA2 = E2 * NU / (1 + NU) / (1 - 2 * NU)

        itg_mu = fn.outer(basis.symgrad(geom)).sum([-1, -2])
        itg_la = fn.outer(basis.div(geom))

        self['stiffness'] += MU1, NutilsArrayIntegrand(itg_mu).prop(
            domain=dom1)
        self['stiffness'] += MU2, NutilsArrayIntegrand(itg_mu).prop(
            domain=dom2)
        self['stiffness'] += LAMBDA1, NutilsArrayIntegrand(itg_la).prop(
            domain=dom1)
        self['stiffness'] += LAMBDA2, NutilsArrayIntegrand(itg_la).prop(
            domain=dom2)

        # Penalty term ... quite hacky
        K = blen // 2
        ldofs = list(range(hnel * (nel + 1), (hnel + 1) * (nel + 1)))
        rdofs = list(range((hnel + 1) * (nel + 1), (hnel + 2) * (nel + 1)))
        ldofs += [k + K for k in ldofs]
        rdofs += [k + K for k in rdofs]
        L = len(ldofs)
        Linds = list(range(self.ndofs - L, self.ndofs))
        pen = sp.coo_matrix(((np.ones(L), (Linds, ldofs))),
                            shape=(self.ndofs, self.ndofs))
        pen += sp.coo_matrix(((-np.ones(L), (Linds, rdofs))),
                             shape=(self.ndofs, self.ndofs))
        self['penalty'] += 1, ScipyArrayIntegrand(sp.csc_matrix(pen + pen.T))

        # Even more hacky for the ROM part
        bnd_lft = domain[:hnel, :].boundary['right']
        bnd_rgt = domain[hnel:, :].boundary['left']
        pts, wts = bnd_lft.elements[0].reference.getischeme('gauss5')
        penalty_mx = np.zeros((self.ndofs, self.ndofs))
        for el_lft, el_rgt in zip(bnd_lft.elements, bnd_rgt.elements):
            udiff = (
                basis.eval(_points=pts,
                           _transforms=(el_lft.transform, el_lft.opposite)) -
                basis.eval(_points=pts,
                           _transforms=(el_rgt.transform, el_rgt.opposite)))
            penalty_mx += (udiff[:, :, _, :] * udiff[:, _, :, :] *
                           wts[:, _, _, _]).sum((0, -1))
        self['penalty-rom'] += 1e20, sp.csc_matrix(penalty_mx)

        normdot = fn.matmat(basis, geom.normal())
        force_bnd = domain[hnel - 11:hnel - 1, :].boundary['top']
        self['forcing'] += F1, NutilsArrayIntegrand(normdot).prop(
            domain=force_bnd)

        self['u-h1s'] = self['stiffness']
        self['u-h1s-l'] = self['stiffness']
        self['u-h1s-r'] = self['stiffness']
        self['u-h1s-e'] = self['stiffness']

        self.verify()
Esempio n. 19
0
    def __init__(self,
                 nel=10,
                 ndim=2,
                 L=15,
                 override=False,
                 finalize=True,
                 graded=False):
        L /= 5
        if graded:
            # HACK!
            xpts = _graded(0, L, int(L * 3 * nel + 1), 1.04)
            yzpts = _graded(0, 0.1, nel // 2 + 1, 1.3)
            yzpts = np.hstack([yzpts[:-1], 0.2 - yzpts[::-1]])
        else:
            xpts = np.linspace(0, L, int(L * 5 * nel + 1))
            yzpts = np.linspace(0, 0.2, nel + 1)
        if ndim == 2:
            domain, geom = mesh.rectilinear([xpts, yzpts])
        else:
            domain, geom = mesh.rectilinear([xpts, yzpts, yzpts])

        NutilsCase.__init__(self, 'Elastic beam', domain, geom)

        E = self.parameters.add('ymod', 1e10, 9e10)
        NU = self.parameters.add('prat', 0.25, 0.42)
        F1 = self.parameters.add('force1', -0.4e6, 0.4e6)
        F2 = self.parameters.add('force2', -0.2e6, 0.2e6)
        if ndim == 3:
            F3 = self.parameters.add('force3', -0.2e6, 0.2e6)

        basis = domain.basis('spline', degree=1).vector(ndim)
        self.bases.add('u', basis, length=len(basis))
        self.lift += 1, np.zeros((len(basis), ))
        self.constrain('u', 'left')

        MU = E / (1 + NU)
        LAMBDA = E * NU / (1 + NU) / (1 - 2 * NU)
        self['stiffness'] += MU, fn.outer(basis.symgrad(geom)).sum([-1, -2])
        self['stiffness'] += LAMBDA, fn.outer(basis.div(geom))

        normdot = fn.matmat(basis, geom.normal())

        irgt = NutilsArrayIntegrand(normdot).prop(
            domain=domain.boundary['right'])
        ibtm = NutilsArrayIntegrand(normdot).prop(
            domain=domain.boundary['bottom'])
        itop = NutilsArrayIntegrand(normdot).prop(
            domain=domain.boundary['top'])
        self['forcing'] += F1, irgt
        self['forcing'] -= F2, ibtm
        self['forcing'] += F2, itop

        if ndim == 3:
            ifrt = NutilsArrayIntegrand(normdot).prop(
                domain=domain.boundary['front'])
            ibck = NutilsArrayIntegrand(normdot).prop(
                domain=domain.boundary['back'])
            self['forcing'] -= F3, ifrt
            self['forcing'] += F3, ibck

        self['u-h1s'] += 1, fn.outer(basis.grad(geom)).sum([-1, -2])

        self.verify()
Esempio n. 20
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. 21
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. 22
0
def metric_tensor(g, c):
    jacT = function.transpose(jacobian(g, c))
    return function.outer(jacT, jacT).sum(-1)
Esempio n. 23
0
@pytest.fixture
def mu():
    return {
        'viscosity': 1.0,
        'length': 10.0,
        'height': 1.5,
        'velocity': 1.0,
    }


def test_divergence_matrix(case, mu):
    domain, vbasis, pbasis = case.domain, case.bases['v'].obj, case.bases[
        'p'].obj
    geom = case.geometry(mu)

    itg = -fn.outer(vbasis.div(geom), pbasis)
    phys_mx = domain.integrate(itg * fn.J(geom),
                               ischeme='gauss9').export('dense')
    test_mx = case['divergence'](mu).toarray()

    np.testing.assert_almost_equal(phys_mx, test_mx)


def test_laplacian_matrix(case, mu):
    domain, vbasis, pbasis = case.domain, case.bases['v'].obj, case.bases[
        'p'].obj
    geom = case.geometry(mu)

    itg = fn.outer(vbasis.grad(geom)).sum([-1, -2]) / mu['viscosity']
    phys_mx = domain.integrate(itg * fn.J(geom),
                               ischeme='gauss9').export('dense')
Esempio n. 24
0
        ]

    vnbasis, vtbasis, pbasis = fn.chain(bases)
    vbasis = vnbasis + vtbasis

    case.bases.add('v', vbasis, length=len(bases[0]) + len(bases[1]))
    case.bases.add('p', pbasis, length=len(bases[2]))

    return vbasis, pbasis


def mk_force(case, geom, vbasis, pbasis):
    domain = case.domain

    with matrix.Scipy():
        lapl = domain.integrate(fn.outer(vbasis.grad(geom)).sum((-1, -2)),
                                geometry=geom,
                                ischeme='gauss9')
        zero = np.zeros((lapl.shape[0], ))

        xcons = domain.boundary['bottom'].project((1, 0),
                                                  onto=vbasis,
                                                  geometry=geom,
                                                  ischeme='gauss9')
        xcons[np.where(np.isnan(xcons))] = 0.0

        ycons = domain.boundary['bottom'].project((0, 1),
                                                  onto=vbasis,
                                                  geometry=geom,
                                                  ischeme='gauss9')
        ycons[np.where(np.isnan(ycons))] = 0.0
Esempio n. 25
0
def elliptic_control_mapping(g,
                             f,
                             eps=1e-4,
                             ltol=1e-5,
                             degree=None,
                             **solveargs):
    '''
        Nutils implementation of the corresponding method from the ``fsol`` module.
        It's slower but accepts any control mapping function. Unline in the ``fsol``
        case, all derivatives are computed automatically.
    '''

    assert len(g) == len(f) == 2
    assert eps >= 0

    if degree is None:
        degree = 4 * g.ischeme

    if isinstance(f, go.TensorGridObject):
        if not (f.knotvector <= g.knotvector).all():
            raise AssertionError('''
                    Error, the control-mapping knotvector needs
                    to be a subset of the target GridObject knotvector
                ''')

        # refine, just in case
        f = go.refine_GridObject(f, g.knotvector)
        G = metric_tensor(g, f.x)
    else:
        # f is a nutils function
        jacT = function.transpose(f.grad(g.geom))
        G = function.outer(jacT, jacT).sum(-1)

    target = function.Argument('target', [len(g.x)])
    basis = g.basis.vector(2)
    x = basis.dot(target)

    (g11, g12), (g21, g22) = metric_tensor(g, target)
    lapl = g22 * x.grad(g.geom)[:, 0].grad(g.geom)[:, 0] - \
        2 * g12 * x.grad(g.geom)[:, 0].grad(g.geom)[:, 1] + \
        g11 * x.grad(g.geom)[:, 1].grad(g.geom)[:, 1]

    G_tilde = G / function.sqrt(function.determinant(G))
    (G11, G12), (G12, G22) = G_tilde

    P = g11 * G12.grad(g.geom)[1] - g12 * G11.grad(g.geom)[1]
    Q = 0.5 * (g11 * G22.grad(g.geom)[0] - g22 * G11.grad(g.geom)[0])
    S = g12 * G22.grad(g.geom)[0] - g22 * G12.grad(g.geom)[0]
    R = 0.5 * (g11 * G22.grad(g.geom)[1] - g22 * G11.grad(g.geom)[1])

    control_term = -x.grad( g.geom )[:, 0] * ( G22*(P-Q) + G12*(S-R) ) \
                   -x.grad( g.geom )[:, 1] * ( G11*(R-S) + G12*(Q-P) )

    scale = g11 + g22 + eps

    res = g.domain.integral((basis * (control_term + lapl)).sum(-1) / scale,
                            geometry=g.geom,
                            degree=degree)

    init, cons = g.x, g.cons
    lhs = solver.newton('target', res, lhs0=init,
                        constrain=cons.where).solve(ltol, **solveargs)

    g.x = lhs
Esempio n. 26
0
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,
    withplots: 'create plots' = True,
  ):

  uinf = numpy.array([ 1, 0 ])
  log.user( 'reynolds number:', density/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, gridgeom = mesh.rectilinear( [range(melems+1),numpy.linspace(0,2*numpy.pi,2*nelems+1)], periodic=(1,) )
  rho, phi = gridgeom
  phi += 1e-3 # tiny nudge (0.057 deg) to break element symmetry
  cylvelo = -.5 * rotation * function.trignormal(phi)
  radius = .5 * function.exp( rscale * rho )
  geom = radius * function.trigtangent(phi)

  # prepare bases
  J = geom.grad( gridgeom )
  detJ = function.determinant( J )
  vnbasis, vtbasis, pbasis = function.chain([ # compatible spaces using piola transformation
    domain.basis( 'spline', degree=(3,2), removedofs=((0,),None) )[:,_] * J[:,0] / detJ,
    domain.basis( 'spline', degree=(2,3) )[:,_] * J[:,1] / detJ,
    domain.basis( 'spline', degree=2 ) / detJ,
  ])
  vbasis = vnbasis + vtbasis
  stressbasis = (2*viscosity) * vbasis.symgrad(geom) - pbasis[:,_,_] * function.eye( domain.ndims )

  # prepare matrices
  A = function.outer( vbasis.grad(geom), stressbasis ).sum([2,3]) + function.outer( pbasis, vbasis.div(geom) )
  Ao = function.outer( vbasis, density * ( vbasis.grad(geom) * uinf ).sum(-1) ).sum(-1)
  At = (density/timestep) * function.outer( vbasis ).sum(-1)
  Ad = function.outer( vbasis.div(geom) )
  stokesmat, uniconvec, inertmat, divmat = domain.integrate( [ A, Ao, At, Ad ], geometry=geom, ischeme='gauss9' )

  # interior boundary condition (weak imposition of shear verlocity component)
  inner = domain.boundary['left']
  h = inner.elem_eval( 1, geometry=geom, ischeme='gauss9', asfunction=True )
  nietzsche = (2*viscosity) * ( (7.5/h) * vbasis - vbasis.symgrad(geom).dotnorm(geom) )
  B = function.outer( nietzsche, vbasis ).sum(-1)
  b = ( nietzsche * cylvelo ).sum(-1)
  bcondmat, rhs = inner.integrate( [ B, b ], geometry=geom, ischeme='gauss9' )
  stokesmat += bcondmat

  # exterior boundary condition (full velocity vector imposed at inflow)
  inflow = domain.boundary['right'].select( -( uinf * geom.normal() ).sum(-1), ischeme='gauss1' )
  cons = inflow.project( uinf, onto=vbasis, geometry=geom, ischeme='gauss9', tol=1e-12 )

  # initial condition (stationary oseen flow)
  lhs = (stokesmat+uniconvec).solve( rhs, constrain=cons, tol=0 )

  # prepare plotting
  if not withplots:
    makeplots = lambda *args: None
  else:
    makeplots = MakePlots( domain, geom, video=withplots=='video', timestep=timestep )
    mesh_ = domain.elem_eval( geom, ischeme='bezier5', separate=True )
    inflow_ = inflow.elem_eval( geom, ischeme='bezier5', separate=True )
    with plot.PyPlot( 'mesh', ndigits=0 ) as plt:
      plt.mesh( mesh_ )
      plt.rectangle( makeplots.bbox[:,0], *( makeplots.bbox[:,1] - makeplots.bbox[:,0] ), ec='green' )
      plt.segments( inflow_, colors='red' )

  # start time stepping
  stokesmat += inertmat
  precon = (stokesmat+uniconvec).getprecon( 'splu', constrain=cons )
  for istep in log.count( 'timestep', start=1 ):
    log.info( 'velocity divergence:', divmat.matvec(lhs).dot(lhs) )
    convection = density * ( vbasis.grad(geom) * vbasis.dot(lhs) ).sum(-1)
    matrix = stokesmat + domain.integrate( function.outer( vbasis, convection ).sum(-1), ischeme='gauss9', geometry=geom )
    lhs = matrix.solve( rhs + inertmat.matvec(lhs), lhs0=lhs, constrain=cons, tol=tol, restart=9999, precon=precon )
    makeplots( vbasis.dot(lhs), pbasis.dot(lhs), istep*timestep*rotation )
    if istep*timestep > tmax:
      break

  return lhs
Esempio n. 27
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. 28
0
    vbasis, pbasis = case.bases['v'].obj, case.bases['p'].obj

    with matrix.Scipy():
        cons = domain.boundary['left'].project((0, 0),
                                               onto=vbasis,
                                               geometry=geom,
                                               ischeme='gauss1')
        cons_x = domain.boundary['right'].select(-x).project(
            (1, 0),
            onto=vbasis,
            geometry=geom,
            ischeme='gauss9',
            constrain=cons,
        )

    mx = fn.outer(vbasis.grad(geom)).sum([-1, -2])
    mx -= fn.outer(pbasis, vbasis.div(geom))
    mx -= fn.outer(vbasis.div(geom), pbasis)
    with matrix.Scipy():
        mx = domain.integrate(mx, geometry=geom, ischeme='gauss9')
    rhs = np.zeros(pbasis.shape)

    lhs_x = mx.solve(rhs, constrain=cons_x)
    lhs_x[case.bases['p'].indices] = 0.0
    case.lift += V, lhs_x

    case.constrain('v', 'left')
    case.constrain('v', domain.boundary['right'].select(-x))


def mk_force(case, geom, vbasis, pbasis):
Esempio n. 29
0
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
Esempio n. 30
0
def main(
    L: 'domain size' = 4.,
    R: 'hole radius' = 1.,
    E: "young's modulus" = 1e5,
    nu: "poisson's ratio" = 0.3,
    T: 'far field traction' = 10,
    nr: 'number of h-refinements' = 2,
    withplots: 'create plots' = True,
):

    #Create the coarsest level parameter domain
    domain, geometry = mesh.rectilinear([1, 2])

    #Define the control points and control point weights
    controlpoints = numpy.array([[0, R], [R * (1 - 2**.5), R],
                                 [-R, R * (2**.5 - 1)], [-R, 0],
                                 [0, .5 * (R + L)],
                                 [-.15 * (R + L), .5 * (R + L)],
                                 [-.5 * (R + L), .15 * (R * L)],
                                 [-.5 * (R + L), 0], [0, L], [-L, L], [-L, L],
                                 [-L, 0]])
    weights = numpy.array(
        [1, .5 + .5 / 2**.5, .5 + .5 / 2**.5, 1, 1, 1, 1, 1, 1, 1, 1, 1])

    #Create the second-order B-spline basis over the coarsest domain
    bsplinebasis = domain.basis('spline', degree=2)

    #Create the NURBS basis
    weightfunc = bsplinebasis.dot(weights)
    nurbsbasis = (bsplinebasis * weights) / weightfunc

    #Create the isogeometric map
    geometry = (nurbsbasis[:, _] * controlpoints).sum(0)

    #Create the computational domain by h-refinement
    domain = domain.refine(nr)

    #Create the B-spline basis
    bsplinebasis = domain.basis('spline', degree=2)

    #Create the NURBS basis
    weights = domain.project(weightfunc,
                             onto=bsplinebasis,
                             geometry=geometry,
                             ischeme='gauss9')
    nurbsbasis = (bsplinebasis * weights) / weightfunc

    #Create the displacement field basis
    ubasis = nurbsbasis.vector(2)

    #Define the plane stress function
    stress = library.Hooke(lmbda=E * nu / (1 - nu**2), mu=.5 * E / (1 + nu))

    #Get the exact solution
    uexact = exact_solution(geometry, T, R, E, nu)
    sigmaexact = stress(uexact.symgrad(geometry))

    #Define the linear and bilinear forms
    mat_func = function.outer(ubasis.symgrad(geometry),
                              stress(ubasis.symgrad(geometry))).sum([2, 3])
    rhs_func = (ubasis * sigmaexact.dotnorm(geometry)).sum(-1)

    #Compute the matrix and rhs
    mat = domain.integrate(mat_func, geometry=geometry, ischeme='gauss9')
    rhs = domain.boundary['right'].integrate(rhs_func,
                                             geometry=geometry,
                                             ischeme='gauss9')

    #Compute the constraints vector for the symmetry conditions
    cons = domain.boundary['top,bottom'].project(0,
                                                 onto=ubasis.dotnorm(geometry),
                                                 geometry=geometry,
                                                 ischeme='gauss9')

    #Solve the system of equations
    sol = mat.solve(rhs=rhs, constrain=cons)

    #Compute the approximate displacement and stress functions
    u = ubasis.dot(sol)
    sigma = stress(u.symgrad(geometry))

    #Post-processing
    if withplots:
        points, colors = domain.simplex.elem_eval([geometry, sigma[0, 0]],
                                                  ischeme='bezier8',
                                                  separate=True)
        with plot.PyPlot('solution', index=nr) as plt:
            plt.mesh(points, colors)
            plt.colorbar()

    #Compute the L2-norm of the error in the stress
    err = numpy.sqrt(
        domain.integrate(
            ((sigma - sigmaexact) * (sigma - sigmaexact)).sum([0, 1]),
            geometry=geometry,
            ischeme='gauss9'))

    #Compute the mesh parameter (maximum physical distance between diagonally opposite knot locations)
    hmax = numpy.max([
        max(numpy.linalg.norm(verts[0] - verts[3]),
            numpy.linalg.norm(verts[1] - verts[2])) for verts in
        domain.elem_eval(geometry, ischeme='bezier2', separate=True)
    ])

    return err, hmax
Esempio n. 31
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. 32
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