Example #1
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
Example #2
0
def main(
    nelems: 'number of elements' = 12,
    viscosity: 'fluid viscosity' = 1e-3,
    density: 'fluid density' = 1,
    degree: 'polynomial degree' = 2,
    warp: 'warp domain (downward bend)' = False,
    tol: 'solver tolerance' = 1e-5,
    maxiter: 'maximum number if iterations, 0 for unlimited' = 0,
    withplots: 'create plots' = True,
  ):

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

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

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

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

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

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

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

  return rhs, lhs