Example #1
0
def test_bases(mu, case):
    domain, vbasis, pbasis = case.domain, case.basis('v'), case.basis('p')
    trfgeom = case.geometry(mu)
    refgeom = case.refgeom

    a_vbasis, a_pbasis = piola_bases(mu, case)

    J = trfgeom.grad(case.geometry())
    detJ = fn.determinant(J)
    b_vbasis = fn.matmat(vbasis, J.transpose()) / detJ
    b_pbasis = pbasis / detJ

    Z = case.geometry(mu).grad(case.geometry())
    detZ = fn.determinant(Z)
    zdiff = np.sqrt(domain.integrate((Z - J)**2 * fn.J(refgeom), ischeme='gauss9').export('dense'))
    np.testing.assert_almost_equal(zdiff, 0.0)

    c_vbasis = fn.matmat(vbasis, Z.transpose()) / detZ
    c_pbasis = pbasis

    pdiff = np.sqrt(domain.integrate((a_pbasis - b_pbasis)**2 * fn.J(refgeom), ischeme='gauss9'))
    np.testing.assert_almost_equal(pdiff, 0.0)
    pdiff = domain.integrate((a_pbasis - c_pbasis)**2 * fn.J(refgeom), ischeme='gauss9')
    np.testing.assert_almost_equal(pdiff, 0.0)

    vdiff = np.sqrt(domain.integrate((a_vbasis - b_vbasis)**2 * fn.J(refgeom), ischeme='gauss9').export('dense'))
    np.testing.assert_almost_equal(vdiff, 0.0)
    vdiff = domain.integrate((a_vbasis - c_vbasis)**2 * fn.J(refgeom), ischeme='gauss9').export('dense')
    np.testing.assert_almost_equal(vdiff, 0.0)
Example #2
0
def splipy_to_nutils(spline):
    """ Returns nutils domain and geometry object for spline mapping given by the argument """
    from nutils import mesh, function
    domain, geom = mesh.rectilinear(spline.knots())
    cp    = controlpoints(spline)
    basis = domain.basis('spline', degree=degree(spline), knotmultiplicities=multiplicities(spline))
    geom  = function.matmat(basis, cp)
    #TODO: add correct behaviour for rational and/or periodic geometries
    return domain, geom
Example #3
0
File: case.py Project: TheBB/aroma
 def basis(self, name, mu=None, transform=True):
     func = super().basis(name, mu=mu)
     if transform and f'{name}-trf' in self and mu is not None:
         J = self[f'{name}-trf'](mu)
         if J.ndim == 0:
             func = func * J
         else:
             func = fn.matmat(func, J.transpose())
     return func
Example #4
0
def splipy_to_nutils(spline):
    """ Returns nutils domain and geometry object for spline mapping given by the argument """
    from nutils import mesh, function
    domain, geom = mesh.rectilinear(spline.knots())
    cp = controlpoints(spline)
    basis = domain.basis('spline',
                         degree=degree(spline),
                         knotmultiplicities=multiplicities(spline))
    geom = function.matmat(basis, cp)
    #TODO: add correct behaviour for rational and/or periodic geometries
    return domain, geom
Example #5
0
File: case.py Project: TheBB/aroma
 def solution(self, lhs, field, mu=None, lift=True, J=None):
     lhs = self.solution_vector(lhs, mu, lift)
     if J is None:
         func = self.basis(field, mu).dot(lhs)
     else:
         func = self.basis(field, mu, transform=False)
         if J.ndim == 0:
             func = func * J
         else:
             func = fn.matmat(func, J.transpose())
         func = func.dot(lhs)
     return self.domain.sample(*element.parse_legacy_ischeme(self.meta['vscheme'])).eval(func)
Example #6
0
 def project(self, projection):
     ns = fn.Namespace()
     for name, func in self._kwargs.items():
         setattr(ns, name, func)
     for p, (name, func) in zip(projection, self._defaults.items()):
         if p is not None:
             func = fn.matmat(p, func)
         setattr(ns, name, func)
     integrand = getattr(ns, self._evaluator)(self._code)
     domain, geom, ischeme = self.prop('domain', 'geometry', 'ischeme')
     with matrix.Numpy():
         retval = domain.integrate(integrand * fn.J(geom), ischeme=ischeme)
     return NumpyArrayIntegrand(retval)
Example #7
0
def main(nelems:int, degree:int, reynolds:float, rotation:float, timestep:float, maxradius:float, seed:int, endtime:float):
  '''
  Flow around a cylinder.

  .. arguments::

     nelems [24]
       Element size expressed in number of elements along the cylinder wall.
       All elements have similar shape with approximately unit aspect ratio,
       with elements away from the cylinder wall growing exponentially.
     degree [3]
       Polynomial degree for velocity space; the pressure space is one degree
       less.
     reynolds [1000]
       Reynolds number, taking the cylinder radius as characteristic length.
     rotation [0]
       Cylinder rotation speed.
     timestep [.04]
       Time step
     maxradius [25]
       Target exterior radius; the actual domain size is subject to integer
       multiples of the configured element size.
     seed [0]
       Random seed for small velocity noise in the intial condition.
     endtime [inf]
       Stopping time.
  '''

  elemangle = 2 * numpy.pi / nelems
  melems = int(numpy.log(2*maxradius) / elemangle + .5)
  treelog.info('creating {}x{} mesh, outer radius {:.2f}'.format(melems, nelems, .5*numpy.exp(elemangle*melems)))
  domain, geom = mesh.rectilinear([melems, nelems], periodic=(1,))
  domain = domain.withboundary(inner='left', outer='right')

  ns = function.Namespace()
  ns.uinf = 1, 0
  ns.r = .5 * function.exp(elemangle * geom[0])
  ns.Re = reynolds
  ns.phi = geom[1] * elemangle # add small angle to break element symmetry
  ns.x_i = 'r <cos(phi), sin(phi)>_i'
  J = ns.x.grad(geom)
  detJ = function.determinant(J)
  ns.ubasis = function.matmat(function.vectorize([
    domain.basis('spline', degree=(degree,degree-1), removedofs=((0,),None)),
    domain.basis('spline', degree=(degree-1,degree))]), J.T) / detJ
  ns.pbasis = domain.basis('spline', degree=degree-1) / detJ
  ns.u_i = 'ubasis_ni ?u_n'
  ns.p = 'pbasis_n ?p_n'
  ns.sigma_ij = '(d(u_i, x_j) + d(u_j, x_i)) / Re - p δ_ij'
  ns.N = 10 * degree / elemangle # Nitsche constant based on element size = elemangle/2
  ns.nitsche_ni = '(N ubasis_ni - (d(ubasis_ni, x_j) + d(ubasis_nj, x_i)) n_j) / Re'
  ns.rotation = rotation
  ns.uwall_i = '0.5 rotation <-sin(phi), cos(phi)>_i'

  inflow = domain.boundary['outer'].select(-ns.uinf.dotnorm(ns.x), ischeme='gauss1') # upstream half of the exterior boundary
  sqr = inflow.integral('sum((u - uinf)^2)' @ ns, degree=degree*2)
  ucons = solver.optimize('u', sqr, droptol=1e-15) # constrain inflow semicircle to uinf
  cons = dict(u=ucons)

  numpy.random.seed(seed)
  sqr = domain.integral('sum((u - uinf)^2)' @ ns, degree=degree*2)
  udofs0 = solver.optimize('u', sqr) * numpy.random.normal(1, .1, len(ns.ubasis)) # set initial condition to u=uinf with small random noise
  state0 = dict(u=udofs0)

  ures = domain.integral('(ubasis_ni d(u_i, x_j) u_j + d(ubasis_ni, x_j) sigma_ij) J(x)' @ ns, degree=9)
  ures += domain.boundary['inner'].integral('(nitsche_ni (u_i - uwall_i) - ubasis_ni sigma_ij n_j) J(x)' @ ns, degree=9)
  pres = domain.integral('pbasis_n d(u_k, x_k) J(x)' @ ns, degree=9)
  uinertia = domain.integral('ubasis_ni u_i J(x)' @ ns, degree=9)

  bbox = numpy.array([[-2,46/9],[-2,2]]) # bounding box for figure based on 16x9 aspect ratio
  bezier0 = domain.sample('bezier', 5)
  bezier = bezier0.subset((bezier0.eval((ns.x-bbox[:,0]) * (bbox[:,1]-ns.x)) > 0).all(axis=1))
  interpolate = util.tri_interpolator(bezier.tri, bezier.eval(ns.x), mergetol=1e-5) # interpolator for quivers
  spacing = .05 # initial quiver spacing
  xgrd = util.regularize(bbox, spacing)

  with treelog.iter.plain('timestep', solver.impliciteuler(('u', 'p'), residual=(ures, pres), inertia=(uinertia, None), arguments=state0, timestep=timestep, constrain=cons, newtontol=1e-10)) as steps:
    for istep, state in enumerate(steps):

      t = istep * timestep
      x, u, normu, p = bezier.eval(['x', 'u', 'norm2(u)', 'p'] @ ns, **state)
      ugrd = interpolate[xgrd](u)

      with export.mplfigure('flow.png', figsize=(12.8,7.2)) as fig:
        ax = fig.add_axes([0,0,1,1], yticks=[], xticks=[], frame_on=False, xlim=bbox[0], ylim=bbox[1])
        im = ax.tripcolor(x[:,0], x[:,1], bezier.tri, p, shading='gouraud', cmap='jet')
        import matplotlib.collections
        ax.add_collection(matplotlib.collections.LineCollection(x[bezier.hull], colors='k', linewidths=.1, alpha=.5))
        ax.quiver(xgrd[:,0], xgrd[:,1], ugrd[:,0], ugrd[:,1], angles='xy', width=1e-3, headwidth=3e3, headlength=5e3, headaxislength=2e3, zorder=9, alpha=.5)
        ax.plot(0, 0, 'k', marker=(3,2,t*rotation*180/numpy.pi-90), markersize=20)
        cax = fig.add_axes([0.9, 0.1, 0.01, 0.8])
        cax.tick_params(labelsize='large')
        fig.colorbar(im, cax=cax)

      if t >= endtime:
        break

      xgrd = util.regularize(bbox, spacing, xgrd + ugrd * timestep)

  return state0, state
Example #8
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()
Example #9
0
import click
import numpy as np
from nutils import log, config, function as fn
from aroma import cases, solvers, util, quadrature, reduction, ensemble as ens, visualization
from aroma.affine import NumpyArrayIntegrand, integrate
import multiprocessing
import matplotlib.pyplot as plt


def get_exforce(case, mu):
    v, p = case.exact(mu, ('v', 'p'))
    geom = case.geometry(mu)
    force = p * geom.normal() - fn.matmat(v.grad(geom),
                                          geom.normal()) / mu['re']
    return case.domain.boundary['bottom'].integrate(force,
                                                    ischeme='gauss9',
                                                    geometry=geom)


def get_locforce(case, mu, lhs):
    return case['force'](mu, cont=(lhs, None))


def get_globforce(case, mu, lhs):
    wx, wy, l = case['xforce'](mu), case['yforce'](mu), case.lift(mu)
    u = lhs + l

    getf = lambda w: (case['divergence'](mu, cont=(w, u)) + case['laplacian'](
        mu, cont=(w, u)) + integrate(case['convection']
                                     (mu, cont=(w, u, u))) - case['forcing']
                      (mu, cont=(w, )))
Example #10
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'])
Example #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
Example #12
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()