示例#1
0
def main(viscosity=1.3e-3, density=1e3, pout=223e5, uw=-0.01, nelems=10):
    # viscosity = 1.3e-3
    # density = 1e3
    # pout = 223e5
    # nelems = 10
    # uw = -0.01

    domain, geom = mesh.rectilinear([numpy.linspace(0, 1, nelems), numpy.linspace(1, 2, nelems), [0, 2 * numpy.pi]],
                                periodic=[2])
    domain = domain.withboundary(inner='bottom', outer='top')

    ns = function.Namespace()
    ns.y, ns.r, ns.θ = geom
    ns.x_i = '<r cos(θ), y, r sin(θ)>_i'
    ns.uybasis, ns.urbasis, ns.pbasis = function.chain([
    domain.basis('std', degree=3, removedofs=((0,-1), None, None)),  # remove normal component at y=0 and y=1
    domain.basis('std', degree=3, removedofs=((0,-1), None, None)),  # remove tangential component at y=0 (no slip)
    domain.basis('std', degree=2)])
    ns.ubasis_ni = '<urbasis_n cos(θ), uybasis_n, urbasis_n sin(θ)>_i'
    ns.viscosity = viscosity
    ns.density = density
    ns.u_i = 'ubasis_ni ?lhs_n'
    ns.p = 'pbasis_n ?lhs_n'
    ns.sigma_ij = 'viscosity (u_i,j + u_j,i) - p δ_ij'
    ns.pout = pout
    ns.uw = uw
    ns.uw_i = 'uw <cos(phi), 0, sin(phi)>_i'
    ns.tout_i = '-pout n_i'
    ns.uw_i = 'uw n_i'  # uniform outflow

    res = domain.integral('(viscosity ubasis_ni,j u_i,j - p ubasis_ni,i + pbasis_n u_k,k) d:x' @ ns, degree=6)
    # res -= domain[1].boundary['inner'].integral('ubasis_ni tout_i d:x' @ ns, degree=6)

    sqr = domain.boundary['inner'].integral('(u_i - uw_i) (u_i - uw_i) d:x' @ ns, degree=6)
    # sqr = domain.boundary['outer'].integral('(u_i - uin_i) (u_i - uin_i) d:x' @ ns, degree=6)
    sqr -= domain.boundary['outer'].integral('(p - pout) (p - pout) d:x' @ ns, degree=6)
    cons = solver.optimize('lhs', sqr, droptol=1e-15)

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

    plottopo = domain[:, :, 0:].boundary['back']

    bezier = plottopo.sample('bezier', 10)
    r, y, p, u = bezier.eval([ns.r, ns.y, ns.p, function.norm2(ns.u)], lhs=lhs)
    with export.mplfigure('pressure.png', dpi=800) as fig:
        ax = fig.add_subplot(111, title='pressure', aspect=1)
        ax.autoscale(enable=True, axis='both', tight=True)
        im = ax.tripcolor(r, y, bezier.tri, p, shading='gouraud', cmap='jet')
        ax.add_collection(
            collections.LineCollection(numpy.array([y, r]).T[bezier.hull], colors='k', linewidths=0.2, alpha=0.2))
        fig.colorbar(im)

    uniform = plottopo.sample('uniform', 1)
    r_, y_, uv = uniform.eval([ns.r, ns.y, ns.u], lhs=lhs)
    with export.mplfigure('velocity.png', dpi=800) as fig:
        ax = fig.add_subplot(111, title='Velocity', aspect=1)
        ax.autoscale(enable=True, axis='both', tight=True)
        im = ax.tripcolor(r, y, bezier.tri, u, shading='gouraud', cmap='jet')
        ax.quiver(r_, y_, uv[:, 0], uv[:, 1], angles='xy', scale_units='xy')
        fig.colorbar(im)
示例#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
示例#3
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
示例#4
0
def main(nelems: int, degree: int, reynolds: float):
    '''
  Driven cavity benchmark problem using compatible spaces.

  .. arguments::

     nelems [12]
       Number of elements along edge.
     degree [2]
       Polynomial degree for velocity; the pressure space is one degree less.
     reynolds [1000]
       Reynolds number, taking the domain size as characteristic length.
  '''

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

    ns = function.Namespace()
    ns.x = geom
    ns.Re = reynolds
    ns.ubasis = function.vectorize([
        domain.basis('spline',
                     degree=(degree, degree - 1),
                     removedofs=((0, -1), None)),
        domain.basis('spline',
                     degree=(degree - 1, degree),
                     removedofs=(None, (0, -1)))
    ])
    ns.pbasis = domain.basis('spline', degree=degree - 1)
    ns.u_i = 'ubasis_ni ?u_n'
    ns.p = 'pbasis_n ?p_n'
    ns.stress_ij = '(d(u_i, x_j) + d(u_j, x_i)) / Re - p δ_ij'
    ns.uwall = domain.boundary.indicator('top'), 0
    ns.N = 5 * degree * nelems  # nitsche constant based on element size = 1/nelems
    ns.nitsche_ni = '(N ubasis_ni - (d(ubasis_ni, x_j) + d(ubasis_nj, x_i)) n(x_j)) / Re'

    ures = domain.integral('d(ubasis_ni, x_j) stress_ij d:x' @ ns,
                           degree=2 * degree)
    ures += domain.boundary.integral(
        '(nitsche_ni (u_i - uwall_i) - ubasis_ni stress_ij n(x_j)) d:x' @ ns,
        degree=2 * degree)
    pres = domain.integral('pbasis_n (d(u_k, x_k) + ?lm) d:x' @ ns,
                           degree=2 * degree)
    lres = domain.integral('p d:x' @ ns, degree=2 * degree)

    with treelog.context('stokes'):
        state0 = solver.solve_linear(['u', 'p', 'lm'], [ures, pres, lres])
        postprocess(domain, ns, **state0)

    ures += domain.integral('ubasis_ni d(u_i, x_j) u_j d:x' @ ns,
                            degree=3 * degree)
    with treelog.context('navierstokes'):
        state1 = solver.newton(('u', 'p', 'lm'), (ures, pres, lres),
                               arguments=state0).solve(tol=1e-10)
        postprocess(domain, ns, **state1)

    return state0, state1
示例#5
0
 def test_res(self):
   for name in 'direct', 'newton':
     with self.subTest(name):
       if name == 'direct':
         lhs = solver.solve_linear('dofs', residual=self.residual, constrain=self.cons)
       else:
         lhs = solver.newton('dofs', residual=self.residual, constrain=self.cons).solve(tol=1e-10, maxiter=0)
       res = self.residual.eval(arguments=dict(dofs=lhs))
       resnorm = numpy.linalg.norm(res[~self.cons.where])
       self.assertLess(resnorm, 1e-13)
示例#6
0
 def test_res(self):
   for name in 'direct', 'newton':
     with self.subTest(name):
       if name == 'direct':
         lhs = solver.solve_linear('dofs', residual=self.residual, constrain=self.cons)
       else:
         lhs = solver.newton('dofs', residual=self.residual, constrain=self.cons).solve(tol=1e-10, maxiter=0)
       res = self.residual.eval(arguments=dict(dofs=lhs))
       resnorm = numpy.linalg.norm(res[~self.cons.where])
       self.assertLess(resnorm, 1e-13)
示例#7
0
def main(nelems: int, degree: int, reynolds: float):
    '''
  Driven cavity benchmark problem using compatible spaces.

  .. arguments::

     nelems [12]
       Number of elements along edge.
     degree [2]
       Polynomial degree for velocity; the pressure space is one degree less.
     reynolds [1000]
       Reynolds number, taking the domain size as characteristic length.
  '''

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

    ns = function.Namespace()
    ns.x = geom
    ns.Re = reynolds
    ns.uxbasis, ns.uybasis, ns.pbasis, ns.lbasis = function.chain([
        domain.basis('spline',
                     degree=(degree, degree - 1),
                     removedofs=((0, -1), None)),
        domain.basis('spline',
                     degree=(degree - 1, degree),
                     removedofs=(None, (0, -1))),
        domain.basis('spline', degree=degree - 1),
        [1],  # lagrange multiplier
    ])
    ns.ubasis_ni = '<uxbasis_n, uybasis_n>_i'
    ns.u_i = 'ubasis_ni ?lhs_n'
    ns.p = 'pbasis_n ?lhs_n'
    ns.l = 'lbasis_n ?lhs_n'
    ns.stress_ij = '(u_i,j + u_j,i) / Re - p δ_ij'
    ns.uwall = domain.boundary.indicator('top'), 0
    ns.N = 5 * degree * nelems  # nitsche constant based on element size = 1/nelems
    ns.nitsche_ni = '(N ubasis_ni - (ubasis_ni,j + ubasis_nj,i) n_j) / Re'

    res = domain.integral(
        '(ubasis_ni,j stress_ij + pbasis_n (u_k,k + l) + lbasis_n p) d:x' @ ns,
        degree=2 * degree)
    res += domain.boundary.integral(
        '(nitsche_ni (u_i - uwall_i) - ubasis_ni stress_ij n_j) d:x' @ ns,
        degree=2 * degree)
    with treelog.context('stokes'):
        lhs0 = solver.solve_linear('lhs', res)
        postprocess(domain, ns, lhs=lhs0)

    res += domain.integral('ubasis_ni u_i,j u_j d:x' @ ns, degree=3 * degree)
    with treelog.context('navierstokes'):
        lhs1 = solver.newton('lhs', res, lhs0=lhs0).solve(tol=1e-10)
        postprocess(domain, ns, lhs=lhs1)

    return lhs0, lhs1
示例#8
0
def main(nelems: int, etype: str, degree: int, reynolds: float):
    '''
  Driven cavity benchmark problem.

  .. arguments::

     nelems [12]
       Number of elements along edge.
     etype [square]
       Element type (square/triangle/mixed).
     degree [2]
       Polynomial degree for velocity; the pressure space is one degree less.
     reynolds [1000]
       Reynolds number, taking the domain size as characteristic length.
  '''

    domain, geom = mesh.unitsquare(nelems, etype)

    ns = function.Namespace()
    ns.Re = reynolds
    ns.x = geom
    ns.ubasis, ns.pbasis = function.chain([
        domain.basis('std', degree=degree).vector(2),
        domain.basis('std', degree=degree - 1),
    ])
    ns.u_i = 'ubasis_ni ?lhs_n'
    ns.p = 'pbasis_n ?lhs_n'
    ns.stress_ij = '(u_i,j + u_j,i) / Re - p δ_ij'

    sqr = domain.boundary.integral('u_k u_k d:x' @ ns, degree=degree * 2)
    wallcons = solver.optimize('lhs', sqr, droptol=1e-15)

    sqr = domain.boundary['top'].integral('(u_0 - 1)^2 d:x' @ ns,
                                          degree=degree * 2)
    lidcons = solver.optimize('lhs', sqr, droptol=1e-15)

    cons = numpy.choose(numpy.isnan(lidcons), [lidcons, wallcons])
    cons[-1] = 0  # pressure point constraint

    res = domain.integral('(ubasis_ni,j stress_ij + pbasis_n u_k,k) d:x' @ ns,
                          degree=degree * 2)
    with treelog.context('stokes'):
        lhs0 = solver.solve_linear('lhs', res, constrain=cons)
        postprocess(domain, ns, lhs=lhs0)

    res += domain.integral(
        '.5 (ubasis_ni u_i,j - ubasis_ni,j u_i) u_j d:x' @ ns,
        degree=degree * 3)
    with treelog.context('navierstokes'):
        lhs1 = solver.newton('lhs', res, lhs0=lhs0,
                             constrain=cons).solve(tol=1e-10)
        postprocess(domain, ns, lhs=lhs1)

    return lhs0, lhs1
示例#9
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])

    # create namespace
    ns = function.Namespace(default_geometry_name='x0')
    ns.x0 = geom
    ns.basis = domain.basis('spline', degree=degree).vector(2)
    ns.u_i = 'basis_ni ?lhs_n'
    ns.x_i = 'x0_i + u_i'
    ns.lmbda = lmbda
    ns.mu = mu
    ns.strain_ij = '(u_i,j + u_j,i) / 2'
    ns.stress_ij = 'lmbda strain_kk δ_ij + 2 mu strain_ij'

    # construct dirichlet boundary constraints
    sqr = domain.boundary['left'].integral('u_k u_k' @ ns,
                                           geometry=ns.x0,
                                           degree=2)
    sqr += domain.boundary['right'].integral('(u_0 - .5)^2' @ ns,
                                             geometry=ns.x0,
                                             degree=2)
    cons = solver.optimize('lhs', sqr, droptol=1e-15)

    # construct residual
    res = domain.integral('basis_ni,j stress_ij' @ ns,
                          geometry=ns.x0,
                          degree=2)

    # solve system and substitute the solution in the namespace
    lhs = solver.solve_linear('lhs', res, constrain=cons)
    ns |= dict(lhs=lhs)

    # plot solution
    if withplots:
        points, colors = domain.elem_eval([ns.x, ns.stress[0, 1]],
                                          ischeme='bezier3',
                                          separate=True)
        with plot.PyPlot('stress', ndigits=0) as plt:
            plt.mesh(points, colors, tight=False)
            plt.colorbar()

    return lhs, cons
示例#10
0
def main(nelems:int, etype:str, degree:int, reynolds:float):
  '''
  Driven cavity benchmark problem.

  .. arguments::

     nelems [12]
       Number of elements along edge.
     etype [square]
       Element type (square/triangle/mixed).
     degree [2]
       Polynomial degree for velocity; the pressure space is one degree less.
     reynolds [1000]
       Reynolds number, taking the domain size as characteristic length.
  '''

  domain, geom = mesh.unitsquare(nelems, etype)

  ns = function.Namespace()
  ns.Re = reynolds
  ns.x = geom
  ns.ubasis = domain.basis('std', degree=degree).vector(domain.ndims)
  ns.pbasis = domain.basis('std', degree=degree-1)
  ns.u_i = 'ubasis_ni ?u_n'
  ns.p = 'pbasis_n ?p_n'
  ns.stress_ij = '(d(u_i, x_j) + d(u_j, x_i)) / Re - p δ_ij'

  usqr = domain.boundary.integral('u_k u_k d:x' @ ns, degree=degree*2)
  wallcons = solver.optimize('u', usqr, droptol=1e-15)

  usqr = domain.boundary['top'].integral('(u_0 - 1)^2 d:x' @ ns, degree=degree*2)
  lidcons = solver.optimize('u', usqr, droptol=1e-15)

  ucons = numpy.choose(numpy.isnan(lidcons), [lidcons, wallcons])
  pcons = numpy.zeros(len(ns.pbasis), dtype=bool)
  pcons[-1] = True # constrain pressure to zero in a point
  cons = dict(u=ucons, p=pcons)

  ures = domain.integral('d(ubasis_ni, x_j) stress_ij d:x' @ ns, degree=degree*2)
  pres = domain.integral('pbasis_n d(u_k, x_k) d:x' @ ns, degree=degree*2)
  with treelog.context('stokes'):
    state0 = solver.solve_linear(('u', 'p'), (ures, pres), constrain=cons)
    postprocess(domain, ns, **state0)

  ures += domain.integral('.5 (ubasis_ni d(u_i, x_j) - d(ubasis_ni, x_j) u_i) u_j d:x' @ ns, degree=degree*3)
  with treelog.context('navierstokes'):
    state1 = solver.newton(('u', 'p'), (ures, pres), arguments=state0, constrain=cons).solve(tol=1e-10)
    postprocess(domain, ns, **state1)

  return state0, state1
示例#11
0
def main(nelems: int, etype: str, btype: str, degree: int, poisson: float):
    '''
  Horizontally loaded linear elastic plate.

  .. arguments::

     nelems [10]
       Number of elements along edge.
     etype [square]
       Type of elements (square/triangle/mixed).
     btype [std]
       Type of basis function (std/spline), with availability depending on the
       configured element type.
     degree [1]
       Polynomial degree.
     poisson [.25]
       Poisson's ratio, nonnegative and strictly smaller than 1/2.
  '''

    domain, geom = mesh.unitsquare(nelems, etype)

    ns = function.Namespace()
    ns.x = geom
    ns.basis = domain.basis(btype, degree=degree).vector(2)
    ns.u_i = 'basis_ni ?lhs_n'
    ns.X_i = 'x_i + u_i'
    ns.lmbda = 2 * poisson
    ns.mu = 1 - 2 * poisson
    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'

    sqr = domain.boundary['left'].integral('u_k u_k J(x)' @ ns,
                                           degree=degree * 2)
    sqr += domain.boundary['right'].integral('(u_0 - .5)^2 J(x)' @ ns,
                                             degree=degree * 2)
    cons = solver.optimize('lhs', sqr, droptol=1e-15)

    res = domain.integral('d(basis_ni, x_j) stress_ij J(x)' @ ns,
                          degree=degree * 2)
    lhs = solver.solve_linear('lhs', res, constrain=cons)

    bezier = domain.sample('bezier', 5)
    X, sxy = bezier.eval(['X', 'stress_01'] @ ns, lhs=lhs)
    export.triplot('shear.png', X, sxy, tri=bezier.tri, hull=bezier.hull)

    return cons, lhs
示例#12
0
def main(
    nelems: 'number of elements' = 10,
    degree: 'polynomial degree' = 1,
    basistype: 'basis function' = 'spline',
    solvetol: 'solver tolerance' = 1e-10,
    figures: 'create figures' = True,
  ):

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

  # create namespace
  ns = function.Namespace()
  ns.x = geom
  ns.basis = domain.basis(basistype, degree=degree)
  ns.u = 'basis_n ?lhs_n'
  ns.fx = 'sin(x_0)'
  ns.fy = 'exp(x_1)'

  # construct residual
  res = domain.integral('-basis_n,i u_,i' @ ns, geometry=ns.x, degree=degree*2)
  res += domain.boundary['top'].integral('basis_n fx fy' @ ns, geometry=ns.x, degree=degree*2)

  # construct dirichlet constraints
  sqr = domain.boundary['left'].integral('u^2' @ ns, geometry=ns.x, degree=degree*2)
  sqr += domain.boundary['bottom'].integral('(u - fx)^2' @ ns, geometry=ns.x, degree=degree*2)
  cons = solver.optimize('lhs', sqr, droptol=1e-15)

  # find lhs such that res == 0 and substitute this lhs in the namespace
  lhs = solver.solve_linear('lhs', res, constrain=cons)
  ns = ns(lhs=lhs)

  # plot solution
  if figures:
    points, colors = domain.elem_eval([ns.x, ns.u], ischeme='bezier9', separate=True)
    with plot.PyPlot('solution', index=nelems) as plt:
      plt.mesh(points, colors, cmap='jet')
      plt.colorbar()

  # evaluate error against exact solution fx fy
  err = domain.integrate('(u - fx fy)^2' @ ns, geometry=ns.x, degree=degree*2)**.5
  log.user('L2 error: {:.2e}'.format(err))

  return cons, lhs, err
示例#13
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 = 1
   self.inertia = domain.integral((ubasis * u).sum(-1), geometry=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), geometry=geom, degree=5)
   self.residual = stokesres + domain.integral((ubasis * (u.grad(geom) * u).sum(-1) * u).sum(-1), geometry=geom, degree=5)
   self.cons = domain.boundary['top,bottom'].project([0,0], onto=ubasis, geometry=geom, ischeme='gauss2') \
             | domain.boundary['left'].project([geom[1]*(1-geom[1]),0], onto=ubasis, geometry=geom, ischeme='gauss2')
   self.lhs0 = solver.solve_linear('dofs', residual=stokesres, constrain=self.cons)
   self.tol = 1e-10
示例#14
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])

  # create namespace
  ns = function.Namespace(default_geometry_name='x0')
  ns.x0 = geom
  ns.basis = domain.basis('spline', degree=degree).vector(2)
  ns.u_i = 'basis_ni ?lhs_n'
  ns.x_i = 'x0_i + u_i'
  ns.lmbda = lmbda
  ns.mu = mu
  ns.strain_ij = '(u_i,j + u_j,i) / 2'
  ns.stress_ij = 'lmbda strain_kk δ_ij + 2 mu strain_ij'

  # construct dirichlet boundary constraints
  sqr = domain.boundary['left'].integral('u_k u_k' @ ns, geometry=ns.x0, degree=2)
  sqr += domain.boundary['right'].integral('(u_0 - .5)^2' @ ns, geometry=ns.x0, degree=2)
  cons = solver.optimize('lhs', sqr, droptol=1e-15)

  # construct residual
  res = domain.integral('basis_ni,j stress_ij' @ ns, geometry=ns.x0, degree=2)

  # solve system and substitute the solution in the namespace
  lhs = solver.solve_linear('lhs', res, constrain=cons)
  ns |= dict(lhs=lhs)

  # plot solution
  if withplots:
    points, colors = domain.elem_eval([ns.x, ns.stress[0,1]], ischeme='bezier3', separate=True)
    with plot.PyPlot('stress', ndigits=0) as plt:
      plt.mesh(points, colors, tight=False)
      plt.colorbar()

  return lhs, cons
示例#15
0
def main(aquifer, degree: int, btype: str, elems: int, rw: unit['m'],
         rmax: unit['m'], H: unit['m'], mu: unit['Pa*s'], φ: float,
         ctinv: unit['Pa'], k_int: unit['m2'], Q: unit['m3/s'],
         timestep: unit['s'], t1endtime: unit['s']):
    '''
    Fluid flow in porous media.

    .. arguments::

       degree [2]
         Polynomial degree for pressure space.

       btype [spline]
         Type of basis function (std/spline).

       elems [30]
         Number of elements.

       rw [0.1m]
         Well radius.

       rmax [1000m]
         Far field radius of influence.

       H [100m]
         Vertical thickness of reservoir.

       mu [0.31mPa*s]
         Dynamic fluid viscosity.

       φ [0.2]
         Porosity.

       ctinv [10GPa]
         Inverse of total compressibility.

       k_int [0.1μm2]
         Intrinsic permeability.

       Q [0.05m3/s]
         Injection rate.

       timestep [60s]
         Time step.

       t1endtime [300s]
         Number of time steps per timeperiod (drawdown or buildup).

    '''

    # define total time and steps
    N = round(t1endtime / timestep)
    timeperiod = timestep * np.linspace(0, 2 * N, 2 * N + 1)

    # define vertices of radial grid
    rverts = np.logspace(np.log2(rw),
                         np.log2(rmax),
                         elems + 1,
                         base=2.0,
                         endpoint=True)
    θverts = [0, 2 * np.pi]
    zverts = np.linspace(0, H, elems + 1)

    topo, geom = mesh.rectilinear([rverts, zverts, θverts], periodic=[2])
    topo = topo.withboundary(inner=topo.boundary['left'],
                             outer=topo.boundary['right'])
    topo = topo.withboundary(strata=topo.boundary -
                             topo.boundary['inner,outer'])
    assert (topo.boundary['inner'].sample('bezier', 2).eval(
        geom[0]) == rw).all(), "Invalid inner boundary condition"
    assert (topo.boundary['outer'].sample('bezier', 2).eval(
        geom[0]) == rmax).all(), "Invalid outer boundary condition"

    ns = function.Namespace()
    ns.r, ns.z, ns.θ = geom
    ns.x_i = '<r cos(θ), z, r sin(θ)>_i'

    # set periodic basis function constant
    ns.pbasis = topo.basis('spline', degree=(1, 1, 0))
    ns.Tbasis = topo.basis('spline', degree=(1, 1, 0))

    # retrieve the well boundary
    ns.Aw = topo.boundary['inner'].integrate("d:x" @ ns, degree=1)
    ns.Aw2 = 2 * math.pi * rw * H
    assert (
        np.round_(ns.Aw.eval() -
                  ns.Aw2.eval()) == 0), "Area of inner boundary does not match"

    # problem variables         # unit
    ns.Q = Q  # [m^3/s]
    ns.H = H  # [m]
    ns.rw = rw  # [m]
    ns.rmax = rmax  # [m]
    ns.φ = φ  # [-]
    ns.ct = 1 / ctinv
    # ns.ctφ = 1e-9             # [1/Pa]
    # ns.ctf = 5e-10            # [1/Pa]
    ns.Jw = ns.Q / ns.H  # [m^2/s]
    ns.mu = aquifer.mu
    ns.cf = aquifer.cpf  # [J/kg K]
    ns.cs = aquifer.cps  # [J/kg K]
    ns.ρf = aquifer.rhof  # [kg/m^3]
    ns.ρs = aquifer.rhos  # [kg/m^3]
    ns.λf = aquifer.labdaf  # [W/mk]
    ns.λs = aquifer.labdas  # [W/mk]
    ns.g = aquifer.g  # [m/s^2]             # ns.ge_i = '<0,-g, 0>_i'
    ns.k = k_int
    ns.uw = 'Q / Aw'
    ns.K = k_int / mu
    # ns.K = np.diag(k_int) / (ns.mu)  # [m/s] *[1/rho g]
    # ns.q_i = '-K_ij (p_,j - ρf ge_i,j)' #[s * Pa* 1/m] = [Pa*s/m] ρf g x_1,j
    # ns.u_i = 'q_i / φ '         # [m/s]
    ns.T0 = aquifer.Tref  # [K] #88.33+273

    # total system (rock + fluid) variable
    ns.ρ = ns.φ * ns.ρf + (1 - ns.φ) * ns.ρs
    ns.cp = ns.φ * ns.cf + (1 - ns.φ) * ns.cs
    ns.λ = ns.φ * ns.λf + (1 - ns.φ) * ns.λs

    ###########################
    # Solve by implicit euler #
    ###########################
    #
    # # introduce temperature dependent variables
    # # ns.ρf = 1000 * (1 - 3.17e-4 * (ns.T - 298.15) - 2.56e-6 * (ns.T - 298.15)**2)
    # # ns.cf = 4187.6 * (-922.47 + 2839.5 * (ns.T / ns.Tatm) - 1800.7 * (ns.T / ns.Tatm)**2 + 525.77*(ns.T / ns.Tatm)**3 - 73.44*(ns.T / ns.Tatm)**4)
    # # ns.cf = 3.3774 - 1.12665e-2 * ns.T + 1.34687e-5 * ns.T**2 # if temperature above T=100 [K]
    # # ns.mu = PropsSI('V', 'T', ns.T.eval(), 'P', ns.p.eval(), 'IF97::Water') # note to self: temperature dependency
    # ns.ρf = PropsSI('D', 'T', ns.T.eval(), 'P', ns.p.eval(), 'IF97::Water') # note to self: temperature dependency
    #
    # # define initial state
    # sqr = topo.integral('(p - p0)^2' @ ns, degree=degree*2)
    # pdofs0 = solver.optimize('lhsp', sqr, droptol=1e-15)
    #
    # # define dirichlet constraints
    # sqrp = topo.boundary['outer'].integral('(p - p0)^2 d:x' @ ns, degree=degree*2)
    # # sqrp += topo.boundary['inner'].integral('(p - pw)^2 d:x' @ ns, degree=degree*2) #presdefined well pressure
    # consp = solver.optimize('lhsp', sqrp, droptol=1e-15)
    #
    # # formulate hydraulic process single field
    # # resp = topo.integral('(-pbasis_n,i q_i) d:x' @ ns, degree=degree*4)
    # # resp += topo.boundary['strata'].integral('(pbasis_n q_i n_i) d:x' @ ns, degree=degree*4)
    # # respwell = topo.boundary['inner'].integral('pbasis_n (δ_i0 n_i + uw) d:x' @ ns, degree=2)  # massabalans bron
    # # respwell = topo.boundary['inner'].integral('pbasis_n uw d:x' @ ns, degree=2)  # massabalans bron
    # # lhsp = solver.newton('lhsp', respwell, constrain=consp, arguments=dict(lhsp=pdofs0)).solve(tol=1e-10)
    #
    # resp = -topo.integral('pbasis_n,i q_i d:x' @ ns, degree=6)
    # # respd = resp - topo.boundary['inner'].integral('pbasis_n (q_i n_i - uw) d:x' @ ns, degree=degree * 2)
    # respd = resp + topo.boundary['inner'].integral('pbasis_n (- uw φ) d:x' @ ns, degree=degree * 2)
    #
    # # ns.Δt = timestep
    # # ns.p = 'pbasis_n ?lhsp_n'
    # # ns.p0 = 'pbasis_n ?lhsp0_n'
    # # ns.δp = '(p - p0) / Δt'
    #
    # # print("residue well", respwell.eval())
    # # respd = resp - respwell
    # # lhsp = solver.solve_linear('lhsp', respd, constrain=consp, arguments=dict(lhsp=pdofs0))
    # # bezier = topo.sample('bezier', 5)
    # # residuep, respwell = bezier.eval(['resp', 'respwell'] @ ns, lhsp=lhsp)
    # # print("residuep", residuep.eval())
    #
    # # lhsp0 = solver.solve_linear('lhsp', respwell, constrain=consp, arguments={'lhsp0': pdofs0}) #los eerst massabalans over de put randvoorwaarde op
    #
    # respb = resp
    # pinertia = topo.integral('pbasis_n (φ ct p) d:x' @ ns, degree=6) #φ ρf ct
    #
    # # define initial condition for thermo process
    # sqr = topo.integral('(T - T0) (T - T0)' @ ns, degree=degree * 2)
    # Tdofs0 = solver.optimize('lhsT', sqr)
    #
    # # define dirichlet constraints for thermo process
    # sqrT = topo.boundary['outer'].integral('(T - T0) (T - T0) d:x' @ ns, degree=degree * 2)
    # consT = solver.optimize('lhsT', sqrT, droptol=1e-15)
    #
    # # formulate thermo process
    # resT = topo.integral('(ρf cf Tbasis_n (q_i T)_,i) d:x' @ ns, degree=degree * 2) #(u_k T)_,k
    # resT += topo.integral('(Tbasis_n,i (- λ) T_,i) d:x' @ ns, degree=degree * 2)
    # resT -= topo.boundary['strata'].integral('(Tbasis_n T_,i n_i) d:x' @ ns, degree=degree*4)
    # resT -= topo.boundary['inner'].integral('(Tbasis_n ρf uw cf T_,i n_i) d:x' @ ns, degree=degree*4)
    # resT2 = resT + topo.boundary['inner'].integral('(Tbasis_n ρf uw cf T_,i n_i) d:x' @ ns, degree=degree*4)
    # # resT -= topo.boundary['top,bottom'].integral('Tbasis_n qh d:x' @ ns, degree=degree * 2)  # heat flux on boundary
    # Tinertia = topo.integral('(ρ cp Tbasis_n T) d:x' @ ns, degree=degree * 4)
    #
    # plottopo = topo[:, :, 0:].boundary['back']
    #
    # # locally refine
    # # nref = 4
    # # ns.sd = (ns.x[0]) ** 2
    # # refined_topo = RefineBySDF(plottopo, ns.rw, geom[0], nref)
    #
    # plottopo = topo[:, :, 0:].boundary['back']
    # # mesh
    # bezier = plottopo.sample('bezier', 2)
    # with export.mplfigure('mesh.png', dpi=800) as fig:
    #     r, z, col = bezier.eval([ns.r, ns.z, 1])
    #     ax = fig.add_subplot(1, 1, 1)
    #     ax.tripcolor(r, z, bezier.tri, col, shading='gouraud', rasterized=True)
    #     ax.add_collection(
    #         collections.LineCollection(np.array([r, z]).T[bezier.hull], colors='k', linewidths=0.2,
    #                                    alpha=0.2))
    #
    # bezier = plottopo.sample('bezier', 9)
    # solve for steady state state of pressure
    # lhsp = solver.solve_linear('lhsp', resp, constrain=consp)

    # construct empty arrays
    parraywell = np.empty([2 * N + 1])
    parrayexact = np.empty(2 * N + 1)
    Tarraywell = np.empty(2 * N + 1)
    Tarrayexact = np.empty(2 * N + 1)
    Qarray = np.empty(2 * N + 1)
    dparraywell = np.empty([2 * N + 1])
    parrayexp = np.empty(2 * N + 1)
    Tarrayexp = np.empty(2 * N + 1)

    ##############################
    # Linear system of equations #
    ##############################

    with treelog.iter.fraction('step', range(2 * N + 1)) as counter:
        for istep in counter:
            time = timestep * istep

            # define problem
            ns.Δt = timestep
            ns.p = 'pbasis_n ?plhs_n'
            ns.p0 = 'pbasis_n ?plhs0_n'
            ns.δp = '(p - p0) / Δt'
            ns.T = 'Tbasis_n ?Tlhs_n'
            ns.T0 = 'Tbasis_n ?Tlhs0_n'
            ns.δT = '(T - T0) / Δt'
            ns.k = k_int
            ns.mu = mu
            ns.q_i = '-(  k  / mu ) p_,i'
            ns.v = 'Q / Aw'
            ns.pref = 225e5  # [Pa]
            ns.Tref = 90 + 273  # [K]
            ns.Twell = 88 + 273  # [K]
            ns.epsilonjt = 2e-7
            ns.constantjt = ns.epsilonjt
            ns.cpratio = (ns.ρf * ns.cf) / (ns.ρ * ns.cp)
            ns.phieff = 0  #ns.φ * ns.cpratio * (ns.epsilonjt + 1/(ns.ρf * ns.cf))

            # add artificial diffusion
            ns.hmin = (rverts[1] - rverts[0])
            strength = 0  # set strength
            ns.ε = strength * ns.hmin * ns.ρf * ns.cf  # calculate artificial diffusion
            ns.qh_i = '-(λ + ε) T_,i'  # set in weak formulation
            print("hmin",
                  ns.hmin.eval(), "c", (ns.ρf * ns.cf).eval(), "diffusion",
                  ns.λ.eval(), 'artificial diffusion', ns.ε.eval())

            psqr = topo.boundary['outer'].integral(
                '( (p - pref)^2 ) d:x' @ ns, degree=2)  # farfield pressure
            pcons = solver.optimize('plhs', psqr, droptol=1e-15)
            Tsqr = topo.boundary['outer'].integral(
                '( (T - Tref)^2 ) d:x' @ ns, degree=2)  # farfield temperature
            Tcons = solver.optimize('Tlhs', Tsqr, droptol=1e-15)

            if istep == 0:
                psqr = topo.integral('( (p - pref)^2 ) d:x' @ ns, degree=2)
                Tsqr = topo.integral('( (T - Tref)^2) d:x' @ ns, degree=2)
                Tsqr += topo.boundary['inner'].integral(
                    '( (T - Twell)^2 ) d:x' @ ns,
                    degree=2)  # initial well temperature
                plhs0 = solver.optimize('plhs', psqr, droptol=1e-15)
                Tlhs0 = solver.optimize('Tlhs', Tsqr, droptol=1e-15)
            else:
                psqr = topo.integral('( (p - pref)^2) d:x' @ ns, degree=2)
                Tsqr = topo.integral('( (T - Tref)^2) d:x' @ ns, degree=2)
                plhs0new = solver.optimize('plhs', psqr, droptol=1e-15)
                Tlhs0new = solver.optimize('Tlhs', Tsqr, droptol=1e-15)
                plhs0new = plhs0new.copy()
                Tlhs0new = Tlhs0new.copy()
                plhs0new[:len(plhs0)] = plhs0
                Tlhs0new[:len(Tlhs0)] = Tlhs0
                plhs0 = plhs0new.copy()
                Tlhs0 = Tlhs0new.copy()

            pres = -topo.integral('pbasis_n,i q_i d:x' @ ns,
                                  degree=6)  # convection term darcy
            pres -= topo.boundary['strata, inner'].integral(
                '(pbasis_n q_i n_i) d:x' @ ns, degree=degree * 3)

            Tres = topo.integral('(Tbasis_n ρf cf q_i T_,i) d:x' @ ns,
                                 degree=degree *
                                 2)  # convection term ( totaal moet - zijn)
            Tres += topo.integral('(Tbasis_n,i qh_i) d:x' @ ns,
                                  degree=degree *
                                  2)  # conduction term ( totaal moet - zijn)
            Tres -= topo.integral(
                '(Tbasis_n epsilonjt ρf cf q_i p_,i) d:x' @ ns,
                degree=degree * 2)  # J-T effect ( totaal moet + zijn)

            if istep > 0:
                pres += topo.integral('pbasis_n (φ ct) δp d:x' @ ns,
                                      degree=degree * 3)  # storativity aquifer
                pres += topo.boundary['inner'].integral(
                    'pbasis_n v d:x' @ ns, degree=6)  # mass conservation well
                Tres += topo.integral('Tbasis_n (ρ cp) δT d:x' @ ns,
                                      degree=degree *
                                      3)  # heat storage aquifer
                Tres += topo.boundary['inner'].integral(
                    '(Tbasis_n ρf cf v n_i T_,i) d:x' @ ns,
                    degree=degree * 2)  # neumann bc

            if istep == (N + 1):
                ns.Td = bezier.eval(['T'] @ ns, Tlhs=Tlhs)[0][0]

            if istep > N:
                pres -= topo.boundary['inner'].integral(
                    'pbasis_n v d:x' @ ns, degree=6)  # mass conservation well
                Tres -= topo.boundary['inner'].integral(
                    '(Tbasis_n ρf cf v n_i T_,i) d:x' @ ns,
                    degree=degree * 2)  # remove neumann bc

                Tsqr += topo.boundary['inner'].integral(
                    '( (T - Td)^2 ) d:x' @ ns, degree=2)
                Tcons = solver.optimize('Tlhs', Tsqr,
                                        droptol=1e-15)  # add dirichlet bc

            plhs = solver.solve_linear('plhs',
                                       pres,
                                       constrain=pcons,
                                       arguments={'plhs0': plhs0})
            Tlhs = solver.solve_linear('Tlhs',
                                       Tres,
                                       constrain=Tcons,
                                       arguments={
                                           'plhs': plhs,
                                           'Tlhs0': Tlhs0
                                       })

            # Tresneumann = topo.boundary['inner'].integral('(Tbasis_n ρf cf v n_i T_,i) d:x' @ ns, degree=degree * 2)
            # neumann = Tresneumann.eval(Tlhs=Tlhs)
            # print("Neumann eval", neumann)

            q_inti = topo.boundary['inner'].integral('(q_i n_i) d:x' @ ns,
                                                     degree=6)
            q = q_inti.eval(plhs=plhs)
            dT_inti = topo.boundary['inner'].integral('(T_,i n_i) d:x' @ ns,
                                                      degree=6)
            dT = dT_inti.eval(Tlhs=Tlhs)
            dp_inti = topo.boundary['inner'].integral('(p_,i n_i) d:x' @ ns,
                                                      degree=6)
            dp = dp_inti.eval(plhs=plhs)

            # print("the fluid flux in the FEA simulated:", q, "the flux that you want to impose:", (ns.v).eval())
            # print("the temperature gradient in the FEA simulated:", dT, "the temperature that you want to impose:")

            plottopo = topo[:, :, 0:].boundary['back']

            ###########################
            #     Post processing     #
            ###########################

            bezier = plottopo.sample('bezier', 7)
            x, q, p, T = bezier.eval(['x_i', 'q_i', 'p', 'T'] @ ns,
                                     plhs=plhs,
                                     Tlhs=Tlhs)

            # compute analytical solution
            if time <= t1endtime:
                Qarray[istep] = Q

                parrayexact[istep] = panalyticaldrawdown(ns, time, ns.rw)
                parraywell[istep] = nanjoin(p, bezier.tri)[::100][0]
                print("pwellFEA", parraywell[istep], "pwellEX",
                      parrayexact[istep])

                # pgrad = dpanalyticaldrawdown(ns, t1, ns.rw)                 # print("gradient pressure exact", pgrad)                 # print("gradient pressure", dp)

                Tarrayexact[istep] = Tanalyticaldrawdown(ns, time, ns.rw)
                Tarraywell[istep] = T.take(bezier.tri.T, 0)[1][0]
                print("TwellFEA", Tarraywell[istep], "TwellEX",
                      Tarrayexact[istep])

                plotdrawdown_1D(ns, bezier, x, p, T, time)

            else:
                Qarray[istep] = 0

                parrayexact[istep] = panalyticalbuildup(
                    ns, t1endtime, time, ns.rw)
                parraywell[istep] = p.take(bezier.tri.T, 0)[1][0]
                print("pwellFEA", parraywell[istep], "pwellEX",
                      parrayexact[istep])

                Tarrayexact[istep] = Tanalyticalbuildup(
                    ns, t1endtime, time, ns.rw)
                Tarraywell[istep] = T.take(bezier.tri.T, 0)[1][0]
                print("TwellFEA", Tarraywell[istep], "TwellEX",
                      Tarrayexact[istep])

                plotbuildup_1D(ns, bezier, x, p, T, t1endtime, time)

            if time >= 2 * t1endtime:  #export
                parrayerror = np.abs(np.subtract(parraywell, parrayexact))
                # with export.mplfigure('pressure.png', dpi=800) as fig:
                #     ax = fig.add_subplot(111, title='pressure', aspect=1)
                #     ax.autoscale(enable=True, axis='both', tight=True)
                #     im = ax.tripcolor(x[:, 0], x[:, 1], bezier.tri, p, shading='gouraud', cmap='jet')
                #     ax.add_collection(
                #         collections.LineCollection(np.array([x[:, 0], x[:, 1]]).T[bezier.hull], colors='k',
                #                                    linewidths=0.2,
                #                                    alpha=0.2))
                #     fig.colorbar(im)
                #
                # with export.mplfigure('temperature.png', dpi=800) as fig:
                #     ax = fig.add_subplot(111, title='temperature', aspect=1)
                #     ax.autoscale(enable=True, axis='both', tight=True)
                #     im = ax.tripcolor(x[:, 0], x[:, 1], bezier.tri, TT, shading='gouraud', cmap='jet')
                #     ax.add_collection(
                #         collections.LineCollection(np.array([x[:, 0], x[:, 1]]).T[bezier.hull], colors='k', linewidths=0.2,
                #                                    alpha=0.2))
                #     fig.colorbar(im)
                #
                # with export.mplfigure('temperature1d.png', dpi=800) as plt:
                #     ax = plt.subplots()
                #     ax.set(xlabel='Distance [m]', ylabel='Temperature [K]')
                #     ax.plot(nanjoin(x[:, 0], bezier.tri)[::100], nanjoin(TT, bezier.tri)[::100], label="FEM")
                #     ax.plot(x[:, 0][::100],
                #             np.array(Tanalyticaldrawdown(ns, t1, x[:, 0][::100]))[0][0][0],
                #             label="analytical")
                #     ax.legend(loc="center right")

                # plotovertime(timeperiod, parraywell, parrayexact, Tarraywell, Tarrayexact, Qarray)

                # mesh
                # bezier = plottopo.sample('bezier', 2)
                #
                # with export.mplfigure('mesh.png', dpi=800) as fig:
                #     r, z, col = bezier.eval([ns.r, ns.z, 1])
                #     ax = fig.add_subplot(1, 1, 1)
                #     ax.tripcolor(r, z, bezier.tri, col, shading='gouraud', rasterized=True)
                #     ax.add_collection(
                #         collections.LineCollection(np.array([r, z]).T[bezier.hull], colors='k', linewidths=0.2,
                #                                    alpha=0.2))

                # export.vtk('aquifer', bezier.tri, bezier.eval(ns.x)) #export
                # break

            plhs0 = plhs.copy()
            Tlhs0 = Tlhs.copy()

            # with export.mplfigure('pressure.png', dpi=800) as fig:
            #     ax = fig.add_subplot(111, title='pressure', aspect=1)
            #     ax.autoscale(enable=True, axis='both', tight=True)
            #     im = ax.tripcolor(x[:, 0], x[:, 1], bezier.tri, p, shading='gouraud', cmap='jet')
            #     ax.add_collection(
            #         collections.LineCollection(np.array([x[:, 0], x[:, 1]]).T[bezier.hull], colors='k',
            #                                    linewidths=0.2,
            #                                    alpha=0.2))
            #     fig.colorbar(im)

        return parraywell, Tarraywell

    # with treelog.iter.plain(
    #         'timestep', solver.impliciteuler(['lhsp', 'lhsT'], (respd, resT), (pinertia, Tinertia), timetarget='t', timestep=timestep, arguments=dict(lhsp=pdofs0, lhsT=Tdofs0), constrain=(dict(lhsp=consp, lhsT=consT)), newtontol=newtontol)) as steps:
    #
    #     for istep, lhs in enumerate(steps):
    #         time = istep * timestep
    #         print("time", time)
    #
    #         # define analytical solution
    #         pex = panalyticaldrawdown(ns, time)
    #
    #         # # define analytical solution
    #         Tex = Tanalyticaldrawdown(ns, time)
    #
    #         x, r, z, p, u, p0, T = bezier.eval(
    #             [ns.x, ns.r, ns.z, ns.p, function.norm2(ns.u), ns.p0, ns.T], lhsp=lhs["lhsp"], lhsT = lhs["lhsT"])
    #
    #         parraywell[istep] = p.take(bezier.tri.T, 0)[1][0]
    #         parrayexact[istep] = pex
    #         Qarray[istep] = ns.Jw.eval()
    #         print("flux in analytical", ns.Jw.eval())
    #         # print("flux in FEM", ns.respwell.eval())
    #         # print("flux in fem", sum(respwell.eval()))
    #
    #         parrayexp[istep] = get_welldata("PRESSURE")[istep]/10
    #
    #         print("well pressure ", parraywell[istep])
    #         print("exact well pressure", pex)
    #         # print("data well pressure", parrayexp[istep])
    #
    #         Tarraywell[istep] = T.take(bezier.tri.T, 0)[1][0]
    #         Tarrayexact[istep] = Tex
    #         Tarrayexp[istep] = get_welldata("TEMPERATURE")[istep]+273
    #
    #         print("well temperature ", Tarraywell[istep])
    #         print("exact well temperature", Tex)
    #         # print("data well temperature", Tarrayexp[istep])
    #
    #         if time >= t1endtime:
    #
    #             with export.mplfigure('pressure.png', dpi=800) as fig:
    #                 ax = fig.add_subplot(111, title='pressure', aspect=1)
    #                 ax.autoscale(enable=True, axis='both', tight=True)
    #                 im = ax.tripcolor(r, z, bezier.tri, p, shading='gouraud', cmap='jet')
    #                 ax.add_collection(
    #                     collections.LineCollection(np.array([r, z]).T[bezier.hull], colors='k', linewidths=0.2,
    #                                                alpha=0.2))
    #                 fig.colorbar(im)
    #
    #             with export.mplfigure('pressure1d.png', dpi=800) as plt:
    #                 ax = plt.subplots()
    #                 ax.set(xlabel='Distance [m]', ylabel='Pressure [MPa]')
    #                 print("pressure array", p.take(bezier.tri.T, 0))
    #                 ax.plot(r.take(bezier.tri.T, 0), p.take(bezier.tri.T, 0))
    #
    #             with export.mplfigure('temperature.png', dpi=800) as fig:
    #                 ax = fig.add_subplot(111, title='temperature', aspect=1)
    #                 ax.autoscale(enable=True, axis='both', tight=True)
    #                 im = ax.tripcolor(r, z, bezier.tri, T, shading='gouraud', cmap='jet')
    #                 ax.add_collection(
    #                     collections.LineCollection(np.array([r, z]).T[bezier.hull], colors='k', linewidths=0.2,
    #                                                alpha=0.2))
    #                 fig.colorbar(im)
    #
    #             with export.mplfigure('temperature1d.png', dpi=800) as plt:
    #                 ax = plt.subplots()
    #                 ax.set(xlabel='Distance [m]', ylabel='Temperature [K]')
    #                 ax.plot(r.take(bezier.tri.T, 0), T.take(bezier.tri.T, 0))
    #
    #             uniform = plottopo.sample('uniform', 1)
    #             r_, z_, uv = uniform.eval(
    #                 [ns.r, ns.z, ns.u], lhsp=lhs["lhsp"])
    #
    #             with export.mplfigure('velocity.png', dpi=800) as fig:
    #                 ax = fig.add_subplot(111, title='Velocity', aspect=1)
    #                 ax.autoscale(enable=True, axis='both', tight=True)
    #                 im = ax.tripcolor(r, z, bezier.tri, u, shading='gouraud', cmap='jet')
    #                 ax.quiver(r_, z_, uv[:, 0], uv[:, 1], angles='xy', scale_units='xy')
    #                 fig.colorbar(im)
    #
    #             with export.mplfigure('pressuretime.png', dpi=800) as plt:
    #                 ax1 = plt.subplots()
    #                 ax2 = ax1.twinx()
    #                 ax1.set(xlabel='Time [s]')
    #                 ax1.set_ylabel('Pressure [MPa]', color='b')
    #                 ax2.set_ylabel('Volumetric flow rate [m^3/s]', color='k')
    #                 ax1.plot(timeperiod, parraywell/1e6, 'bo', label="FEM")
    #                 ax1.plot(timeperiod, parrayexact/1e6, label="analytical")
    #                 # ax1.plot(timeperiod, parrayexp, label="NLOG")
    #                 ax1.legend(loc="center right")
    #                 ax2.plot(timeperiod, Qarray, 'k')
    #
    #             with export.mplfigure('temperaturetime.png', dpi=800) as plt:
    #                 ax = plt.subplots()
    #                 ax.set(xlabel='Time [s]', ylabel='Temperature [K]')
    #                 ax.plot(timeperiod, Tarraywell, 'ro')
    #                 ax.plot(timeperiod, Tarrayexact)
    #                 # ax.plot(timeperiod, Tarrayexp)
    #
    #             break
    #
    # with treelog.iter.plain(
    #         'timestep', solver.impliciteuler(['lhsp', 'lhsT'], (respb, resT2), (pinertia, Tinertia), timestep=timestep,
    #                              arguments=dict(lhsp=lhs["lhsp"], lhsT=lhs["lhsT"]), constrain=(dict(lhsp=consp, lhsT=consT)),
    #                              newtontol=newtontol)) as steps:
    #         # 'timestep', solver.impliciteuler(('lhsp'), resp2, pinertia, timestep=timestep, arguments=dict(lhsp=lhsp), constrain=consp, newtontol=1e-2)) as steps:
    #     time = 0
    #     istep = 0
    #
    #     for istep, lhs2 in enumerate(steps):
    #         time = istep * timestep
    #
    #         # define analytical solution
    #         pex2 = panalyticalbuildup(ns, time, pex)
    #
    #         # define analytical solution
    #         Tex2 = Tanalyticalbuildup(ns, time, Tex)
    #
    #         x, r, z, p, u, p0, T = bezier.eval(
    #             [ns.x, ns.r, ns.z, ns.p, function.norm2(ns.u), ns.p0, ns.T], lhsp=lhs2["lhsp"], lhsT=lhs2["lhsT"])
    #
    #         parraywell[N+istep] = p.take(bezier.tri.T, 0)[1][0]
    #         Qarray[N+istep] = 0
    #         parrayexact[N+istep] = pex2
    #         # print(get_welldata("PRESSURE")[213+istep]/10)
    #         # parrayexp[N+istep] = get_welldata("PRESSURE")[212+istep]/10
    #
    #         print("well pressure ", parraywell[N+istep])
    #         print("exact well pressure", pex2)
    #         # print("data well pressure", parrayexp[N+istep])
    #
    #         Tarraywell[N+istep] = T.take(bezier.tri.T, 0)[1][0]
    #         Tarrayexact[N+istep] = Tex2
    #         # Tarrayexp[N+istep] = get_welldata("TEMPERATURE")[212+istep]+273
    #
    #         print("well temperature ", Tarraywell[N+istep])
    #         print("exact well temperature", Tex2)
    #         # print("data well temperature", Tarrayexp[N+istep])
    #
    #         if time >= t1endtime:
    #
    #             with export.mplfigure('pressure.png', dpi=800) as fig:
    #                 ax = fig.add_subplot(111, title='pressure', aspect=1)
    #                 ax.autoscale(enable=True, axis='both', tight=True)
    #                 im = ax.tripcolor(r, z, bezier.tri, p, shading='gouraud', cmap='jet')
    #                 ax.add_collection(
    #                     collections.LineCollection(np.array([r, z]).T[bezier.hull], colors='k', linewidths=0.2,
    #                                                alpha=0.2))
    #                 fig.colorbar(im)
    #
    #             with export.mplfigure('pressure1d.png', dpi=800) as plt:
    #                 ax = plt.subplots()
    #                 ax.set(xlabel='Distance [m]', ylabel='Pressure [MPa]')
    #                 ax.plot(r.take(bezier.tri.T, 0), p.take(bezier.tri.T, 0))
    #
    #             uniform = plottopo.sample('uniform', 1)
    #             r_, z_, uv = uniform.eval(
    #                 [ns.r, ns.z, ns.u], lhsp=lhs2["lhsp"])
    #
    #             with export.mplfigure('temperature.png', dpi=800) as fig:
    #                 ax = fig.add_subplot(111, title='temperature', aspect=1)
    #                 ax.autoscale(enable=True, axis='both', tight=True)
    #                 im = ax.tripcolor(r, z, bezier.tri, T, shading='gouraud', cmap='jet')
    #                 ax.add_collection(
    #                     collections.LineCollection(np.array([r, z]).T[bezier.hull], colors='k', linewidths=0.2,
    #                                                alpha=0.2))
    #                 fig.colorbar(im)
    #
    #             with export.mplfigure('temperature1d.png', dpi=800) as plt:
    #                 ax = plt.subplots()
    #                 ax.set(xlabel='Distance [m]', ylabel='Temperature [K]')
    #                 ax.plot(r.take(bezier.tri.T, 0), T.take(bezier.tri.T, 0))
    #
    #             with export.mplfigure('velocity.png', dpi=800) as fig:
    #                 ax = fig.add_subplot(111, title='Velocity', aspect=1)
    #                 ax.autoscale(enable=True, axis='both', tight=True)
    #                 im = ax.tripcolor(r, z, bezier.tri, u, shading='gouraud', cmap='jet')
    #                 ax.quiver(r_, z_, uv[:, 0], uv[:, 1], angles='xy', scale_units='xy')
    #                 fig.colorbar(im)
    #
    #             with export.mplfigure('pressuretimebuildup.png', dpi=800) as plt:
    #                 ax1 = plt.subplots()
    #                 ax2 = ax1.twinx()
    #                 ax1.set(xlabel='Time [s]')
    #                 ax1.set_ylabel('Pressure [MPa]', color='b')
    #                 ax2.set_ylabel('Volumetric flow rate [m^3/s]', color='k')
    #                 ax1.plot(timeperiod, parraywell/1e6, 'bo', label="FEM")
    #                 ax1.plot(timeperiod, parrayexact/1e6, label="analytical")
    #                 # ax1.plot(timeperiod, parrayexp, label="NLOG")
    #                 ax1.legend(loc="center right")
    #                 ax2.plot(timeperiod, Qarray, 'k')
    #
    #             with export.mplfigure('temperaturetime.png', dpi=800) as plt:
    #                 ax1 = plt.subplots()
    #                 ax2 = ax1.twinx()
    #                 ax1.set(xlabel='Time [s]')
    #                 ax1.set_ylabel('Temperature [K]', color='r')
    #                 ax2.set_ylabel('Volumetric flow rate [m^3/s]', color='k')
    #                 ax1.plot(timeperiod, Tarraywell, 'ro', label="FEM")
    #                 ax1.plot(timeperiod, Tarrayexact, 'r', label="analytical")
    #                 # ax1.plot(timeperiod, Tarrayexp, label="NLOG")
    #                 ax1.legend(loc="lower right")
    #                 ax2.plot(timeperiod, Qarray, 'k')
    #
    #                 # export.vtk('aquifer', bezier.tri, bezier.eval(ns.x))
    #
    #             break
    return
示例#16
0
 def test_direct(self):
     with self.assertRaises(solver.SolverError):
         self.assert_resnorm(
             solver.solve_linear('dofs',
                                 residual=self.residual,
                                 constrain=self.cons))
示例#17
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,
    figures: 'create figures' = True,
  ):

  ns = function.Namespace()
  ns.lmbda = E*nu/(1-nu**2)
  ns.mu = .5*E/(1+nu)

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

  # create the second-order B-spline basis over the coarsest domain
  ns.bsplinebasis = domain0.basis('spline', degree=2)
  ns.controlweights = 1,.5+.5/2**.5,.5+.5/2**.5,1,1,1,1,1,1,1,1,1
  ns.weightfunc = 'bsplinebasis_n controlweights_n'
  ns.nurbsbasis = ns.bsplinebasis * ns.controlweights / ns.weightfunc

  # create the isogeometric map
  ns.controlpoints = [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]
  ns.x_i = 'nurbsbasis_n controlpoints_ni'

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

  # create the second-order B-spline basis over the refined domain
  ns.bsplinebasis = domain.basis('spline', degree=2)
  sqr = domain.integral('(bsplinebasis_n ?lhs_n - weightfunc)^2' @ ns, geometry=ns.x, degree=9)
  ns.controlweights = solver.optimize('lhs', sqr)
  ns.nurbsbasis = ns.bsplinebasis * ns.controlweights / ns.weightfunc

  # prepare the displacement field
  ns.ubasis = ns.nurbsbasis.vector(2)
  ns.u_i = 'ubasis_ni ?lhs_n'
  ns.strain_ij = '(u_i,j + u_j,i) / 2'
  ns.stress_ij = 'lmbda strain_kk δ_ij + 2 mu strain_ij'

  # construct the exact solution
  ns.r2 = 'x_k x_k'
  ns.R2 = R**2
  ns.T = T
  ns.k = (3-nu) / (1+nu) # plane stress parameter
  ns.uexact_i = '''(T / 4 mu) <x_0 ((k + 1) / 2 + (1 + k) R2 / r2 + (1 - R2 / r2) (x_0^2 - 3 x_1^2) R2 / r2^2),
                               x_1 ((k - 3) / 2 + (1 - k) R2 / r2 + (1 - R2 / r2) (3 x_0^2 - x_1^2) R2 / r2^2)>_i'''
  ns.strainexact_ij = '(uexact_i,j + uexact_j,i) / 2'
  ns.stressexact_ij = 'lmbda strainexact_kk δ_ij + 2 mu strainexact_ij'

  # define the linear and bilinear forms
  res = domain.integral('ubasis_ni,j stress_ij' @ ns, geometry=ns.x, degree=9)
  res -= domain.boundary['right'].integral('ubasis_ni stressexact_ij n_j' @ ns, geometry=ns.x, degree=9)

  # compute the constraints vector for the symmetry conditions
  sqr = domain.boundary['top,bottom'].integral('(u_i n_i)^2' @ ns, degree=9)
  cons = solver.optimize('lhs', sqr, droptol=1e-15)

  # solve the system of equations
  lhs = solver.solve_linear('lhs', res, constrain=cons)
  ns = ns(lhs=lhs)

  # post-processing
  if figures:
    geom, stressxx = domain.simplex.elem_eval([ns.x, 'stress_00' @ ns], ischeme='bezier8', separate=True)
    with plot.PyPlot( 'solution', index=nr ) as plt:
      plt.mesh( geom, stressxx )
      plt.colorbar()

  # compute the L2-norm of the error in the stress
  err = domain.integrate('(?dstress_ij ?dstress_ij)(dstress_ij = stress_ij - stressexact_ij)' @ ns, geometry=ns.x, ischeme='gauss9')**.5

  # compute the mesh parameter (maximum physical distance between knots)
  hmax = max(numpy.linalg.norm(v[:,numpy.newaxis]-v, axis=2).max() for v in domain.elem_eval(ns.x, ischeme='bezier2', separate=True))

  return err, hmax
示例#18
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,
    degree: 'polynomial degree' = 2,
    withplots: 'create plots' = True,
  ):

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

  # create namespace
  ns = function.Namespace()
  ns.uinf = 1, 0
  ns.density = density
  ns.viscosity = 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, x0 = mesh.rectilinear([range(melems+1),numpy.linspace(0,2*numpy.pi,2*nelems+1)], periodic=(1,))
  rho, phi = x0
  phi += 1e-3 # tiny nudge (0.057 deg) to break element symmetry
  radius = .5 * function.exp(rscale * rho)
  ns.x = radius * function.trigtangent(phi)
  domain = domain.withboundary(inner='left', inflow=domain.boundary['right'].select(-ns.uinf.dotnorm(ns.x), ischeme='gauss1'))

  # prepare bases (using piola transformation to maintain u/p compatibility)
  J = ns.x.grad(x0)
  detJ = function.determinant(J)
  ns.unbasis, ns.utbasis, ns.pbasis = function.chain([ # compatible spaces using piola transformation
    domain.basis('spline', degree=(degree+1,degree), removedofs=((0,),None))[:,_] * J[:,0] / detJ,
    domain.basis('spline', degree=(degree,degree+1))[:,_] * J[:,1] / detJ,
    domain.basis('spline', degree=degree) / detJ,
  ])
  ns.ubasis_ni = 'unbasis_ni + utbasis_ni'

  # populate namespace
  ns.u_i = 'ubasis_ni ?lhs_n'
  ns.p = 'pbasis_n ?lhs_n'
  ns.sigma_ij = 'viscosity (u_i,j + u_j,i) - p δ_ij'
  ns.hinner = 2 * numpy.pi / nelems
  ns.c = 5 * (degree+1) / ns.hinner
  ns.nietzsche_ni = 'viscosity (c ubasis_ni - (ubasis_ni,j + ubasis_nj,i) n_j)'
  ns.ucyl = -.5 * rotation * function.trignormal(phi)

  # create residual vector components
  res = domain.integral('ubasis_ni,j sigma_ij + pbasis_n u_k,k' @ ns, geometry=ns.x, degree=2*(degree+1))
  res += domain.boundary['inner'].integral('nietzsche_ni (u_i - ucyl_i)' @ ns, geometry=ns.x, degree=2*(degree+1))
  oseen = domain.integral('density ubasis_ni u_i,j uinf_j' @ ns, geometry=ns.x, degree=2*(degree+1))
  convec = domain.integral('density ubasis_ni u_i,j u_j' @ ns, geometry=ns.x, degree=3*(degree+1))
  inertia = domain.integral('density ubasis_ni u_i' @ ns, geometry=ns.x, degree=2*(degree+1))

  # constrain full velocity vector at inflow
  sqr = domain.boundary['inflow'].integral('(u_i - uinf_i) (u_i - uinf_i)' @ ns, geometry=ns.x, degree=9)
  cons = solver.optimize('lhs', sqr, droptol=1e-15)

  # solve unsteady navier-stokes equations, starting from stationary oseen flow
  lhs0 = solver.solve_linear('lhs', res+oseen, constrain=cons)
  makeplots = MakePlots(domain, ns, timestep=timestep, rotation=rotation) if withplots else lambda *args: None
  for istep, lhs in log.enumerate('timestep', solver.impliciteuler('lhs', residual=res+convec, inertia=inertia, lhs0=lhs0, timestep=timestep, constrain=cons, newtontol=1e-10)):
    makeplots(lhs)
    if istep * timestep >= tmax:
      break

  return lhs0, lhs
示例#19
0
def main(inflow: 'inflow velocity' = 10,
         viscosity: 'kinematic viscosity' = 1.0,
         density: 'density' = 1.0,
         theta=0.5,
         timestepsize=0.01):

    # mesh and geometry definition
    grid_x_1 = numpy.linspace(-3, -1, 7)
    grid_x_1 = grid_x_1[:-1]
    grid_x_2 = numpy.linspace(-1, -0.3, 8)
    grid_x_2 = grid_x_2[:-1]
    grid_x_3 = numpy.linspace(-0.3, 0.3, 13)
    grid_x_3 = grid_x_3[:-1]
    grid_x_4 = numpy.linspace(0.3, 1, 8)
    grid_x_4 = grid_x_4[:-1]
    grid_x_5 = numpy.linspace(1, 3, 7)
    grid_x = numpy.concatenate(
        (grid_x_1, grid_x_2, grid_x_3, grid_x_4, grid_x_5), axis=None)
    grid_y_1 = numpy.linspace(0, 1.5, 16)
    grid_y_1 = grid_y_1[:-1]
    grid_y_2 = numpy.linspace(1.5, 2, 4)
    grid_y_2 = grid_y_2[:-1]
    grid_y_3 = numpy.linspace(2, 4, 7)
    grid_y = numpy.concatenate((grid_y_1, grid_y_2, grid_y_3), axis=None)
    grid = [grid_x, grid_y]

    topo, geom = mesh.rectilinear(grid)
    domain = topo.withboundary(inflow='left', wall='top,bottom', outflow='right') - \
        topo[18:20, :10].withboundary(flap='left,right,top')

    # Nutils namespace
    ns = function.Namespace()

    # time approximations
    # TR interpolation
    ns._functions['t'] = lambda f: theta * f + (1 - theta) * subs0(f)
    ns._functions_nargs['t'] = 1
    # 1st order FD
    ns._functions['δt'] = lambda f: (f - subs0(f)) / dt
    ns._functions_nargs['δt'] = 1
    # 2nd order FD
    ns._functions['tt'] = lambda f: (1.5 * f - 2 * subs0(f) + 0.5 * subs00(f)
                                     ) / dt
    ns._functions_nargs['tt'] = 1
    # extrapolation for pressure
    ns._functions['tp'] = lambda f: (1.5 * f - 0.5 * subs0(f))
    ns._functions_nargs['tp'] = 1

    ns.nu = viscosity
    ns.rho = density
    ns.uin = inflow
    ns.x0 = geom  # reference geometry
    ns.dbasis = domain.basis('std', degree=1).vector(2)
    ns.d_i = 'dbasis_ni ?meshdofs_n'
    ns.umesh_i = 'dbasis_ni (1.5 ?meshdofs_n - 2 ?oldmeshdofs_n + 0.5 ?oldoldmeshdofs_n ) / ?dt'
    ns.x_i = 'x0_i + d_i'  # moving geometry
    ns.ubasis, ns.pbasis = function.chain([
        domain.basis('std', degree=2).vector(2),
        domain.basis('std', degree=1),
    ])
    ns.F_i = 'ubasis_ni ?F_n'  # stress field
    ns.urel_i = 'ubasis_ni ?lhs_n'  # relative velocity
    ns.u_i = 'umesh_i + urel_i'  # total velocity
    ns.p = 'pbasis_n ?lhs_n'  # pressure

    # initialization of dofs
    meshdofs = numpy.zeros(len(ns.dbasis))
    oldmeshdofs = meshdofs
    oldoldmeshdofs = meshdofs
    oldoldoldmeshdofs = meshdofs
    lhs0 = numpy.zeros(len(ns.ubasis))

    # for visualization
    bezier = domain.sample('bezier', 2)

    # preCICE setup
    configFileName = "../precice-config.xml"
    participantName = "Fluid"
    solverProcessIndex = 0
    solverProcessSize = 1
    interface = precice.Interface(participantName, configFileName,
                                  solverProcessIndex, solverProcessSize)

    # define coupling meshes
    meshName = "Fluid-Mesh"
    meshID = interface.get_mesh_id(meshName)

    couplinginterface = domain.boundary['flap']
    couplingsample = couplinginterface.sample(
        'gauss', degree=2)  # mesh located at Gauss points
    dataIndices = interface.set_mesh_vertices(meshID,
                                              couplingsample.eval(ns.x0))

    # coupling data
    writeData = "Force"
    readData = "Displacement"
    writedataID = interface.get_data_id(writeData, meshID)
    readdataID = interface.get_data_id(readData, meshID)

    # initialize preCICE
    precice_dt = interface.initialize()
    dt = min(precice_dt, timestepsize)

    # boundary conditions for fluid equations
    sqr = domain.boundary['wall,flap'].integral('urel_k urel_k d:x0' @ ns,
                                                degree=4)
    cons = solver.optimize('lhs', sqr, droptol=1e-15)
    sqr = domain.boundary['inflow'].integral(
        '((urel_0 - uin)^2 + urel_1^2) d:x0' @ ns, degree=4)
    cons = solver.optimize('lhs', sqr, droptol=1e-15, constrain=cons)

    # weak form fluid equations
    res = domain.integral('t(ubasis_ni,j (u_i,j + u_j,i) rho nu d:x)' @ ns,
                          degree=4)
    res += domain.integral('(-ubasis_ni,j p δ_ij + pbasis_n u_k,k) d:x' @ ns,
                           degree=4)
    res += domain.integral('rho ubasis_ni δt(u_i d:x)' @ ns, degree=4)
    res += domain.integral('rho ubasis_ni t(u_i,j urel_j d:x)' @ ns, degree=4)

    # weak form for force computation
    resF = domain.integral('(ubasis_ni,j (u_i,j + u_j,i) rho nu d:x)' @ ns,
                           degree=4)
    resF += domain.integral('tp(-ubasis_ni,j p δ_ij d:x)' @ ns, degree=4)
    resF += domain.integral('pbasis_n u_k,k d:x' @ ns, degree=4)
    resF += domain.integral('rho ubasis_ni tt(u_i d:x)' @ ns, degree=4)
    resF += domain.integral('rho ubasis_ni (u_i,j urel_j d:x)' @ ns, degree=4)
    resF += couplinginterface.sample('gauss',
                                     4).integral('ubasis_ni F_i d:x' @ ns)
    consF = numpy.isnan(
        solver.optimize('F',
                        couplinginterface.sample('gauss',
                                                 4).integral('F_i F_i' @ ns),
                        droptol=1e-10))

    # boundary conditions mesh displacements
    sqr = domain.boundary['inflow,outflow,wall'].integral('d_i d_i' @ ns,
                                                          degree=2)
    meshcons0 = solver.optimize('meshdofs', sqr, droptol=1e-15)

    # weak form mesh displacements
    meshsqr = domain.integral('d_i,x0_j d_i,x0_j d:x0' @ ns, degree=2)

    # better initial guess: start from Stokes solution, comment out for comparison with other solvers
    #res_stokes = domain.integral('(ubasis_ni,j ((u_i,j + u_j,i) rho nu - p δ_ij) + pbasis_n u_k,k) d:x' @ ns, degree=4)
    #lhs0 = solver.solve_linear('lhs', res_stokes, constrain=cons, arguments=dict(meshdofs=meshdofs, oldmeshdofs=oldmeshdofs, oldoldmeshdofs=oldoldmeshdofs, oldoldoldmeshdofs=oldoldoldmeshdofs, dt=dt))
    lhs00 = lhs0

    timestep = 0
    t = 0

    while interface.is_coupling_ongoing():

        # read displacements from interface
        if interface.is_read_data_available():
            readdata = interface.read_block_vector_data(
                readdataID, dataIndices)
            coupledata = couplingsample.asfunction(readdata)
            sqr = couplingsample.integral(((ns.d - coupledata)**2).sum(0))
            meshcons = solver.optimize('meshdofs',
                                       sqr,
                                       droptol=1e-15,
                                       constrain=meshcons0)
            meshdofs = solver.optimize('meshdofs', meshsqr, constrain=meshcons)

        # save checkpoint
        if interface.is_action_required(
                precice.action_write_iteration_checkpoint()):
            lhs_checkpoint = lhs0
            lhs00_checkpoint = lhs00
            t_checkpoint = t
            timestep_checkpoint = timestep
            oldmeshdofs_checkpoint = oldmeshdofs
            oldoldmeshdofs_checkpoint = oldoldmeshdofs
            oldoldoldmeshdofs_checkpoint = oldoldoldmeshdofs
            interface.mark_action_fulfilled(
                precice.action_write_iteration_checkpoint())

        # solve fluid equations
        lhs1 = solver.newton(
            'lhs',
            res,
            lhs0=lhs0,
            constrain=cons,
            arguments=dict(
                lhs0=lhs0,
                dt=dt,
                meshdofs=meshdofs,
                oldmeshdofs=oldmeshdofs,
                oldoldmeshdofs=oldoldmeshdofs,
                oldoldoldmeshdofs=oldoldoldmeshdofs)).solve(tol=1e-6)

        # write forces to interface
        if interface.is_write_data_required(dt):
            F = solver.solve_linear('F',
                                    resF,
                                    constrain=consF,
                                    arguments=dict(
                                        lhs00=lhs00,
                                        lhs0=lhs0,
                                        lhs=lhs1,
                                        dt=dt,
                                        meshdofs=meshdofs,
                                        oldmeshdofs=oldmeshdofs,
                                        oldoldmeshdofs=oldoldmeshdofs,
                                        oldoldoldmeshdofs=oldoldoldmeshdofs))
            # writedata = couplingsample.eval(ns.F, F=F) # for stresses
            writedata = couplingsample.eval('F_i d:x' @ ns, F=F, meshdofs=meshdofs) * \
                numpy.concatenate([p.weights for p in couplingsample.points])[:, numpy.newaxis]
            interface.write_block_vector_data(writedataID, dataIndices,
                                              writedata)

        # do the coupling
        precice_dt = interface.advance(dt)
        dt = min(precice_dt, timestepsize)

        # advance variables
        timestep += 1
        t += dt
        lhs00 = lhs0
        lhs0 = lhs1
        oldoldoldmeshdofs = oldoldmeshdofs
        oldoldmeshdofs = oldmeshdofs
        oldmeshdofs = meshdofs

        # read checkpoint if required
        if interface.is_action_required(
                precice.action_read_iteration_checkpoint()):
            lhs0 = lhs_checkpoint
            lhs00 = lhs00_checkpoint
            t = t_checkpoint
            timestep = timestep_checkpoint
            oldmeshdofs = oldmeshdofs_checkpoint
            oldoldmeshdofs = oldoldmeshdofs_checkpoint
            oldoldoldmeshdofs = oldoldoldmeshdofs_checkpoint
            interface.mark_action_fulfilled(
                precice.action_read_iteration_checkpoint())

        if interface.is_time_window_complete():
            x, u, p = bezier.eval(['x_i', 'u_i', 'p'] @ ns,
                                  lhs=lhs1,
                                  meshdofs=meshdofs,
                                  oldmeshdofs=oldmeshdofs,
                                  oldoldmeshdofs=oldoldmeshdofs,
                                  oldoldoldmeshdofs=oldoldoldmeshdofs,
                                  dt=dt)
            with treelog.add(treelog.DataLog()):
                export.vtk('Fluid_' + str(timestep), bezier.tri, x, u=u, p=p)

    interface.finalize()
示例#20
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))
def main(X: unit['m'], Y: unit['m'], l0: unit['m'], degree: int,
         du: unit['m']):
    '''
  Mechanical test case

  .. arguments::

     X [0.5mm]
       Domain size in x direction.

     Y [0.04mm]
       Domain size in y direction.

     l0 [0.015mm]
       Charateristic length scale.    

     degree [1]
       Polynomial degree of the approximation.

     du [0.01mm]
       Applied displacement.
  '''

    assert degree > 0

    # create the mesh
    topo, geom = mesh.rectilinear([
        numpy.linspace(0.001, 0.001 + X, 31),
        numpy.linspace(0.001, 0.001 + Y, 11)
    ])

    # prepare the integration and post processing samples
    ipoints = topo.sample('gauss', 2 * degree)
    bezier = topo.sample('bezier', 2 * degree)

    # initialize the namespace
    ns = function.Namespace()
    ns.x = geom
    ns.ubasis = topo.basis('th-spline', degree=degree).vector(topo.ndims)
    ns.dbasis = topo.basis('th-spline', degree=degree)
    ns.Hbasis = ipoints.basis()
    ns.u_i = 'ubasis_ni ?solu_n'
    ns.d = 'dbasis_n  ?sold_n'
    ns.H0 = 'Hbasis_n ?solH0_n'
    ns.l0 = l0
    ns.du = du

    # volume coupling fields
    ns.Gc = 'dbasis_n  ?gcdofs_n'
    ns.lmbda = 'dbasis_n  ?lmbdadofs_n'
    ns.mu = 'dbasis_n  ?mudofs_n'

    # formulation
    ns.strain_ij = '( u_i,j + u_j,i ) / 2'
    ns.stress_ij = 'lmbda strain_kk δ_ij + 2 mu strain_ij'
    ns.psi = 'stress_ij strain_ij / 2'
    ns.H = function.max(ns.psi, ns.H0)
    ns.gamma = '( d^2 + l0^2 d_,i d_,i ) / (2 l0)'

    # boundary condition for displacement field
    sqru = topo.boundary['top'].integral('( u_i n_i - du )^2 d:x' @ ns,
                                         degree=degree * 2)
    sqru += topo.boundary['bottom'].integral('( u_i n_i )^2 d:x' @ ns,
                                             degree=degree * 2)
    sqru += topo.boundary['bottom'].boundary['left'].integral(
        'u_i u_i d:x' @ ns, degree=degree * 2)
    consu = solver.optimize('solu', sqru, droptol=1e-12)

    # initialize the solution vectors
    solu = numpy.zeros(ns.ubasis.shape[0])
    sold = numpy.zeros(ns.dbasis.shape[0])
    solH0 = ipoints.eval(0.)

    # preCICE setup
    configFileName = "precice-config.xml"
    participantName = "BrittleFracture"
    solverProcessIndex = 0
    solverProcessSize = 1
    interface = precice.Interface(participantName, configFileName,
                                  solverProcessIndex, solverProcessSize)

    # define coupling mesh
    meshName = "BrittleFracture-Mesh"
    meshID = interface.get_mesh_id(meshName)
    couplingsample = topo.sample('gauss', degree=degree * 2)
    vertices = couplingsample.eval(ns.x)
    dataIndices = interface.set_mesh_vertices(meshID, vertices)

    lmbda = 121153.8e6  # First Lamé parameter in Pa
    mu = 80769.2e6  # Second Lamé parameter in Pa

    sqrl = couplingsample.integral((ns.lmbda - lmbda)**2)
    lmbdadofs = solver.optimize('lmbdadofs', sqrl, droptol=1e-12)

    sqrm = couplingsample.integral((ns.mu - mu)**2)
    mudofs = solver.optimize('mudofs', sqrm, droptol=1e-12)

    # coupling data
    gcID = interface.get_data_id("Gc", meshID)

    precice_dt = interface.initialize(
    )  # pseudo timestep size handled by preCICE

    nstep = 10000  # very high number of steps, end of simulation is steered by preCICE instead

    # time loop
    with treelog.iter.fraction('step', range(nstep)) as counter:
        for istep in counter:

            if not interface.is_coupling_ongoing():
                break

            if interface.is_read_data_available():
                gc = interface.read_block_scalar_data(gcID, dataIndices)
                gc_function = couplingsample.asfunction(gc)
                sqrg = couplingsample.integral((ns.Gc - gc_function)**2)
                gcdofs = solver.optimize('gcdofs', sqrg, droptol=1e-12)

            ############################
            # Phase field problem      #
            ############################

            resd = ipoints.integral(
                '( Gc / l0 ) ( d dbasis_n + l0^2 d_,i dbasis_n,i ) d:x' @ ns)
            resd += ipoints.integral('2 H ( d - 1 ) dbasis_n d:x' @ ns)

            sold = solver.solve_linear('sold',
                                       resd,
                                       arguments={
                                           'solu': solu,
                                           'solH0': solH0,
                                           'lmbdadofs': lmbdadofs,
                                           'mudofs': mudofs,
                                           'gcdofs': gcdofs
                                       })

            ############################
            # Elasticity problem       #
            ############################

            resu = topo.integral('( 1 - d )^2 ubasis_ni,j stress_ij d:x' @ ns,
                                 degree=2 * degree)
            solu = solver.solve_linear('solu',
                                       resu,
                                       arguments={
                                           'sold': sold,
                                           'lmbdadofs': lmbdadofs,
                                           'mudofs': mudofs
                                       },
                                       constrain=consu)

            # Update zero state and history field
            solH0 = ipoints.eval(ns.H,
                                 arguments={
                                     'solu': solu,
                                     'solH0': solH0,
                                     'lmbdadofs': lmbdadofs,
                                     'mudofs': mudofs
                                 })

            # do the coupling
            precice_dt = interface.advance(precice_dt)

            ############################
            # Output                   #
            ############################

            # element-averaged history field
            transforms = ipoints.transforms[0]
            indicator = function.kronecker(
                1.,
                axis=0,
                length=len(transforms),
                pos=function.TransformsIndexWithTail(transforms,
                                                     function.TRANS).index)
            areas, integrals = ipoints.integrate(
                [indicator, indicator * ns.H],
                arguments={
                    'solu': solu,
                    'solH0': solH0,
                    'lmbdadofs': lmbdadofs,
                    'mudofs': mudofs,
                    'gcdofs': gcdofs
                })
            H = indicator.dot(integrals / areas)

            # evaluate fields
            points, dvals, uvals, lvals, mvals, gcvals = bezier.eval(
                ['x_i', 'd', 'u_i', 'lmbda', 'mu', 'Gc'] @ ns,
                arguments={
                    'solu': solu,
                    'sold': sold,
                    'solH0': solH0,
                    'lmbdadofs': lmbdadofs,
                    'mudofs': mudofs,
                    'gcdofs': gcdofs
                })
            Hvals = bezier.eval(H, arguments={'solu': solu, 'solH0': solH0})

            with treelog.add(treelog.DataLog()):
                export.vtk('Solid_' + str(istep),
                           bezier.tri,
                           points,
                           Gc=gcvals,
                           D=dvals,
                           U=uvals,
                           H=Hvals)

    interface.finalize()
示例#22
0
def main(nelems: int, etype: str, btype: str, degree: int):
    '''
  Laplace problem on a unit square.

  .. arguments::

     nelems [10]
       Number of elements along edge.
     etype [square]
       Type of elements (square/triangle/mixed).
     btype [std]
       Type of basis function (std/spline), availability depending on the
       selected element type.
     degree [1]
       Polynomial degree.
  '''

    # A unit square domain is created by calling the
    # :func:`nutils.mesh.unitsquare` mesh generator, with the number of elements
    # along an edge as the first argument, and the type of elements ("square",
    # "triangle", or "mixed") as the second. The result is a topology object
    # ``domain`` and a vectored valued geometry function ``geom``.

    domain, geom = mesh.unitsquare(nelems, etype)

    # To be able to write index based tensor contractions, we need to bundle all
    # relevant functions together in a namespace. Here we add the geometry ``x``,
    # a scalar ``basis``, and the solution ``u``. The latter is formed by
    # contracting the basis with a to-be-determined solution vector ``?lhs``.

    ns = function.Namespace()
    ns.x = geom
    ns.basis = domain.basis(btype, degree=degree)
    ns.u = 'basis_n ?lhs_n'

    # We are now ready to implement the Laplace equation. In weak form, the
    # solution is a scalar field :math:`u` for which:
    #
    # .. math:: ∀ v: ∫_Ω \frac{dv}{dx_i} \frac{du}{dx_i} - ∫_{Γ_n} v f = 0.
    #
    # By linearity the test function :math:`v` can be replaced by the basis that
    # spans its space. The result is an integral ``res`` that evaluates to a
    # vector matching the size of the function space.

    res = domain.integral('d(basis_n, x_i) d(u, x_i) J(x)' @ ns,
                          degree=degree * 2)
    res -= domain.boundary['right'].integral(
        'basis_n cos(1) cosh(x_1) J(x)' @ ns, degree=degree * 2)

    # The Dirichlet constraints are set by finding the coefficients that minimize
    # the error:
    #
    # .. math:: \min_u ∫_{\Gamma_d} (u - u_d)^2
    #
    # The resulting ``cons`` array holds numerical values for all the entries of
    # ``?lhs`` that contribute (up to ``droptol``) to the minimization problem.
    # All remaining entries are set to ``NaN``, signifying that these degrees of
    # freedom are unconstrained.

    sqr = domain.boundary['left'].integral('u^2 J(x)' @ ns, degree=degree * 2)
    sqr += domain.boundary['top'].integral(
        '(u - cosh(1) sin(x_0))^2 J(x)' @ ns, degree=degree * 2)
    cons = solver.optimize('lhs', sqr, droptol=1e-15)

    # The unconstrained entries of ``?lhs`` are to be determined such that the
    # residual vector evaluates to zero in the corresponding entries. This step
    # involves a linearization of ``res``, resulting in a jacobian matrix and
    # right hand side vector that are subsequently assembled and solved. The
    # resulting ``lhs`` array matches ``cons`` in the constrained entries.

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

    # Once all entries of ``?lhs`` are establised, the corresponding solution can
    # be vizualised by sampling values of ``ns.u`` along with physical
    # coordinates ``ns.x``, with the solution vector provided via the
    # ``arguments`` dictionary. The sample members ``tri`` and ``hull`` provide
    # additional inter-point information required for drawing the mesh and
    # element outlines.

    bezier = domain.sample('bezier', 9)
    x, u = bezier.eval(['x', 'u'] @ ns, lhs=lhs)
    export.triplot('solution.png', x, u, tri=bezier.tri, hull=bezier.hull)

    # To confirm that our computation is correct, we use our knowledge of the
    # analytical solution to evaluate the L2-error of the discrete result.

    err = domain.integral('(u - sin(x_0) cosh(x_1))^2 J(x)' @ ns,
                          degree=degree * 2).eval(lhs=lhs)**.5
    treelog.user('L2 error: {:.2e}'.format(err))

    return cons, lhs, err
示例#23
0
def main(
    uinf      = 2.0,
    L         = 2.0,
    R         = 0.5,
    nelems    = 7  ,
    degree    = 2  ,
    maxrefine = 3  ,
    withplots = True
    ):
  
  """`main` functions with different parameters.
  
  Parameters
  ----------
  uinf : float 
      free stream velocity
  L : float
      domain size
  R : float
      cylinder radius
  nelems : int
      number of elements
  degree : int
      b-spline degree
  maxrefine : int
      bisectioning steps
  withplots : bool
      create plots
  Returns
  -------
  lhs : float
      solution φ
  err : float
      L2 norm, H1 norm and energy errors
  """
  # construct mesh
  verts = numpy.linspace(-L/2, L/2, nelems+1)
  domain, geom = mesh.rectilinear([verts, verts])
  # trim out a circle
  domain = domain.trim(function.norm2(geom)-R, maxrefine=maxrefine)
  # initialize namespace
  ns = function.Namespace()
  ns.R    = R
  ns.x    = geom
  ns.uinf = uinf
  # construct function space and lagrange multiplier
  ns.phibasis, ns.lbasis = function.chain([domain.basis('spline', degree=degree),[1.]])
  ns.phi = ' phibasis_n ?lhs_n'
  ns.u   = 'sqrt( (phibasis_n,i ?lhs_n) (phibasis_m,i ?lhs_m) )'
  ns.l   = 'lbasis_n ?lhs_n'
  # set the exact solution
  ns.phiexact = 'uinf x_1 ( 1 - R^2 / (x_0^2 + x_1^2) )' # average is zero
  ns.phierror = 'phi - phiexact'
  # construct residual
  res  = domain.integral('-phibasis_n,i phi_,i' @ ns, geometry=ns.x, degree=degree*2)
  res += domain.boundary.integral('phibasis_n phiexact_,i n_i' @ ns, geometry=ns.x, degree=degree*2)
  res += domain.integral('lbasis_n phi + l phibasis_n' @ ns, geometry=ns.x, degree=degree*2)
  # find lhs such that res == 0 and substitute this lhs in the namespace
  lhs = solver.solve_linear('lhs', res)
  ns = ns(lhs=lhs)
  # evaluate error
  err1 = numpy.sqrt(domain.integrate(['phierror phierror' @ns,'phierror phierror + phierror_,i phierror_,i' @ns, '0.5 phi_,i phi_,i' @ns], geometry=ns.x, degree=degree*4))
  err2 = abs(err1[2] - 2.7710377946088443)
  err = numpy.array([err1[0],err1[1],err2])
  log.info('errors: L2={:.2e}, H1={:.2e}, eh={:.2e}'.format(*err))
  if withplots:
    makeplots(domain, ns)
  return lhs, err
示例#24
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,
    degree: 'polynomial degree' = 2,
    figures: 'create figures' = True,
  ):

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

  # create namespace
  ns = function.Namespace()
  ns.uinf = 1, 0
  ns.density = density
  ns.viscosity = 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, x0 = mesh.rectilinear([range(melems+1),numpy.linspace(0,2*numpy.pi,2*nelems+1)], periodic=(1,))
  rho, phi = x0
  phi += 1e-3 # tiny nudge (0.057 deg) to break element symmetry
  radius = .5 * function.exp(rscale * rho)
  ns.x = radius * function.trigtangent(phi)
  domain = domain.withboundary(inner='left', inflow=domain.boundary['right'].select(-ns.uinf.dotnorm(ns.x), ischeme='gauss1'))

  # prepare bases (using piola transformation to maintain u/p compatibility)
  J = ns.x.grad(x0)
  detJ = function.determinant(J)
  ns.unbasis, ns.utbasis, ns.pbasis = function.chain([ # compatible spaces using piola transformation
    domain.basis('spline', degree=(degree+1,degree), removedofs=((0,),None))[:,_] * J[:,0] / detJ,
    domain.basis('spline', degree=(degree,degree+1))[:,_] * J[:,1] / detJ,
    domain.basis('spline', degree=degree) / detJ,
  ])
  ns.ubasis_ni = 'unbasis_ni + utbasis_ni'

  # populate namespace
  ns.u_i = 'ubasis_ni ?lhs_n'
  ns.p = 'pbasis_n ?lhs_n'
  ns.sigma_ij = 'viscosity (u_i,j + u_j,i) - p δ_ij'
  ns.hinner = 2 * numpy.pi / nelems
  ns.c = 5 * (degree+1) / ns.hinner
  ns.nietzsche_ni = 'viscosity (c ubasis_ni - (ubasis_ni,j + ubasis_nj,i) n_j)'
  ns.ucyl = -.5 * rotation * function.trignormal(phi)

  # create residual vector components
  res = domain.integral('ubasis_ni,j sigma_ij + pbasis_n u_k,k' @ ns, geometry=ns.x, degree=2*(degree+1))
  res += domain.boundary['inner'].integral('nietzsche_ni (u_i - ucyl_i)' @ ns, geometry=ns.x, degree=2*(degree+1))
  oseen = domain.integral('density ubasis_ni u_i,j uinf_j' @ ns, geometry=ns.x, degree=2*(degree+1))
  convec = domain.integral('density ubasis_ni u_i,j u_j' @ ns, geometry=ns.x, degree=3*(degree+1))
  inertia = domain.integral('density ubasis_ni u_i' @ ns, geometry=ns.x, degree=2*(degree+1))

  # constrain full velocity vector at inflow
  sqr = domain.boundary['inflow'].integral('(u_i - uinf_i) (u_i - uinf_i)' @ ns, geometry=ns.x, degree=9)
  cons = solver.optimize('lhs', sqr, droptol=1e-15)

  # solve unsteady navier-stokes equations, starting from stationary oseen flow
  lhs0 = solver.solve_linear('lhs', res+oseen, constrain=cons)
  makeplots = MakePlots(domain, ns, timestep=timestep, rotation=rotation) if figures else lambda *args: None
  for istep, lhs in log.enumerate('timestep', solver.impliciteuler('lhs', residual=res+convec, inertia=inertia, lhs0=lhs0, timestep=timestep, constrain=cons, newtontol=1e-10)):
    makeplots(lhs)
    if istep * timestep >= tmax:
      break

  return lhs0, lhs
示例#25
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,
):

    ns = function.Namespace()
    ns.lmbda = E * nu / (1 - nu**2)
    ns.mu = .5 * E / (1 + nu)

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

    # create the second-order B-spline basis over the coarsest domain
    ns.bsplinebasis = domain0.basis('spline', degree=2)
    ns.controlweights = 1, .5 + .5 / 2**.5, .5 + .5 / 2**.5, 1, 1, 1, 1, 1, 1, 1, 1, 1
    ns.weightfunc = 'bsplinebasis_n controlweights_n'
    ns.nurbsbasis = ns.bsplinebasis * ns.controlweights / ns.weightfunc

    # create the isogeometric map
    ns.controlpoints = [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]
    ns.x_i = 'nurbsbasis_n controlpoints_ni'

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

    # create the second-order B-spline basis over the refined domain
    ns.bsplinebasis = domain.basis('spline', degree=2)
    sqr = domain.integral('(bsplinebasis_n ?lhs_n - weightfunc)^2' @ ns,
                          geometry=ns.x,
                          degree=9)
    ns.controlweights = solver.optimize('lhs', sqr)
    ns.nurbsbasis = ns.bsplinebasis * ns.controlweights / ns.weightfunc

    # prepare the displacement field
    ns.ubasis = ns.nurbsbasis.vector(2)
    ns.u_i = 'ubasis_ni ?lhs_n'
    ns.strain_ij = '(u_i,j + u_j,i) / 2'
    ns.stress_ij = 'lmbda strain_kk δ_ij + 2 mu strain_ij'

    # construct the exact solution
    ns.r2 = 'x_k x_k'
    ns.R2 = R**2
    ns.T = T
    ns.k = (3 - nu) / (1 + nu)  # plane stress parameter
    ns.uexact_i = '''(T / 4 mu) <x_0 ((k + 1) / 2 + (1 + k) R2 / r2 + (1 - R2 / r2) (x_0^2 - 3 x_1^2) R2 / r2^2),
                               x_1 ((k - 3) / 2 + (1 - k) R2 / r2 + (1 - R2 / r2) (3 x_0^2 - x_1^2) R2 / r2^2)>_i'''
    ns.strainexact_ij = '(uexact_i,j + uexact_j,i) / 2'
    ns.stressexact_ij = 'lmbda strainexact_kk δ_ij + 2 mu strainexact_ij'

    # define the linear and bilinear forms
    res = domain.integral('ubasis_ni,j stress_ij' @ ns,
                          geometry=ns.x,
                          degree=9)
    res -= domain.boundary['right'].integral(
        'ubasis_ni stressexact_ij n_j' @ ns, geometry=ns.x, degree=9)

    # compute the constraints vector for the symmetry conditions
    sqr = domain.boundary['top,bottom'].integral('(u_i n_i)^2' @ ns, degree=9)
    cons = solver.optimize('lhs', sqr, droptol=1e-15)

    # solve the system of equations
    lhs = solver.solve_linear('lhs', res, constrain=cons)
    ns |= dict(lhs=lhs)

    # post-processing
    if withplots:
        geom, stressxx = domain.simplex.elem_eval([ns.x, 'stress_00' @ ns],
                                                  ischeme='bezier8',
                                                  separate=True)
        with plot.PyPlot('solution', index=nr) as plt:
            plt.mesh(geom, stressxx)
            plt.colorbar()

    # compute the L2-norm of the error in the stress
    err = domain.integrate(
        '?dstress_ij ?dstress_ij | ?dstress_ij = stress_ij - stressexact_ij'
        @ ns,
        geometry=ns.x,
        ischeme='gauss9')**.5

    # compute the mesh parameter (maximum physical distance between knots)
    hmax = max(
        numpy.linalg.norm(v[:, numpy.newaxis] - v, axis=2).max()
        for v in domain.elem_eval(ns.x, ischeme='bezier2', separate=True))

    return err, hmax
示例#26
0
 def test_direct(self):
   with self.assertRaises(solver.ModelError):
     self.assert_resnorm(solver.solve_linear('dofs', residual=self.residual, constrain=self.cons))
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
示例#28
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,
    figures: 'create figures' = True,
):

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

    # create namespace
    ns = function.Namespace()
    ns.viscosity = viscosity
    ns.density = density

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

    # construct bases
    ns.uxbasis, ns.uybasis, ns.pbasis, ns.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
    ])
    ns.ubasis_ni = '<uxbasis_n, uybasis_n>_i'

    # construct geometry
    if not warp:
        ns.x = ns.x0
    else:
        xi, eta = ns.x0
        ns.x = (eta + 2) * function.rotmat(xi * .4)[:, 1] - (
            0, 2)  # slight downward bend
        ns.J_ij = 'x_i,x0_j'
        ns.detJ = function.determinant(ns.J)
        ns.ubasis_ni = 'ubasis_nj J_ij / detJ'  # piola transform
        ns.pbasis_n = 'pbasis_n / detJ'

    # populate namespace
    ns.u_i = 'ubasis_ni ?lhs_n'
    ns.p = 'pbasis_n ?lhs_n'
    ns.l = 'lbasis_n ?lhs_n'
    ns.sigma_ij = 'viscosity (u_i,j + u_j,i) - p δ_ij'
    ns.c = 5 * (degree + 1) / domain.boundary.elem_eval(
        1, geometry=ns.x, ischeme='gauss2', asfunction=True)
    ns.nietzsche_ni = 'viscosity (c ubasis_ni - (ubasis_ni,j + ubasis_nj,i) n_j)'
    ns.top = domain.boundary.indicator('top')
    ns.utop_i = 'top <n_1, -n_0>_i'

    # solve stokes flow
    res = domain.integral(
        'ubasis_ni,j sigma_ij + pbasis_n (u_k,k + l) + lbasis_n p' @ ns,
        geometry=ns.x,
        degree=2 * (degree + 1))
    res += domain.boundary.integral('nietzsche_ni (u_i - utop_i)' @ ns,
                                    geometry=ns.x,
                                    degree=2 * (degree + 1))
    lhs0 = solver.solve_linear('lhs', res)
    if figures:
        postprocess(domain, ns(lhs=lhs0))

    # solve navier-stokes flow
    res += domain.integral('density ubasis_ni u_i,j u_j' @ ns,
                           geometry=ns.x,
                           degree=3 * (degree + 1))
    lhs1 = solver.newton('lhs', res, lhs0=lhs0).solve(tol=1e-10)
    if figures:
        postprocess(domain, ns(lhs=lhs1))

    return lhs0, lhs1
示例#29
0
def main(etype: str, btype: str, degree: int, nrefine: int):
    '''
  Adaptively refined Laplace problem on an L-shaped domain.

  .. arguments::

     etype [square]
       Type of elements (square/triangle/mixed).
     btype [h-std]
       Type of basis function (h/th-std/spline), with availability depending on
       the configured element type.
     degree [2]
       Polynomial degree
     nrefine [5]
       Number of refinement steps to perform.
  '''

    domain, geom = mesh.unitsquare(2, etype)

    x, y = geom - .5
    exact = (x**2 + y**2)**(1 / 3) * function.cos(
        function.arctan2(y + x, y - x) * (2 / 3))
    domain = domain.trim(exact - 1e-15, maxrefine=0)
    linreg = util.linear_regressor()

    with treelog.iter.fraction('level', range(nrefine + 1)) as lrange:
        for irefine in lrange:

            if irefine:
                refdom = domain.refined
                ns.refbasis = refdom.basis(btype, degree=degree)
                indicator = refdom.integral(
                    'd(refbasis_n, x_k) d(u, x_k) J(x)' @ ns,
                    degree=degree * 2).eval(lhs=lhs)
                indicator -= refdom.boundary.integral(
                    'refbasis_n d(u, x_k) n(x_k) J(x)' @ ns,
                    degree=degree * 2).eval(lhs=lhs)
                supp = ns.refbasis.get_support(
                    indicator**2 > numpy.mean(indicator**2))
                domain = domain.refined_by(refdom.transforms[supp])

            ns = function.Namespace()
            ns.x = geom
            ns.basis = domain.basis(btype, degree=degree)
            ns.u = 'basis_n ?lhs_n'
            ns.du = ns.u - exact

            sqr = domain.boundary['trimmed'].integral('u^2 J(x)' @ ns,
                                                      degree=degree * 2)
            cons = solver.optimize('lhs', sqr, droptol=1e-15)

            sqr = domain.boundary.integral('du^2 J(x)' @ ns, degree=7)
            cons = solver.optimize('lhs', sqr, droptol=1e-15, constrain=cons)

            res = domain.integral('d(basis_n, x_k) d(u, x_k) J(x)' @ ns,
                                  degree=degree * 2)
            lhs = solver.solve_linear('lhs', res, constrain=cons)

            ndofs = len(ns.basis)
            error = domain.integral('<du^2, sum:k(d(du, x_k)^2)>_i J(x)' @ ns,
                                    degree=7).eval(lhs=lhs)**.5
            rate, offset = linreg.add(numpy.log(len(ns.basis)),
                                      numpy.log(error))
            treelog.user(
                'ndofs: {ndofs}, L2 error: {error[0]:.2e} ({rate[0]:.2f}), H1 error: {error[1]:.2e} ({rate[1]:.2f})'
                .format(ndofs=len(ns.basis), error=error, rate=rate))

            bezier = domain.sample('bezier', 9)
            x, u, du = bezier.eval(['x', 'u', 'du'] @ ns, lhs=lhs)
            export.triplot('sol.png', x, u, tri=bezier.tri, hull=bezier.hull)
            export.triplot('err.png', x, du, tri=bezier.tri, hull=bezier.hull)

    return ndofs, error, lhs
示例#30
0
def main(nelems: int, etype: str, btype: str, degree: int, traction: float,
         maxrefine: int, radius: float, poisson: float):
    '''
  Horizontally loaded linear elastic plate with FCM hole.

  .. arguments::

     nelems [9]
       Number of elements along edge.
     etype [square]
       Type of elements (square/triangle/mixed).
     btype [std]
       Type of basis function (std/spline), with availability depending on the
       selected element type.
     degree [2]
       Polynomial degree.
     traction [.1]
       Far field traction (relative to Young's modulus).
     maxrefine [2]
       Number or refinement levels used for the finite cell method.
     radius [.5]
       Cut-out radius.
     poisson [.3]
       Poisson's ratio, nonnegative and strictly smaller than 1/2.
  '''

    domain0, geom = mesh.unitsquare(nelems, etype)
    domain = domain0.trim(function.norm2(geom) - radius, maxrefine=maxrefine)

    ns = function.Namespace()
    ns.x = geom
    ns.lmbda = 2 * poisson
    ns.mu = 1 - poisson
    ns.ubasis = domain.basis(btype, degree=degree).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['left,bottom'].integral('(u_i n_i)^2 J(x)' @ ns,
                                                  degree=degree * 2)
    cons = solver.optimize('lhs', sqr, droptol=1e-15)
    sqr = domain.boundary['top,right'].integral('du_k du_k J(x)' @ ns,
                                                degree=20)
    cons = solver.optimize('lhs', sqr, droptol=1e-15, constrain=cons)

    res = domain.integral('d(ubasis_ni, x_j) stress_ij J(x)' @ ns,
                          degree=degree * 2)
    lhs = solver.solve_linear('lhs', res, constrain=cons)

    bezier = domain.sample('bezier', 5)
    X, stressxx = bezier.eval(['X', 'stress_00'] @ ns, lhs=lhs)
    export.triplot('stressxx.png',
                   X,
                   stressxx,
                   tri=bezier.tri,
                   hull=bezier.hull)

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

    return err, cons, lhs
示例#31
0
def neutrondiffusion(mat_flag='scatterer',
                     BC_flag='vacuum',
                     bigsquare=1,
                     smallsquare=.1,
                     degree=1,
                     basis='lagrange'):

    W = bigsquare  #width of outer box
    Wi = smallsquare  #width of inner box

    nelems = int((2 * 1 * W / Wi))

    if mat_flag == 'scatterer':
        sigt = 2
        sigs = 1.99
    elif mat_flag == 'reflector':
        sigt = 2
        sigs = 1.8
    elif mat_flag == 'absorber':
        sigt = 10
        sigs = 2
    elif mat_flag == 'air':
        sigt = .01
        sigs = .006

    topo, geom = mesh.unitsquare(nelems,
                                 'square')  #unit square centred at (0.5, 0.5)
    ns = function.Namespace()
    ns.basis = topo.basis(basis, degree=degree)

    ns.x = W * geom  #scales the unit square to our physical square
    ns.f = function.max(
        function.abs(ns.x[0] - W / 2),
        function.abs(ns.x[1] - W / 2))  #level set function for inner square

    inner, outer = function.partition(
        ns.f, Wi / 2)  #indicator function for inner square and outer square

    ns.phi = 'basis_A ?dofs_A'
    ns.SIGs = sigs * outer  #scattering cross-section
    ns.SIGt = 0.1 * inner + sigt * outer  #total cross-section
    ns.SIGa = 'SIGt - SIGs'  #absorption cross-section
    ns.D = '1 / (3 SIGt)'  #diffusion co-efficient
    ns.Q = inner  #source term

    if BC_flag == 'vacuum':
        sqr = topo.boundary.integral('(phi - 0)^2 J(x)' @ ns,
                                     degree=degree * 2)
        cons = solver.optimize(
            'dofs', sqr,
            droptol=1e-14)  #this applies the boundary condition to u

        #residual
        res = topo.integral(
            '(D basis_i,j phi_,j + SIGa basis_i phi - basis_i Q) J(x)' @ ns,
            degree=degree * 2)

        #solve for degrees of freedom
        dofs = solver.solve_linear('dofs', res, constrain=cons)

    elif BC_flag == 'reflecting':
        #residual
        res = topo.integral(
            '(D basis_i,j phi_,j + SIGa basis_i phi - basis_i Q) J(x)' @ ns,
            degree=degree * 2)

        #solve for degrees of freedom
        dofs = solver.solve_linear('dofs', res)

    #select lower triangular half of square domain. Diagonal is one of its boundaries
    triang = topo.trim('x_0 - x_1' @ ns, maxrefine=5)
    triangbnd = triang.boundary  #select boundary of lower triangle
    # eval the vertices of the boundary elements of lower triangle:
    verts = triangbnd.sample(*element.parse_legacy_ischeme("vertex")).eval(
        'x_i' @ ns)
    # now select the verts of the boundary
    diag = topology.SubsetTopology(triangbnd, [
        triangbnd.references[i] if
        (verts[2 * i][0] == verts[2 * i][1] and verts[2 * i + 1][0]
         == verts[2 * i + 1][1]) else triangbnd.references[i].empty
        for i in range(len(triangbnd.references))
    ])
    bezier_diag = diag.sample('bezier', degree + 1)
    x_diag = bezier_diag.eval('(x_0^2 + x_1^2)^(1 / 2)' @ ns)
    phi_diag = bezier_diag.eval('phi' @ ns, dofs=dofs)

    bezier_bottom = topo.boundary['bottom'].sample('bezier', degree + 1)
    x_bottom = bezier_bottom.eval('x_0' @ ns)
    phi_bottom = bezier_bottom.eval('phi' @ ns, dofs=dofs)

    fig_bottom = plt.figure(0)
    ax_bottom = fig_bottom.add_subplot(111)
    plt.plot(x_bottom, phi_bottom)
    ax_bottom.set_title('Scalar flux along bottom for %s with %s BCs' %
                        (mat_flag, BC_flag))
    ax_bottom.set_xlabel('x')
    ax_bottom.set_ylabel('$\\phi(x)$')

    fig_diag = plt.figure(1)
    ax_diag = fig_diag.add_subplot(111)
    plt.plot(x_diag, phi_diag)
    ax_diag.set_title('Scalar flux along diagonal for %s with %s BCs' %
                      (mat_flag, BC_flag))
    ax_diag.set_xlabel('$\\sqrt{x^2 + y^2}$')
    ax_diag.set_ylabel('$\\phi(x = y)$')

    return fig_bottom, fig_diag