示例#1
0
    def shear_stress(self, velocity):
        if self.geometric_dimension == 1:
            return dolf.Constant(4.0 / 3.0) * velocity.dx(0) / self.dolf_constants.Re

        i, j = ufl.indices(2)
        shear_stress = (
            velocity[i].dx(j)
            + dolf.Constant(1.0 / 3.0) * self.identity_tensor[i, j] * dolf.div(velocity)
        ) / self.dolf_constants.Re
        # shear_stress = (
        #     velocity[i].dx(j)
        #     + velocity[j].dx(i)
        #     - dolf.Constant(2.0 / 3.0) * self.identity_tensor[i, j] * dolf.div(velocity)
        # ) / self.dolf_constants.Re
        return dolf.as_tensor(shear_stress, (i, j))
示例#2
0
    def strain_rate_tensor(self, u):
        r"""Define the symmetric strain-rate tensor

        :param u: The velocity field (2D).
        :return: The strain rate tensor.
        """
        r = dolfin.SpatialCoordinate(self._mesh)[0]
        ur = u[0]
        uz = u[1]
        ur_r = ur.dx(0)
        ur_z = ur.dx(1)
        uz_r = uz.dx(0)
        uz_z = uz.dx(1)
        return dolfin.sym(
            dolfin.as_tensor([[ur_r, 0, 0.5 * (uz_r + ur_z)], [0, ur / r, 0],
                              [0.5 * (uz_r + ur_z), 0, uz_z]]))
示例#3
0
def gen3d2(rank2_2d):
    r"""
    Generate a 3D 2-tensor from a 2D 2-tensor (add zeros to last dimensions).

    Returns the synthetic 3D version
    :math:`A \in \mathbb{R}^{3 \times 3}`
    of a 2D rank-2 tensor
    :math:`B \in \mathbb{R}^{2 \times 2}`.
    The 3D-components are set to zero.

    .. math::
        B &= \begin{pmatrix}
                b_{xx} & b_{xy} \\
                b_{yx} & b_{yy}
            \end{pmatrix}
        \\
        A &= \begin{pmatrix}
                b_{xx} & b_{xy} & 0 \\
                b_{yx} & b_{yy} & 0 \\
                0      & 0      & 0
            \end{pmatrix}

    Example
    -------

    >>> t2d = df.Expression((("1","2"),("3","4")), degree=1)
    >>> t3d = gen3d2(t2d)
    >>> print(
    ...     t3d[0,0]==t2d[0,0] and
    ...     t3d[0,1]==t2d[0,1] and
    ...     t3d[0,2]==0 and
    ...     t3d[1,0]==t2d[1,0] and
    ...     t3d[1,1]==t2d[1,1] and
    ...     t3d[1,2]==0 and
    ...     t3d[2,0]==0 and
    ...     t3d[2,1]==0 and
    ...     t3d[2,2]==0
    ... )
    True

    """
    return df.as_tensor([[rank2_2d[0, 0], rank2_2d[0, 1], 0],
                         [rank2_2d[1, 0], rank2_2d[1, 1], 0], [0, 0, 0]])
示例#4
0
def gen3dTF2(rank2_2d):
    r"""
    Generate a 3D tracefree 2-tensor from a 2D 2-tensor.

    Returns the synthetic 3D version
    :math:`A \in \mathbb{R}^{3 \times 3}`
    of a 2D rank-2 tensor
    :math:`B \in \mathbb{R}^{2 \times 2}`.

    .. math::
        B &= \begin{pmatrix}
                b_{xx} & b_{xy} \\
                b_{yx} & b_{yy}
            \end{pmatrix}
        \\
        A &= \begin{pmatrix}
                b_{xx} & b_{xy} & 0 \\
                b_{yx} & b_{yy} & 0 \\
                0      & 0      & -(b_{yx}+b_{yy})
            \end{pmatrix}

    Example
    -------

    >>> t2d = df.Expression((("1","2"),("3","4")), degree=1)
    >>> t3d = gen3dTF2(t2d)
    >>> print(
    ...     t3d[0,0]==t2d[0,0] and
    ...     t3d[0,1]==t2d[0,1] and
    ...     t3d[0,2]==0 and
    ...     t3d[1,0]==t2d[1,0] and
    ...     t3d[1,1]==t2d[1,1] and
    ...     t3d[1,2]==0 and
    ...     t3d[2,0]==0 and
    ...     t3d[2,1]==0 and
    ...     t3d[2,2]==-t2d[0,0]-t2d[1,1]
    ... )
    True

    """
    return df.as_tensor([[rank2_2d[0, 0], rank2_2d[0, 1], 0],
                         [rank2_2d[1, 0], rank2_2d[1, 1], 0],
                         [0, 0, -rank2_2d[0, 0] - rank2_2d[1, 1]]])
示例#5
0
    def _spatial_component(self, trial, test):
        pressure, velocity, temperature = trial
        test_pressure, test_velocity, test_temperature = test

        i, j = ufl.indices(2)

        if self.geometric_dimension == 1:
            continuity_component = test_pressure * velocity.dx(0)
            momentum_component = test_velocity.dx(0) * self.stress(pressure, velocity)
        else:
            continuity_component = test_pressure * dolf.div(velocity)
            momentum_component = dolf.inner(
                dolf.as_tensor(test_velocity[i].dx(j), (i, j)),
                self.stress(pressure, velocity),
            )
        energy_component = dolf.inner(
            dolf.grad(test_temperature), self.heat_flux(temperature)
        )
        return continuity_component + momentum_component + energy_component
示例#6
0
    def define_coupled_equation(self):
        """
        Setup the coupled Navier-Stokes equation

        This implementation assembles the full LHS and RHS each time they are needed
        """
        sim = self.simulation
        mpm = sim.multi_phase_model
        mesh = sim.data['mesh']
        Vcoupled = sim.data['Vcoupled']
        u_conv = sim.data['u_conv']

        # Unpack the coupled trial and test functions
        uc = dolfin.TrialFunction(Vcoupled)
        vc = dolfin.TestFunction(Vcoupled)
        ulist = []
        vlist = []
        sigmas, taus = [], []
        for d in range(sim.ndim):
            ulist.append(uc[d])
            vlist.append(vc[d])
            indices = list(
                range(1 + sim.ndim * (d + 1), 1 + sim.ndim * (d + 2)))
            sigmas.append([uc[i] for i in indices])
            taus.append([vc[i] for i in indices])

        u = dolfin.as_vector(ulist)
        v = dolfin.as_vector(vlist)
        p = uc[sim.ndim]
        q = vc[sim.ndim]
        sigma = dolfin.as_tensor(sigmas)
        tau = dolfin.as_tensor(taus)

        c1, c2, c3 = sim.data['time_coeffs']
        dt = sim.data['dt']
        g = sim.data['g']
        n = dolfin.FacetNormal(mesh)
        h = dolfin.FacetArea(mesh)

        # Fluid properties
        rho = mpm.get_density(0)
        mu = mpm.get_laminar_dynamic_viscosity(0)

        # Upwind and downwind velocities
        w_nU = (dot(u_conv, n) + abs(dot(u_conv, n))) / 2.0
        w_nD = (dot(u_conv, n) - abs(dot(u_conv, n))) / 2.0
        u_uw_s = dolfin.conditional(dolfin.gt(dot(u_conv, n), 0.0), 1.0,
                                    0.0)('+')
        u_uw = u_uw_s * u('+') + (1 - u_uw_s) * u('-')

        # LDG penalties
        # kappa_0 = Constant(4.0)
        # kappa = mu*kappa_0/h
        C11 = avg(mu / h)
        D11 = avg(h / mu)
        C12 = 0.2 * n('+')
        D12 = 0.2 * n('+')

        def ojump(v, n):
            return outer(v, n)('+') + outer(v, n)('-')

        # Interior facet fluxes
        # u_hat_dS = avg(u)
        # sigma_hat_dS = avg(sigma) - avg(kappa)*ojump(u, n)
        # p_hat_dS = avg(p)
        u_hat_s_dS = avg(u) + dot(ojump(u, n), C12)
        u_hat_p_dS = avg(u) + D11 * jump(p, n) + D12 * jump(u, n)
        sigma_hat_dS = avg(sigma) - C11 * ojump(u, n) - outer(
            jump(sigma, n), C12)
        p_hat_dS = avg(p) - dot(D12, jump(p, n))

        # Time derivative
        up = sim.data['up']
        upp = sim.data['upp']
        eq = rho * dot(c1 * u + c2 * up + c3 * upp, v) / dt * dx

        # LDG equation 1
        eq += inner(sigma, tau) * dx
        eq += dot(u, div(mu * tau)) * dx
        eq -= dot(u_hat_s_dS, jump(mu * tau, n)) * dS

        # LDG equation 2
        eq += (inner(sigma, grad(v)) - p * div(v)) * dx
        eq -= (inner(sigma_hat_dS, ojump(v, n)) - p_hat_dS * jump(v, n)) * dS
        eq -= dot(u, div(outer(v, rho * u_conv))) * dx
        eq += rho('+') * dot(u_conv('+'), n('+')) * dot(u_uw, v('+')) * dS
        eq += rho('-') * dot(u_conv('-'), n('-')) * dot(u_uw, v('-')) * dS
        momentum_sources = sim.data['momentum_sources'] + [rho * g]
        eq -= dot(sum(momentum_sources), v) * dx

        # LDG equation 3
        eq -= dot(u, grad(q)) * dx
        eq += dot(u_hat_p_dS, jump(q, n)) * dS

        # Dirichlet boundary
        dirichlet_bcs = get_collected_velocity_bcs(sim, 'dirichlet_bcs')
        for ds, u_bc in dirichlet_bcs.items():
            # sigma_hat_ds = sigma - kappa*outer(u, n)
            sigma_hat_ds = sigma - C11 * outer(u - u_bc, n)
            u_hat_ds = u_bc
            p_hat_ds = p

            # LDG equation 1
            eq -= dot(u_hat_ds, dot(mu * tau, n)) * ds

            # LDG equation 2
            eq -= (inner(sigma_hat_ds, outer(v, n)) -
                   p_hat_ds * dot(v, n)) * ds
            eq += rho * w_nU * dot(u, v) * ds
            eq += rho * w_nD * dot(u_bc, v) * ds

            # LDG equation 3
            eq += dot(u_hat_ds, q * n) * ds

        # Neumann boundary
        neumann_bcs = get_collected_velocity_bcs(sim, 'neumann_bcs')
        assert not neumann_bcs
        for ds, du_bc in neumann_bcs.items():
            # Divergence free criterion
            if self.use_grad_q_form:
                eq += q * dot(u, n) * ds
            else:
                eq -= q * dot(u, n) * ds

            # Convection
            eq += rho * w_nU * dot(u, v) * ds

            # Diffusion
            u_hat_ds = u
            sigma_hat_ds = outer(du_bc, n) / mu
            eq -= dot(u_hat_ds, dot(mu * tau, n)) * ds
            eq -= inner(sigma_hat_ds, outer(v, n)) * ds

            # Pressure
            if not self.use_grad_p_form:
                eq += p * dot(v, n) * ds

        a, L = dolfin.system(eq)
        self.form_lhs = a
        self.form_rhs = L
        self.tensor_lhs = None
        self.tensor_rhs = None
示例#7
0
def solve(mesh, Eps, degree):
    V = FunctionSpace(mesh, "CG", degree)
    u = TrialFunction(V)
    v = TestFunction(V)

    n = FacetNormal(mesh)

    gdim = mesh.geometry().dim()

    A = [
        _assemble_eigen(
            Constant(Eps[i, j]) * (u.dx(i) * v.dx(j) * dx - u.dx(i) * n[j] * v * ds)
        ).sparray()
        for j in range(gdim)
        for i in range(gdim)
    ]

    assert_equality = False
    if assert_equality:
        # The sum of the `A`s is exactly that:
        n = FacetNormal(V.mesh())
        AA = _assemble_eigen(
            +dot(dot(as_tensor(Eps), grad(u)), grad(v)) * dx
            - dot(dot(as_tensor(Eps), grad(u)), n) * v * ds
        ).sparray()
        diff = AA - sum(A)
        assert numpy.all(abs(diff.data) < 1.0e-14)
        #
        # ATAsum = sum(a.T.dot(a) for a in A)
        # diff = AA.T.dot(AA) - ATAsum
        # # import betterspy
        # # betterspy.show(ATAsum)
        # # betterspy.show(AA.T.dot(AA))
        # # betterspy.show(ATAsum - AA.T.dot(AA))
        # print(diff.data)
        # assert numpy.all(abs(diff.data) < 1.0e-14)

    tol = 1.0e-10

    def lower(x, on_boundary):
        return on_boundary and x[1] < -1.0 + tol

    def upper(x, on_boundary):
        return on_boundary and x[1] > 1.0 - tol

    def left(x, on_boundary):
        return on_boundary and abs(x[0] + 1.0) < tol

    def right(x, on_boundary):
        return on_boundary and abs(x[0] - 1.0) < tol

    def upper_left(x, on_boundary):
        return on_boundary and x[1] > +1.0 - tol and x[0] < -0.8

    def lower_right(x, on_boundary):
        return on_boundary and x[1] < -1.0 + tol and x[0] > 0.8

    bcs = [
        # DirichletBC(V, Constant(0.0), lower_right),
        # DirichletBC(V, Constant(0.0), upper_left),
        DirichletBC(V, Constant(0.0), lower),
        DirichletBC(V, Constant(0.0), upper),
        # DirichletBC(V, Constant(0.0), upper_left, method='pointwise'),
        # DirichletBC(V, Constant(0.0), lower_left, method='pointwise'),
        # DirichletBC(V, Constant(0.0), lower_right, method='pointwise'),
    ]

    M = _assemble_eigen(u * v * dx).sparray()

    ATMinvAsum = sum(
        numpy.dot(a.toarray().T, numpy.linalg.solve(M.toarray(), a.toarray()))
        for a in A
    )

    AA2 = _assemble_eigen(
        +dot(dot(as_tensor(Eps), grad(u)), grad(v)) * dx
        - dot(dot(as_tensor(Eps), grad(u)), n) * v * ds,
        # bcs=[DirichletBC(V, Constant(0.0), 'on_boundary')]
        # bcs=bcs
        # bcs=[
        #     DirichletBC(V, Constant(0.0), lower),
        #     DirichletBC(V, Constant(0.0), right),
        #     ]
    ).sparray()

    ATA2 = numpy.dot(AA2.toarray().T, numpy.linalg.solve(M.toarray(), AA2.toarray()))

    # Find combination of Dirichlet points:
    if False:
        # min_val = 1.0
        max_val = 0.0
        # min_combi = []
        max_combi = []
        is_updated = False
        it = 0
        # get boundary indices
        d = DirichletBC(V, Constant(0.0), "on_boundary")
        boundary_idx = numpy.sort(list(d.get_boundary_values().keys()))
        # boundary_idx = numpy.arange(V.dim())
        # print(boundary_idx)
        # pick some at random
        # idx = numpy.sort(numpy.random.choice(boundary_idx, size=3, replace=False))
        for idx in itertools.combinations(boundary_idx, 3):
            it += 1
            print()
            print(it)

            # Replace the rows corresponding to test functions living in one cell
            # (deliberately chosen as 0) by Dirichlet rows.
            AA3 = AA2.tolil()
            for k in idx:
                AA3[k] = 0
                AA3[k, k] = 1
            n = AA3.shape[0]
            AA3 = AA3.tocsr()

            ATA2 = numpy.dot(
                AA3.toarray().T, numpy.linalg.solve(M.toarray(), AA3.toarray())
            )
            vals = numpy.sort(numpy.linalg.eigvalsh(ATA2))
            if vals[0] < 0.0:
                continue

            # op = sparse.linalg.LinearOperator(
            #     (n, n),
            #     matvec=lambda x: _spsolve(AA3, M.dot(_spsolve(AA3.T.tocsr(), x)))
            #     )
            # vals, _ = scipy.sparse.linalg.eigsh(op, k=3, which='LM')
            # vals = numpy.sort(1/vals[::-1])
            # print(vals)

            print(idx)

            # if min_val > vals[0]:
            #     min_val = vals[0]
            #     min_combi = idx
            #     is_updated = True

            if max_val < vals[0]:
                max_val = vals[0]
                max_combi = idx
                is_updated = True

            if is_updated:
                # vals, _ = scipy.sparse.linalg.eigsh(op, k=10, which='LM')
                # vals = numpy.sort(1/vals[::-1])
                # print(vals)
                is_updated = False
                # print(min_val, min_combi)
                print(max_val, max_combi)
                # plt.plot(dofs_x[:, 0], dofs_x[:, 1], 'x')
                meshzoo.plot2d(mesh.coordinates(), mesh.cells())
                dofs_x = V.tabulate_dof_coordinates().reshape((-1, gdim))
                # plt.plot(dofs_x[min_combi, 0], dofs_x[min_combi, 1], 'or')
                plt.plot(dofs_x[max_combi, 0], dofs_x[max_combi, 1], "ob")
                plt.gca().set_aspect("equal")
                plt.title(f"smallest eigenvalue: {max_val}")
                plt.show()

            # # if True:
            # if abs(vals[0]) < 1.0e-8:
            #     gdim = mesh.geometry().dim()
            #     # plt.plot(dofs_x[:, 0], dofs_x[:, 1], 'x')
            #     X = mesh.coordinates()
            #     meshzoo.plot2d(mesh.coordinates(), mesh.cells())
            #     dofs_x = V.tabulate_dof_coordinates().reshape((-1, gdim))
            #     plt.plot(dofs_x[idx, 0], dofs_x[idx, 1], 'or')
            #     plt.gca().set_aspect('equal')
            #     plt.show()

        meshzoo.plot2d(mesh.coordinates(), mesh.cells())
        dofs_x = V.tabulate_dof_coordinates().reshape((-1, gdim))
        # plt.plot(dofs_x[min_combi, 0], dofs_x[min_combi, 1], 'or')
        plt.plot(dofs_x[max_combi, 0], dofs_x[max_combi, 1], "ob")
        plt.gca().set_aspect("equal")
        plt.title(f"final smallest eigenvalue: {max_val}")
        plt.show()
        exit(1)

    # Eigenvalues of the operators
    if True:
        # import betterspy
        # betterspy.show(sum(A), colormap="viridis")

        AA = _assemble_eigen(
            +dot(grad(u), grad(v)) * dx - dot(grad(u), n) * v * ds
        ).sparray()

        eigvals, eigvecs = scipy.sparse.linalg.eigs(AA, k=5, which="SM")

        assert numpy.all(numpy.abs(eigvals.imag) < 1.0e-12)
        eigvals = eigvals.real
        assert numpy.all(numpy.abs(eigvecs.imag) < 1.0e-12)
        eigvecs = eigvecs.real

        i = numpy.argsort(eigvals)
        print(eigvals[i])

        import meshio

        for k in range(3):
            meshio.write_points_cells(
                f"eigval{k}.vtk",
                points,
                {"triangle": cells},
                point_data={"ev": eigvecs[:, i][:, k]},
            )
        exit(1)

        # import betterspy
        # betterspy.show(AA, colormap="viridis")
        # print(numpy.sort(numpy.linalg.eigvals(AA.todense())))
        exit(1)

        Asum = sum(A).todense()
        AsumT_Minv_Asum = numpy.dot(Asum.T, numpy.linalg.solve(M.toarray(), Asum))

        # print(numpy.sort(numpy.linalg.eigvalsh(Asum)))
        print(numpy.sort(numpy.linalg.eigvalsh(AsumT_Minv_Asum)))
        exit(1)

        # eigvals, eigvecs = numpy.linalg.eigh(Asum)
        # i = numpy.argsort(eigvals)
        # print(eigvals[i])
        # exit(1)
        # print(eigvals[:20])
        # eigvals[eigvals < 1.0e-15] = 1.0e-15
        #
        # eigvals = numpy.sort(numpy.linalg.eigvalsh(sum(A).todense()))
        # print(eigvals[:20])
        # plt.semilogy(eigvals, ".", label="Asum")
        # plt.legend()
        # plt.grid()
        # plt.show()
        # exit(1)

        ATMinvAsum_eigs = numpy.sort(numpy.linalg.eigvalsh(ATMinvAsum))
        print(ATMinvAsum_eigs[:20])
        ATMinvAsum_eigs[ATMinvAsum_eigs < 0.0] = 1.0e-12
        # ATA2_eigs = numpy.sort(numpy.linalg.eigvalsh(ATA2))
        # print(ATA2_eigs[:20])
        plt.semilogy(ATMinvAsum_eigs, ".", label="ATMinvAsum")
        # plt.semilogy(ATA2_eigs, ".", label="ATA2")
        plt.legend()
        plt.grid()
        plt.show()
        # # Preconditioned eigenvalues
        # # IATA_eigs = numpy.sort(scipy.linalg.eigvalsh(ATMinvAsum, ATA2))
        # # plt.semilogy(IATA_eigs, ".", label="precond eigenvalues")
        # # plt.legend()
        # # plt.show()
        exit(1)

    # # Test with A only
    # numpy.random.seed(123)
    # b = numpy.random.rand(sum(a.shape[0] for a in A))
    # MTM = M.T.dot(M)
    # MTb = M.T.dot(b)
    # sol = _gmres(
    #     MTM,
    #     # TODO linear operator
    #     # lambda x: M.T.dot(M.dot(x)),
    #     MTb,
    #     M=prec
    #     )
    # plt.semilogy(sol.resnorms)
    # plt.show()
    # exit(1)

    n = AA2.shape[0]

    # define the operator
    def matvec(x):
        # M^{-1} can be computed in O(n) with CG + diagonal preconditioning
        # or algebraic multigrid.
        # return sum([a.T.dot(a.dot(x)) for a in A])
        return numpy.sum([a.T.dot(_spsolve(M, a.dot(x))) for a in A], axis=0)

    op = sparse.linalg.LinearOperator((n, n), matvec=matvec)

    # pick a random solution and a consistent rhs
    x = numpy.random.rand(n)
    b = op.dot(x)

    linear_system = krypy.linsys.LinearSystem(op, b)
    print("unpreconditioned solve...")
    t = time.time()
    out = krypy.linsys.Gmres(linear_system, tol=1.0e-12, explicit_residual=True)
    out.xk = out.xk.reshape(b.shape)
    print("done.")
    print("  res: {}".format(out.resnorms[-1]))
    print(
        "  unprec res: {}".format(
            numpy.linalg.norm(b - op.dot(out.xk)) / numpy.linalg.norm(b)
        )
    )
    # The error isn't useful here; only with the nullspace removed
    # print('  error: {}'.format(numpy.linalg.norm(out.xk - x)))
    print("  its: {}".format(len(out.resnorms)))
    print("  duration: {}s".format(time.time() - t))

    # preconditioned solver
    ml = pyamg.smoothed_aggregation_solver(AA2)
    # res = []
    # b = numpy.random.rand(AA2.shape[0])
    # x0 = numpy.zeros(AA2.shape[1])
    # x = ml.solve(b, x0, residuals=res, tol=1.0e-12)
    # print(res)
    # plt.semilogy(res)
    # plt.show()

    mlT = pyamg.smoothed_aggregation_solver(AA2.T.tocsr())
    # res = []
    # b = numpy.random.rand(AA2.shape[0])
    # x0 = numpy.zeros(AA2.shape[1])
    # x = mlT.solve(b, x0, residuals=res, tol=1.0e-12)

    # print(res)
    def prec_matvec(b):
        x0 = numpy.zeros(n)
        b1 = mlT.solve(b, x0, tol=1.0e-12)
        b2 = M.dot(b1)
        x = ml.solve(b2, x0, tol=1.0e-12)
        return x

    prec = LinearOperator((n, n), matvec=prec_matvec)

    # TODO assert this in a test
    # x = prec_matvec(b)
    # print(b - AA2.T.dot(AA2.dot(x)))

    linear_system = krypy.linsys.LinearSystem(op, b, Ml=prec)
    print()
    print("preconditioned solve...")
    t = time.time()
    try:
        out_prec = krypy.linsys.Gmres(
            linear_system, tol=1.0e-14, maxiter=1000, explicit_residual=True
        )
    except krypy.utils.ConvergenceError:
        print("prec not converged!")
        pass
    out_prec.xk = out_prec.xk.reshape(b.shape)
    print("done.")
    print("  res: {}".format(out_prec.resnorms[-1]))
    print(
        "  unprec res: {}".format(
            numpy.linalg.norm(b - op.dot(out_prec.xk)) / numpy.linalg.norm(b)
        )
    )
    print("  its: {}".format(len(out_prec.resnorms)))
    print("  duration: {}s".format(time.time() - t))

    plt.semilogy(out.resnorms, label="original")
    plt.semilogy(out_prec.resnorms, label="preconditioned")
    plt.legend()
    plt.show()

    return out.xk
示例#8
0
def grad3dOf2(rank2_3d):
    r"""
    Return 3D gradient of 3D 2-tensor.

    Returns the 3D gradient (w.r.t. :math:`x,y,z`)
    :math:`\frac{\partial A_{ij}}{\partial x_{k}}`
    of a 3D :math:`z`-independent rank-2 tensor
    :math:`A(x,y) \in \mathbb{R}^{3 \times 3}`
    where

    .. math::
        A_{ij} = \begin{pmatrix}
                    a_{xx}(x,y) & a_{xy}(x,y) & a_{xz}(x,y) \\
                    a_{yx}(x,y) & a_{yy}(x,y) & a_{yz}(x,y) \\
                    a_{zx}(x,y) & a_{zy}(x,y) & a_{zz}(x,y)
                \end{pmatrix}

    The function then returns the 3-tensor with components
    :math:`\frac{\partial A_{ij}}{\partial x_{k}}`
    where

    .. math::
        \frac{\partial A_{ij}}{\partial x_{1}}
        =
        \frac{\partial A_{ij}}{\partial x}
        &= \begin{pmatrix}
                \partial_x a_{xx}(x,y) &
                \partial_x a_{xy}(x,y) &
                \partial_x a_{xz}(x,y) \\
                \partial_x a_{yx}(x,y) &
                \partial_x a_{yy}(x,y) &
                \partial_x a_{yz}(x,y) \\
                \partial_x a_{zx}(x,y) &
                \partial_x a_{zy}(x,y) &
                \partial_x a_{zz}(x,y)
            \end{pmatrix}
        , \\
        \frac{\partial A_{ij}}{\partial x_{2}}
        =
        \frac{\partial A_{ij}}{\partial y}
        &= \begin{pmatrix}
                \partial_y a_{xx}(x,y) &
                \partial_y a_{xy}(x,y) &
                \partial_y a_{xz}(x,y) \\
                \partial_y a_{yx}(x,y) &
                \partial_y a_{yy}(x,y) &
                \partial_y a_{yz}(x,y) \\
                \partial_y a_{zx}(x,y) &
                \partial_y a_{zy}(x,y) &
                \partial_y a_{zz}(x,y)
            \end{pmatrix}
        , \\
        \frac{\partial A_{ij}}{\partial x_{3}}
        =
        0
        &= \begin{pmatrix}
                0 &
                0 &
                0 \\
                0 &
                0 &
                0 \\
                0 &
                0 &
                0
            \end{pmatrix}
    """
    grad2d = df.grad(rank2_3d)
    dim3 = df.as_tensor([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
    grad3d = df.as_tensor([grad2d[:, :, 0], grad2d[:, :, 1], dim3[:, :]])
    return grad3d
示例#9
0
def solve(M, b, mesh, Eps):
    V = FunctionSpace(mesh, 'CG', 1)
    u = TrialFunction(V)
    v = TestFunction(V)

    n = FacetNormal(mesh)

    dim = mesh.geometry().dim()

    A = [
        [
            _assemble_eigen(+Constant(Eps[i, j]) * u.dx(i) * v.dx(j) * dx
                            # pylint: disable=unsubscriptable-object
                            - Constant(Eps[i, j]) * u.dx(i) * n[j] * v *
                            ds).sparray() for j in range(dim)
        ] for i in range(dim)
    ]
    Aflat = [item for sublist in A for item in sublist]

    assert_equality = False
    if assert_equality:
        # The sum of the `A`s is exactly that:
        n = FacetNormal(V.mesh())
        AA = _assemble_eigen(+dot(dot(as_tensor(Eps), grad(u)), grad(v)) * dx -
                             dot(dot(as_tensor(Eps), grad(u)), n) * v *
                             ds).sparray()
        diff = AA - sum(Aflat)
        assert numpy.all(abs(diff.data) < 1.0e-14)
        #
        # ATAsum = sum(a.T.dot(a) for a in Aflat)
        # diff = AA.T.dot(AA) - ATAsum
        # # import betterspy
        # # betterspy.show(ATAsum)
        # # betterspy.show(AA.T.dot(AA))
        # # betterspy.show(ATAsum - AA.T.dot(AA))
        # print(diff.data)
        # assert numpy.all(abs(diff.data) < 1.0e-14)

    tol = 1.0e-13

    def lower(x, on_boundary):
        return on_boundary and abs(x[1] + 1.0) < tol

    def right(x, on_boundary):
        return on_boundary and abs(x[0] - 1.0) < tol

    def upper_left(x, on_boundary):
        return on_boundary and (abs(x[0] + 1.0) < tol) and (abs(x[1] - 1.0) <
                                                            tol)

    def lower_left(x, on_boundary):
        return on_boundary and (abs(x[0] + 1.0) < tol) and (abs(x[1] + 1.0) <
                                                            tol)

    def lower_right(x, on_boundary):
        return on_boundary and (abs(x[0] - 1.0) < tol) and (abs(x[1] + 1.0) <
                                                            tol)

    bcs = [
        DirichletBC(V, Constant(0.0), upper_left, method='pointwise'),
        DirichletBC(V, Constant(0.0), lower_left, method='pointwise'),
        DirichletBC(V, Constant(0.0), lower_right, method='pointwise'),
    ]

    # TODO THIS IS IT
    AA2 = _assemble_eigen(
        +dot(dot(as_tensor(Eps), grad(u)), grad(v)) * dx -
        dot(dot(as_tensor(Eps), grad(u)), n) * v * ds,
        # bcs=[DirichletBC(V, Constant(0.0), 'on_boundary')]
        # bcs=bcs
        bcs=[
            DirichletBC(V, Constant(0.0), lower),
            DirichletBC(V, Constant(0.0), right),
        ]).sparray()

    ATA2 = AA2.dot(AA2)
    # ATAsum = sum(a.T.dot(a) for a in Aflat)

    # ATAsum_eigs = numpy.sort(numpy.linalg.eigvalsh(ATAsum.todense()))
    # print(ATAsum_eigs)
    # print()
    ATA2_eigs = numpy.sort(numpy.linalg.eigvalsh(ATA2.todense()))
    print(ATA2_eigs)
    exit(1)
    # plt.semilogy(range(len(ATAsum_eigs)), ATAsum_eigs, '.', label='ATAsum')
    # plt.semilogy(range(len(ATA2_eigs)), ATA2_eigs, '.', label='ATA2')
    # plt.legend()
    # plt.show()

    # # invsqrtATA2 = numpy.linalg.inv(scipy.linalg.sqrtm(ATA2.todense()))
    # # IATA = numpy.dot(numpy.dot(invsqrtATA2, ATAsum), invsqrtATA2)
    # # IATA_eigs = numpy.sort(numpy.linalg.eigvals(IATA))
    # IATA_eigs = numpy.sort(scipy.linalg.eigvals(ATAsum.todense(), ATA2.todense()))
    # plt.semilogy(range(len(IATA_eigs)), IATA_eigs, '.', label='IATA')
    # # plt.plot(IATA_eigs, numpy.zeros(len(IATA_eigs)), 'x', label='IATA')
    # plt.legend()
    # plt.show()
    # # exit(1)

    # # Test with A only
    # M = sparse.vstack(Aflat)
    # numpy.random.seed(123)
    # b = numpy.random.rand(sum(a.shape[0] for a in Aflat))
    # MTM = M.T.dot(M)
    # MTb = M.T.dot(b)
    # sol = _gmres(
    #     MTM,
    #     # TODO linear operator
    #     # lambda x: M.T.dot(M.dot(x)),
    #     MTb,
    #     M=prec
    #     )
    # plt.semilogy(sol.resnorms)
    # plt.show()
    # exit(1)

    ml = pyamg.smoothed_aggregation_solver(AA2)
    # res = []
    # b = numpy.random.rand(AA2.shape[0])
    # x0 = numpy.zeros(AA2.shape[1])
    # x = ml.solve(b, x0, residuals=res, tol=1.0e-12)
    # print(res)
    # plt.semilogy(res)
    # plt.show()

    mlT = pyamg.smoothed_aggregation_solver(AA2.T.tocsr())

    # res = []
    # b = numpy.random.rand(AA2.shape[0])
    # x0 = numpy.zeros(AA2.shape[1])
    # x = mlT.solve(b, x0, residuals=res, tol=1.0e-12)

    # print(res)
    def prec_matvec(b):
        n = len(b)
        x0 = numpy.zeros(n)
        b1 = mlT.solve(b, x0, tol=1.0e-12)
        x = ml.solve(b1, x0, tol=1.0e-12)
        return x

    n = AA2.shape[0]
    prec = LinearOperator((n, n), matvec=prec_matvec)

    # TODO assert this in a test
    # x = prec_matvec(b)
    # print(b - AA2.T.dot(AA2.dot(x)))

    MTM = sparse.linalg.LinearOperator((M.shape[1], M.shape[1]),
                                       matvec=lambda x: M.T.dot(M.dot(x)))

    linear_system = krypy.linsys.LinearSystem(MTM, M.T.dot(b), M=prec)
    out = krypy.linsys.Gmres(linear_system, tol=1.0e-12)

    # plt.semilogy(out.resnorms)
    # plt.show()

    return out.xk