Example #1
0
 def test_newton_relax0(self):
     self.assert_resnorm(
         solver.newton('dofs',
                       residual=self.residual,
                       lhs0=self.lhs0,
                       constrain=self.cons,
                       relax0=.1).solve(tol=self.tol, maxiter=5))
Example #2
0
 def test_newton_relax0(self):
     self.assert_resnorm(
         solver.newton(self.dofs,
                       residual=self.residual,
                       arguments=self.arguments,
                       constrain=self.cons,
                       relax0=.1).solve(tol=self.tol, maxiter=5))
Example #3
0
 def test_newton_medianbased(self):
     self.assert_resnorm(
         solver.newton('dofs',
                       residual=self.residual,
                       lhs0=self.lhs0,
                       constrain=self.cons,
                       linesearch=solver.MedianBased()).solve(tol=self.tol,
                                                              maxiter=2))
Example #4
0
 def test_newton_medianbased(self):
     self.assert_resnorm(
         solver.newton(self.dofs,
                       residual=self.residual,
                       arguments=self.arguments,
                       constrain=self.cons,
                       linesearch=solver.MedianBased()).solve(tol=self.tol,
                                                              maxiter=2))
Example #5
0
 def test_newton_iter(self):
     _test_recursion_cache(
         self, lambda:
         ((types.frozenarray(lhs), resnorm)
          for lhs, resnorm in solver.newton('dofs',
                                            residual=self.residual,
                                            lhs0=self.lhs0,
                                            constrain=self.cons)))
Example #6
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
Example #7
0
def solve_nutils(g, method='Elliptic', ltol=1e-5, **solveargs):
    assert len(g) == 2

    res = method_library(g, method=method)

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

    g.x = lhs
Example #8
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)
Example #9
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)
Example #10
0
 def test_newton_tolnotreached(self):
     with self.assertLogs('nutils', logging.WARNING) as cm:
         self.assert_resnorm(
             solver.newton('dofs',
                           residual=self.residual,
                           lhs0=self.lhs0,
                           constrain=self.cons,
                           linrtol=1e-99).solve(tol=self.tol, maxiter=2))
     for msg in cm.output:
         self.assertIn('solver failed to reach tolerance', msg)
Example #11
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
Example #12
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
Example #13
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
Example #14
0
 def test_newton_boolcons(self):
     self.assert_resnorm(
         solver.newton('dofs',
                       residual=self.residual,
                       constrain=self.boolcons).solve(tol=self.tol,
                                                      maxiter=7))
Example #15
0
def finitestrain_patch(bottom, right, top, left):
    from nutils import version
    if int(version[0]) != 4:
        raise ImportError(
            'Mismatching nutils version detected, only version 4 supported. Upgrade by \"pip install --upgrade nutils\"'
        )

    from nutils import mesh, function
    from nutils import _, log, solver

    # error test input
    if not (left.dimension == right.dimension == top.dimension ==
            bottom.dimension == 2):
        raise RuntimeError(
            'finitestrain_patch only supported for planar (2D) geometries')
    if left.rational or right.rational or top.rational or bottom.rational:
        raise RuntimeError(
            'finitestrain_patch not supported for rational splines')

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

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

    # create an initial mesh (correct corners) which we will morph into the right one
    p1 = bottom.order(0)
    p2 = left.order(0)
    p = max(p1, p2)
    linear = BSplineBasis(2)
    srf = Surface(linear, linear, [bottom[0], bottom[-1], top[0], top[-1]])
    srf.raise_order(p1 - 2, p2 - 2)
    for k in bottom.knots(0, True)[p1:-p1]:
        srf.insert_knot(k, 0)
    for k in left.knots(0, True)[p2:-p2]:
        srf.insert_knot(k, 1)

    # create computational mesh
    n1 = len(bottom)
    n2 = len(left)
    dim = left.dimension
    domain, geom = mesh.rectilinear(srf.knots())
    ns = function.Namespace()
    ns.basis = domain.basis('spline',
                            degree(srf),
                            knotmultiplicities=multiplicities(srf)).vector(2)
    ns.phi = domain.basis('spline',
                          degree(srf),
                          knotmultiplicities=multiplicities(srf))
    ns.eye = np.array([[1, 0], [0, 1]])
    ns.cp = controlpoints(srf)
    ns.x_i = 'cp_ni phi_n'
    ns.lmbda = 1
    ns.mu = 1

    # add total boundary conditions
    # for hard problems these will be taken in steps and multiplied by dt every
    # time (quasi-static iterations)
    constraints = np.array([[[np.nan] * n2] * n1] * dim)
    for d in range(dim):
        constraints[d, 0, :] = (left[:, d] - srf[0, :, d])
        constraints[d, -1, :] = (right[:, d] - srf[-1, :, d])
        constraints[d, :, 0] = (bottom[:, d] - srf[:, 0, d])
        constraints[d, :, -1] = (top[:, d] - srf[:, -1, d])
    # TODO: Take a close look at the logic below

    # in order to iterate, we let t0=0 be current configuration and t1=1 our target configuration
    # if solver divergeces (too large deformation), we will try with dt=0.5. If this still
    # fails we will resort to dt=0.25 until a suitable small iterations size have been found

    # dt = 1
    # t0 = 0
    # t1 = 1
    # while t0 < 1:
    # dt = t1-t0
    n = 10
    dt = 1 / n
    for i in range(n):
        # print(' ==== Quasi-static '+str(t0*100)+'-'+str(t1*100)+' % ====')
        print(' ==== Quasi-static ' + str(i / (n - 1) * 100) + ' % ====')

        # define the non-linear finite strain problem formulation
        ns.cp = np.reshape(srf[:, :, :].swapaxes(0, 1), (n1 * n2, dim),
                           order='F')
        ns.x_i = 'cp_ni phi_n'  # geometric mapping (reference geometry)
        ns.u_i = 'basis_ki ?w_k'  # displacement (unknown coefficients w_k)
        ns.X_i = 'x_i + u_i'  # displaced geometry
        ns.strain_ij = '.5 (u_i,j + u_j,i + u_k,i u_k,j)'
        ns.stress_ij = 'lmbda strain_kk eye_ij + 2 mu strain_ij'

        # try:
        residual = domain.integral(ns.eval_n('stress_ij basis_ni,j d:X'),
                                   degree=2 * p)
        cons = np.ndarray.flatten(constraints * dt, order='C')
        lhs = solver.newton('w', residual, constrain=cons).solve(
            tol=state.controlpoint_absolute_tolerance, maxiter=8)

        # store the results on a splipy object and continue
        geom = lhs.reshape((n2, n1, dim), order='F')
        srf[:, :, :] += geom.swapaxes(0, 1)

        # t0 += dt
        # t1 = 1
        # except solver.SolverError: # newton method fail to converge, try a smaller step length 'dt'
        # t1 = (t1+t0)/2
    return srf
Example #16
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()
Example #17
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))
Example #18
0
 def test_newton_iter(self):
   _test_recursion_cache(self, lambda: ((self.frozen(lhs), info.resnorm) for lhs, info in solver.newton(self.dofs, residual=self.residual, constrain=self.cons)))
Example #19
0
def mixed_fem(g, ltol=1e-5, coordinate_directions=None, **solveargs):
    assert len(g) == 2
    n = len(g.x)
    basis = g.basis

    def c0(g):
        return tuple(
            [i for i in range(2) if g.degree[i] in g.knotmultiplicities[i]])

    if coordinate_directions is None:
        coordinate_directions = c0(g)

    assert len(coordinate_directions) in (1, 2) and all(
        [i in (0, 1) for i in coordinate_directions])

    s = function.stack

    veclength = {1: 4, 2: 6}[len(coordinate_directions)]
    target = function.Argument('target', [veclength * len(basis)])

    U = g.basis.vector(veclength).dot(target)

    G = metric_tensor(g, target[-n:])
    (g11, g12), (g21, g22) = G

    scale = g11 + g22

    if len(coordinate_directions) == 2:
        u, v, x_ = U[:2], U[2:4], U[4:]
        expr = function.concatenate(x_.grad(g.geom) - s([u, v], axis=1))
        res1 = (basis.vector(4) * expr).sum(-1)
        res2 = g22 * u.grad(g.geom)[:, 0] - g12 * u.grad(
            g.geom)[:, 1] - g12 * v.grad(g.geom)[:, 0] + g11 * v.grad(
                g.geom)[:, 1]

    if len(coordinate_directions) == 1:
        index = coordinate_directions[0]
        u, x_ = U[:2], U[2:4]
        expr = x_.grad(g.geom)[:, index] - u
        res1 = (basis.vector(2) * expr).sum(-1)
        if index == 0:
            x_eta = x_.grad(g.geom)[:, 1]
            res2 = g22 * u.grad(g.geom)[:, 0] - g12 * u.grad(
                g.geom)[:, 1] - g12 * x_eta.grad(
                    g.geom)[:, 0] + g11 * x_eta.grad(g.geom)[:, 1]
        if index == 1:
            x_xi = x_.grad(g.geom)[:, 0]
            res2 = g22 * x_xi.grad(g.geom)[:, 0] - g12 * u.grad(
                g.geom)[:, 0] - g12 * x_xi.grad(g.geom)[:, 1] + g11 * u.grad(
                    g.geom)[:, 1]

    res = function.concatenate(
        [res1, (basis.vector(2) * res2).sum(-1) / scale])
    res = g.domain.integral(res, geometry=g.geom, degree=g.ischeme * 4)

    mapping0 = g.basis.vector(2).dot(g.x)

    cons = util.NanVec(n * (len(coordinate_directions) + 1))
    cons[-n:] = g.cons
    init = np.concatenate([
        g.domain.project(mapping0.grad(g.geom)[:, i],
                         geometry=g.geom,
                         onto=g.basis.vector(2),
                         ischeme='gauss12') for i in coordinate_directions
    ] + [g.x])

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

    g.x = lhs[-n:]
Example #20
0
def elliptic_control_mapping(g,
                             f,
                             eps=1e-4,
                             ltol=1e-5,
                             degree=None,
                             **solveargs):
    '''
        Nutils implementation of the corresponding method from the ``fsol`` module.
        It's slower but accepts any control mapping function. Unline in the ``fsol``
        case, all derivatives are computed automatically.
    '''

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

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

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

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

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

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

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

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

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

    scale = g11 + g22 + eps

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

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

    g.x = lhs
Example #21
0
 def test_newton(self):
   self.assert_resnorm(solver.newton('dofs', residual=self.residual, lhs0=self.lhs0, constrain=self.cons).solve(tol=self.tol, maxiter=2))
Example #22
0
 def test_newton_boolcons(self):
   self.assert_resnorm(solver.newton('dofs', residual=self.residual, constrain=self.boolcons).solve(tol=self.tol, maxiter=7))
Example #23
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 #24
0
 def test_newton_iter(self):
   _test_recursion_cache(self, lambda: ((types.frozenarray(lhs), info.resnorm) for lhs, info in solver.newton('dofs', residual=self.residual, constrain=self.cons)))