Beispiel #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)
Beispiel #2
0
 def setUp(self):
     super().setUp()
     domain, geom = mesh.rectilinear([numpy.linspace(0, 1, 9)] * 2)
     ubasis, pbasis = function.chain([
         domain.basis('std', degree=2).vector(2),
         domain.basis('std', degree=1),
     ])
     dofs = function.Argument('dofs', [len(ubasis)])
     u = ubasis.dot(dofs)
     p = pbasis.dot(dofs)
     viscosity = 1e-3
     self.inertia = domain.integral((ubasis * u).sum(-1) * function.J(geom),
                                    degree=5)
     stokesres = domain.integral(
         (viscosity * (ubasis.grad(geom) *
                       (u.grad(geom) + u.grad(geom).T)).sum([-1, -2]) -
          ubasis.div(geom) * p + pbasis * u.div(geom)) * function.J(geom),
         degree=5)
     self.residual = stokesres + domain.integral(
         (ubasis *
          (u.grad(geom) * u).sum(-1) * u).sum(-1) * function.J(geom),
         degree=5)
     self.cons = domain.boundary['top,bottom'].project([0,0], onto=ubasis, geometry=geom, ischeme='gauss4') \
               | domain.boundary['left'].project([geom[1]*(1-geom[1]),0], onto=ubasis, geometry=geom, ischeme='gauss4')
     self.lhs0 = solver.solve_linear('dofs',
                                     residual=stokesres,
                                     constrain=self.cons)
     self.tol = 1e-10
Beispiel #3
0
 def setUp(self):
   super().setUp()
   domain, geom = mesh.rectilinear([8,8])
   basis = domain.basis('std', degree=1)
   self.cons = domain.boundary['left'].project(0, onto=basis, geometry=geom, ischeme='gauss2')
   dofs = function.Argument('dofs', [len(basis)])
   u = basis.dot(dofs)
   self.residual = domain.integral((basis.grad(geom) * u.grad(geom)).sum(-1)*function.J(geom), degree=2) \
                 + domain.boundary['top'].integral(basis*function.J(geom), degree=2)
 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
Beispiel #5
0
def _divs(fast: bool = False, piola: bool = False, num=8):
    __, solutions, supremizers = get_ensemble(fast, piola, num)
    case = get_case(fast, piola)

    angles = np.linspace(-35, 35, 15) * np.pi / 180

    eig_sol = reduction.eigen(case, solutions, fields=['v', 'p'])
    rb_sol = reduction.reduced_bases(case, solutions, eig_sol, (20, 20))

    results = []
    for angle in angles:
        log.user(f'angle = {angle}')

        mu = case.parameter(angle=angle)
        geom = case.physical_geometry(mu)

        divs = []
        for i in range(10):
            vsol, = case.solution(rb_sol['v'][i], mu, ['v'], lift=True)
            div = np.sqrt(
                case.domain.integrate(vsol.div(geom)**2 * fn.J(geom),
                                      ischeme='gauss9'))
            log.user(f'{i}: {div:.2e}')
            divs.append(div)

        results.append([angle * 180 / np.pi, max(divs), np.mean(divs)])

    results = np.array(results)
    np.savetxt(
        util.make_filename(_divs, 'airfoil-divs-{piola}.csv', piola=piola),
        results)
Beispiel #6
0
 def test_poly(self):
   target = self.geom.sum(-1) if self.btype == 'bubble' \
       else (self.geom**self.degree).sum(-1) + self.domain.f_index if self.btype == 'discont' \
       else (self.geom**self.degree).sum(-1)
   projection = self.domain.projection(target, onto=self.basis, geometry=self.geom, ischeme='gauss', degree=2*self.degree, droptol=0)
   error2 = self.domain.integrate((target-projection)**2*function.J(self.geom), ischeme='gauss', degree=2*self.degree)
   numpy.testing.assert_almost_equal(error2, 0, decimal=24)
Beispiel #7
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'))
Beispiel #8
0
 def setUp(self):
   super().setUp()
   domain, geom = mesh.rectilinear([numpy.linspace(0,1,9)] * 2)
   gauss = domain.sample('gauss', 5)
   uin = geom[1] * (1-geom[1])
   dx = function.J(geom, 2)
   ubasis = domain.basis('std', degree=2)
   pbasis = domain.basis('std', degree=1)
   if self.single:
     ubasis, pbasis = function.chain([ubasis.vector(2), pbasis])
     dofs = function.Argument('dofs', [len(ubasis)])
     u = ubasis.dot(dofs)
     p = pbasis.dot(dofs)
     dofs = 'dofs'
     ures = gauss.integral((self.viscosity * (ubasis.grad(geom) * (u.grad(geom) + u.grad(geom).T)).sum([-1,-2]) - ubasis.div(geom) * p) * dx)
     dres = gauss.integral((ubasis * (u.grad(geom) * u).sum(-1)).sum(-1) * dx)
   else:
     u = (ubasis[:,numpy.newaxis] * function.Argument('dofs', [len(ubasis), 2])).sum(0)
     p = (pbasis * function.Argument('pdofs', [len(pbasis)])).sum(0)
     dofs = 'dofs', 'pdofs'
     ures = gauss.integral((self.viscosity * (ubasis[:,numpy.newaxis].grad(geom) * (u.grad(geom) + u.grad(geom).T)).sum(-1) - ubasis.grad(geom) * p) * dx)
     dres = gauss.integral(ubasis[:,numpy.newaxis] * (u.grad(geom) * u).sum(-1) * dx)
   pres = gauss.integral((pbasis * u.div(geom)) * dx)
   cons = solver.optimize('dofs', domain.boundary['top,bottom'].integral((u**2).sum(), degree=4), droptol=1e-10)
   cons = solver.optimize('dofs', domain.boundary['left'].integral((u[0]-uin)**2 + u[1]**2, degree=4), droptol=1e-10, constrain=cons)
   self.cons = cons if self.single else {'dofs': cons}
   stokes = solver.solve_linear(dofs, residual=ures + pres if self.single else [ures, pres], constrain=self.cons)
   self.arguments = dict(dofs=stokes) if self.single else stokes
   self.residual = ures + dres + pres if self.single else [ures + dres, pres]
   inertia = gauss.integral(.5 * (u**2).sum(-1) * dx).derivative('dofs')
   self.inertia = inertia if self.single else [inertia, None]
   self.tol = 1e-10
   self.dofs = dofs
   self.frozen = types.frozenarray if self.single else solver.argdict
Beispiel #9
0
def mk_lift(case):
    mu = case.parameter()
    vbasis = case.basis('v', mu)

    geom = case['geometry'](mu)
    x, __ = geom
    cons = case.domain.boundary['left'].project((0, 0),
                                                onto=vbasis,
                                                geometry=geom,
                                                ischeme='gauss1')
    cons = case.domain.boundary['right'].select(-x).project(
        (1, 0),
        onto=vbasis,
        geometry=geom,
        ischeme='gauss9',
        constrain=cons,
    )

    mx = case['laplacian'](mu) + case['divergence'](mu, sym=True)
    lhs = matrix.ScipyMatrix(mx).solve(np.zeros(case.ndofs), constrain=cons)

    vsol = vbasis.dot(lhs)
    vdiv = vsol.div(geom)**2
    vdiv = np.sqrt(case.domain.integrate(vdiv * fn.J(geom), ischeme='gauss9'))
    log.user('Lift divergence (ref coord):', vdiv)

    lhs[case.bases['p'].indices] = 0.0
    return lhs
Beispiel #10
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)
Beispiel #11
0
 def integrate(*args):
     domain, geom, ischeme = args[0]._domain, args[0]._geometry, args[0]._ischeme
     assert all(arg._domain is domain for arg in args[1:])
     assert all(arg._geometry is geom for arg in args[1:])
     assert all(arg._ischeme == ischeme for arg in args[1:])
     with MaybeScipyBackend():
         retval = domain.integrate([arg._obj*fn.J(geom) for arg in args], ischeme=ischeme)
     return [r.core if isinstance(r, matrix.Matrix) else r for r in retval]
Beispiel #12
0
 def test_pum_sum(self):
     # Note that this test holds for btype 'lagrange' as well, although the
     # basis functions are not confined to range [0,1].
     error2 = self.domain.integrate(
         (1 - self.basis.sum(0))**2 * function.J(self.geom),
         ischeme='gauss',
         degree=2 * self.degree)
     numpy.testing.assert_almost_equal(error2, 0, decimal=22)
Beispiel #13
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())
Beispiel #14
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())
Beispiel #15
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())
Beispiel #16
0
def test_nutils_tensor():
    domain, geom = mesh.rectilinear([[0, 1], [0, 1]])
    basis = domain.basis('spline', degree=1)

    itg = basis[:, _, _] * basis[_, :, _] * basis[_, _, :]

    a = AffineIntegral(1, itg)
    a.prop(domain=domain, geometry=geom, ischeme='gauss9')
    a = a.cache_main(force=True)(None, {})
    b = domain.integrate(itg * fn.J(geom), ischeme='gauss9')

    np.testing.assert_almost_equal(a, b)
Beispiel #17
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)
Beispiel #18
0
 def project(self, projection):
     obj = self.obj
     s = slice(None)
     for i, p in enumerate(projection):
         if p is None:
             continue
         obj = obj[(s,)*i + (_,s,Ellipsis)]
         obj = obj * p[(_,)*i + (s,s) + (_,) * (self.ndim - i - 1)]
         obj = obj.sum(i+1)
     domain, geom, ischeme = self.prop('domain', 'geometry', 'ischeme')
     with matrix.Numpy():
         retval = domain.integrate(obj * fn.J(geom), ischeme=ischeme)
     return NumpyArrayIntegrand(retval)
Beispiel #19
0
 def cache(self, force=False, **kwargs):
     if self.ndim >= 3 and force:
         return self._highdim_cache(**kwargs)
     elif self.ndim >= 3:
         # Store properties for later integration
         self.prop(**kwargs)
         return self
     domain, geom, ischeme = self.prop('domain', 'geometry', 'ischeme', **kwargs)
     with MaybeScipyBackend():
         value = domain.integrate(self.obj * fn.J(geom), ischeme=ischeme)
     if isinstance(value, matrix.Matrix):
         value = value.core
     return Integrand.make(value)
Beispiel #20
0
def test_convection(mu, case):
    vbasis, pbasis = case.bases['v'].obj, case.bases['p'].obj
    trfgeom = case.geometry(mu)

    a, b, c = [np.random.rand(vbasis.shape[0]) for __ in range(3)]
    u = vbasis.dot(b)
    v = vbasis.dot(c).grad(trfgeom)
    w = vbasis.dot(a)

    itg = (w[:, _] * u[_, :] * v[:, :]).sum([-1, -2])
    phys_conv = case.domain.integrate(itg * fn.J(trfgeom), ischeme='gauss9')

    test_conv = affine.integrate(case['convection'](mu, cont=(a, b, c)))
    np.testing.assert_almost_equal(phys_conv, test_conv)
Beispiel #21
0
def test_exact_stokes(e_exact, a_exact, mu):
    mu = e_exact.parameter(*mu)

    elhs = stokes(e_exact, mu)
    alhs = stokes(a_exact, mu)
    _check_exact(e_exact, mu, elhs, with_p=False)  # TODO

    # Size of physical geometry
    pgeom = e_exact.geometry(mu)
    size = e_exact.domain.integrate(fn.J(pgeom), ischeme='gauss9')
    np.testing.assert_almost_equal(size, mu['w'] * mu['h'])

    # Solenoidal in physical coordinates
    pgeom = e_exact.geometry(mu)
    vdiv = e_exact.basis('v', mu).dot(elhs + e_exact.lift(mu)).div(pgeom)
    vdiv = np.sqrt(
        e_exact.domain.integrate(vdiv**2 * fn.J(pgeom), ischeme='gauss9'))
    np.testing.assert_almost_equal(0.0, vdiv)

    pgeom = a_exact.geometry(mu)
    vdiv = a_exact.basis('v', mu).dot(alhs + a_exact.lift(mu)).div(pgeom)
    vdiv = np.sqrt(
        a_exact.domain.integrate(vdiv**2 * fn.J(pgeom), ischeme='gauss9'))
    np.testing.assert_almost_equal(0.0, vdiv)

    # Solenoidal in reference coordinates
    rgeom = e_exact.refgeom
    vdiv = e_exact.basis('v').dot(elhs).div(rgeom)
    vdiv = np.sqrt(
        e_exact.domain.integrate(vdiv**2 * fn.J(rgeom), ischeme='gauss9'))
    np.testing.assert_almost_equal(0.0, vdiv)

    rgeom = a_exact.refgeom
    vdiv = a_exact.basis('v').dot(alhs).div(rgeom)
    vdiv = np.sqrt(
        a_exact.domain.integrate(vdiv**2 * fn.J(rgeom), ischeme='gauss9'))
    np.testing.assert_almost_equal(0.0, vdiv)
Beispiel #22
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'))
Beispiel #23
0
class NSConvection(MuCallable):

    _ident_ = 'NSConvection'

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

    def evaluate(self, case, mu, cont):
        geom = case['geometry'](mu)
        vbasis = case.basis('v', mu)
        vgrad = vbasis.grad(geom)
        itg = (vbasis[:,_,_,:,_] * vbasis[_,:,_,_,:] * vgrad[_,_,:,:,:]).sum([-1, -2])
        itg = util.contract(itg, cont)
        backend = matrix.Scipy if itg.ndim < 3 else COOTensorBackend
        with backend():
            return unwrap(case.domain.integrate(itg * fn.J(geom), ischeme='gauss9'))
Beispiel #24
0
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')
    test_mx = case['laplacian'](mu).toarray()
Beispiel #25
0
 def _highdim_cache(self, **kwargs):
     domain, geom, ischeme = self.prop('domain', 'geometry', 'ischeme', **kwargs)
     with COOTensorBackend():
         value = domain.integrate(self.obj * fn.J(geom), ischeme=ischeme)
     return value
Beispiel #26
0
import pytest

from aroma import cases
from aroma.solvers import stokes, navierstokes


def _check_exact(case, mu, lhs, with_p=True):
    vsol = case.basis('v', mu).dot(lhs + case.lift(mu))
    psol = case.basis('p', mu).dot(lhs + case.lift(mu))
    vexc, pexc = case.exact(mu, ['v', 'p'])
    vdiff = fn.norm2(vsol - vexc)
    pdiff = (psol - pexc)**2

    geom = case.geometry(mu)
    verr, perr = case.domain.integrate(
        [vdiff * fn.J(geom), pdiff * fn.J(geom)], ischeme='gauss9')

    np.testing.assert_almost_equal(verr, 0.0)
    if with_p:
        np.testing.assert_almost_equal(perr, 0.0)


@pytest.fixture()
def cavity():
    case = cases.cavity(nel=2)
    case.precompute()
    return case


@pytest.fixture()
def e_exact():
Beispiel #27
0
def main(fname: str, degree: int, Δuload: unit['mm'], nsteps: int, E: unit['GPa'], nu: float, σyield: unit['MPa'], hardening: unit['GPa'], referencedata: typing.Optional[str], testing: bool):

  '''
  Plastic deformation of a perforated strip.

  .. arguments::

     fname [strip.msh]
       Mesh file with units in [mm]

     degree [1]
       Finite element interpolation order

     Δuload [5μm]
       Load boundary displacement steps

     nsteps [11]
       Number of load steps

     E [70GPa]
       Young's modulus

     nu [0.2]
       Poisson ratio

     σyield [243MPa]
       Yield strength

     hardening [2.25GPa]
       Hardening parameter

     referencedata [zienkiewicz.csv]
       Reference data file name

     testing [False]
       Use a 1 element mesh for testing

  .. presets::

     testing
       nsteps=30
       referencedata=
       testing=True
  '''

  # We commence with reading the mesh from the specified GMSH file, or, alternatively,
  # we continue with a single-element mesh for testing purposes.
  domain, geom = mesh.gmsh(pathlib.Path(__file__).parent/fname)
  Wdomain, Hdomain = domain.boundary['load'].integrate([function.J(geom),geom[1]*function.J(geom)], degree=1)
  Hdomain /= Wdomain

  if testing:
    domain, geom = mesh.rectilinear([numpy.linspace(0,Wdomain/2,2),numpy.linspace(0,Hdomain,2)])
    domain = domain.withboundary(hsymmetry='left', vsymmetry='bottom', load='top')

  # We next initiate the point set in which the constitutive bahvior will be evaluated.
  # Note that this is also the point set in which the history variable will be stored.
  gauss  = domain.sample('gauss', 2)

  # Elasto-plastic formulation
  # ==========================
  # The weak formulation is constructed using a `Namespace`, which is initialized and
  # populated with the necessary problem parameters and coordinate system. Note that the
  # coefficients `mu` and `λ` have been defined such that 'C_{ijkl}' is the fourth-order
  # **plane stress** elasticity tensor.

  ns = function.Namespace(fallback_length=domain.ndims)

  ns.x      = geom
  ns.Δuload = Δuload
  ns.mu     = E/(1-nu**2)*((1-nu)/2)
  ns.λ      = E/(1-nu**2)*nu
  ns.delta  = function.eye(domain.ndims)
  ns.C_ijkl = 'mu ( delta_ik delta_jl + delta_il delta_jk ) + λ delta_ij delta_kl'

  # We make use of a Lagrange finite element basis of arbitrary `degree`. Since we
  # approximate the displacement field, the basis functions are vector-valued. Both
  # the displacement field at the current load step `u` and displacement field of the
  # previous load step `u0` are approximated using this basis:

  ns.basis = domain.basis('std',degree=degree).vector(domain.ndims)

  ns.u0_i = 'basis_ni ?lhs0_n'
  ns.u_i  = 'basis_ni ?lhs_n'

  # This simulation is based on a standard elasto-plasticity model. In this
  # model the *total strain*, ε_kl = ½ (∂u_k/∂x_l + ∂u_l/∂x_k)', is comprised of an
  # elastic and a plastic part:
  #
  #   ε_kl = εe_kl + εp_kl
  #
  # The stress is related to the *elastic strain*, εe_kl, through Hooke's law:
  #
  #   σ_ij = C_ijkl εe_kl = C_ijkl (ε_kl - εp_kl)

  ns.ε_kl   = '(u_k,l + u_l,k) / 2'
  ns.ε0_kl  = '(u0_k,l + u0_l,k) / 2'
  ns.gbasis = gauss.basis()
  ns.εp0_ij = 'gbasis_n ?εp0_nij'
  ns.κ0     = 'gbasis_n ?κ0_n'

  ns.εp    = PlasticStrain(ns.ε, ns.ε0, ns.εp0, ns.κ0, E, nu, σyield, hardening)
  ns.εe_ij = 'ε_ij - εp_ij'
  ns.σ_ij  = 'C_ijkl εe_kl'

  # Note that the plasticity model is implemented through the user-defined function `PlasticStrain`,
  # which implements the actual yielding model including a standard return mapping algorithm. This
  # function is discussed in detail below.
  #
  # The components of the residual vector are then defined as:
  #
  #   r_n = ∫_Ω (∂N_ni/∂x_j) σ_ij dΩ

  res = domain.integral('basis_ni,j σ_ij d:x' @ ns, degree=2)

  # The problem formulation is completed by supplementing prescribed displacement boundary conditions
  # (for a load step), which are computed in the standard manner:

  sqr  = domain.boundary['hsymmetry,vsymmetry'].integral('(u_k n_k)^2 d:x' @ ns, degree=2)
  sqr += domain.boundary['load'].integral('(u_k n_k - Δuload)^2 d:x' @ ns, degree=2)
  cons = solver.optimize('lhs', sqr, droptol=1e-15)

  # Incremental-iterative solution procedure
  # ========================================
  # We initialize the solution vector for the first load step `lhs` and solution vector
  # of the previous load step `lhs0`. Note that, in order to construct a predictor step
  # for the first load step, we define the previous load step state as the solution
  # vector corresponding to a negative elastic loading step.

  lhs0 = -solver.solve_linear('lhs', domain.integral('basis_ni,j C_ijkl ε_kl d:x' @ ns, degree=2), constrain=cons)
  lhs  = numpy.zeros_like(lhs0)
  εp0  = numpy.zeros((gauss.npoints,)+ns.εp0.shape)
  κ0   = numpy.zeros((gauss.npoints,)+ns.κ0.shape)

  # To store the force-dispalcement data we initialize an empty data array with the
  # inital state solution substituted in the first row.
  fddata      = numpy.empty(shape=(nsteps+1,2))
  fddata[:]   = numpy.nan
  fddata[0,:] = 0

  # Load step incrementation
  # ------------------------
  with treelog.iter.fraction('step', range(nsteps)) as counter:
    for step in counter:

      # The solution of the previous load step is set to `lhs0`, and the Newton solution
      # procedure is initialized by extrapolation of the state vector:
      lhs_init = lhs + (lhs-lhs0)
      lhs0     = lhs

      # The non-linear system of equations is solved for `lhs` using Newton iterations,
      # where the `step` variable is used to scale the incremental constraints.
      lhs = solver.newton(target='lhs', residual=res, constrain=cons*step, lhs0=lhs_init, arguments={'lhs0':lhs0,'εp0':εp0,'κ0':κ0}).solve(tol=1e-6)

      # The computed solution is post-processed in the form of a loading curve - which
      # plots the normalized mean stress versus the maximum 'ε_{yy}' strain
      # component - and a contour plot showing the 'σ_{yy}' stress component on a
      # deformed mesh. Note that since the stresses are defined in the integration points
      # only, a post-processing step is involved that transfers the stress information to
      # the nodal points.
      εyymax = gauss.eval(ns.ε[1,1], arguments=dict(lhs=lhs)).max()

      basis = domain.basis('std', degree=1)
      bw, b = domain.integrate([basis * ns.σ[1,1] * function.J(geom), basis * function.J(geom)], degree=2, arguments=dict(lhs=lhs,lhs0=lhs0,εp0=εp0,κ0=κ0))
      σyy = basis.dot(bw / b)

      uyload, σyyload = domain.boundary['load'].integrate(['u_1 d:x'@ns,σyy * function.J(geom)], degree=2, arguments=dict(lhs=lhs,εp0=εp0,κ0=κ0))
      uyload /= Wdomain
      σyyload /= Wdomain
      fddata[step,0] = (E*εyymax)/σyield
      fddata[step,1] = (σyyload*2)/σyield

      with export.mplfigure('forcedisp.png') as fig:
        ax = fig.add_subplot(111, xlabel=r'${E \cdot {\rm max}(\varepsilon_{yy})}/{\sigma_{\rm yield}}$', ylabel=r'${\sigma_{\rm mean}}/{\sigma_{\rm yield}}$')
        if referencedata:
          data = numpy.genfromtxt(pathlib.Path(__file__).parent/referencedata, delimiter=',', skip_header=1)
          ax.plot(data[:,0], data[:,1], 'r:', label='Reference')
          ax.legend()
        ax.plot(fddata[:,0], fddata[:,1], 'o-', label='Nutils')
        ax.grid()

      bezier = domain.sample('bezier', 3)
      points, uvals, σyyvals = bezier.eval(['(x_i + 25 u_i)' @ ns, ns.u, σyy], arguments=dict(lhs=lhs))
      with export.mplfigure('stress.png') as fig:
        ax = fig.add_subplot(111, aspect='equal', xlabel=r'$x$ [mm]', ylabel=r'$y$ [mm]')
        im = ax.tripcolor(points[:,0]/unit('mm'), points[:,1]/unit('mm'), bezier.tri, σyyvals/unit('MPa'), shading='gouraud', cmap='jet')
        ax.add_collection(collections.LineCollection(points.take(bezier.hull, axis=0), colors='k', linewidths=.1))
        ax.autoscale(enable=True, axis='both', tight=True)
        cb = fig.colorbar(im)
        im.set_clim(0, 1.2*σyield)
        cb.set_label(r'$σ_{yy}$ [MPa]')

      # Load step convergence
      # ---------------------
      # At the end of the loading step, the plastic strain state and history parameter are updated,
      # where use if made of the strain hardening relation for the history variable:
      #
      #   Δκ = √(Δεp_ij Δεp_ij)

      Δεp = ns.εp-ns.εp0
      Δκ  = function.sqrt((Δεp*Δεp).sum((0,1)))
      κ0  = gauss.eval(ns.κ0+Δκ, arguments=dict(lhs0=lhs0,lhs=lhs,εp0=εp0,κ0=κ0))
      εp0 = gauss.eval(ns.εp, arguments=dict(lhs0=lhs0,lhs=lhs,εp0=εp0,κ0=κ0))
Beispiel #28
0
def poisson_patch(bottom, right, top, left):
    from nutils import version
    if int(version[0]) != 4:
        raise ImportError(
            'Mismatching nutils version detected, only version 4 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 * fn.J(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))

        # 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)
def main(nrefine: int, traction: float, radius: float, poisson: float):
    '''
  Horizontally loaded linear elastic plate with IGA hole.

  .. arguments::

     nrefine [2]
       Number of uniform refinements starting from 1x2 base mesh.
     traction [.1]
       Far field traction (relative to Young's modulus).
     radius [.5]
       Cut-out radius.
     poisson [.3]
       Poisson's ratio, nonnegative and strictly smaller than 1/2.
  '''

    # create the coarsest level parameter domain
    domain, geom0 = mesh.rectilinear([1, 2])
    bsplinebasis = domain.basis('spline', degree=2)
    controlweights = numpy.ones(12)
    controlweights[1:3] = .5 + .25 * numpy.sqrt(2)
    weightfunc = bsplinebasis.dot(controlweights)
    nurbsbasis = bsplinebasis * controlweights / weightfunc

    # create geometry function
    indices = [0, 2], [1, 2], [2, 1], [2, 0]
    controlpoints = numpy.concatenate([
        numpy.take([0, 2**.5 - 1, 1], indices) * radius,
        numpy.take([0, .3, 1], indices) * (radius + 1) / 2,
        numpy.take([0, 1, 1], indices)
    ])
    geom = (nurbsbasis[:, numpy.newaxis] * controlpoints).sum(0)

    radiuserr = domain.boundary['left'].integral(
        (function.norm2(geom) - radius)**2 * function.J(geom0),
        degree=9).eval()**.5
    treelog.info('hole radius exact up to L2 error {:.2e}'.format(radiuserr))

    # refine domain
    if nrefine:
        domain = domain.refine(nrefine)
        bsplinebasis = domain.basis('spline', degree=2)
        controlweights = domain.project(weightfunc,
                                        onto=bsplinebasis,
                                        geometry=geom0,
                                        ischeme='gauss9')
        nurbsbasis = bsplinebasis * controlweights / weightfunc

    ns = function.Namespace()
    ns.x = geom
    ns.lmbda = 2 * poisson
    ns.mu = 1 - poisson
    ns.ubasis = nurbsbasis.vector(2)
    ns.u_i = 'ubasis_ni ?lhs_n'
    ns.X_i = 'x_i + u_i'
    ns.strain_ij = '(d(u_i, x_j) + d(u_j, x_i)) / 2'
    ns.stress_ij = 'lmbda strain_kk δ_ij + 2 mu strain_ij'
    ns.r2 = 'x_k x_k'
    ns.R2 = radius**2 / ns.r2
    ns.k = (3 - poisson) / (1 + poisson)  # plane stress parameter
    ns.scale = traction * (1 + poisson) / 2
    ns.uexact_i = 'scale (x_i ((k + 1) (0.5 + R2) + (1 - R2) R2 (x_0^2 - 3 x_1^2) / r2) - 2 δ_i1 x_1 (1 + (k - 1 + R2) R2))'
    ns.du_i = 'u_i - uexact_i'

    sqr = domain.boundary['top,bottom'].integral('(u_i n_i)^2 J(x)' @ ns,
                                                 degree=9)
    cons = solver.optimize('lhs', sqr, droptol=1e-15)
    sqr = domain.boundary['right'].integral('du_k du_k J(x)' @ ns, degree=20)
    cons = solver.optimize('lhs', sqr, droptol=1e-15, constrain=cons)

    # construct residual
    res = domain.integral('d(ubasis_ni, x_j) stress_ij J(x)' @ ns, degree=9)

    # solve system
    lhs = solver.solve_linear('lhs', res, constrain=cons)

    # vizualize result
    bezier = domain.sample('bezier', 9)
    X, stressxx = bezier.eval(['X', 'stress_00'] @ ns, lhs=lhs)
    export.triplot('stressxx.png',
                   X,
                   stressxx,
                   tri=bezier.tri,
                   hull=bezier.hull,
                   clim=(numpy.nanmin(stressxx), numpy.nanmax(stressxx)))

    # evaluate error
    err = domain.integral('<du_k du_k, sum:ij(d(du_i, x_j)^2)>_n J(x)' @ ns,
                          degree=9).eval(lhs=lhs)**.5
    treelog.user('errors: L2={:.2e}, H1={:.2e}'.format(*err))

    return err, cons, lhs
Beispiel #30
0
        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


@util.pickle_cache('airfoil-{piola}-{imported}-{nred}.rcase')