コード例 #1
0
 def prec_inv(psi):
     prec_orig = pyfvm.get_fvm_matrix(self.mesh,
                                      edge_kernels=[Energy(mu)])
     diag = prec_orig.diagonal()
     diag += self.g * 2.0 * (psi[0::2]**2 + psi[1::2]**2) * cv[0::2]
     prec_orig.setdiag(diag)
     return split_sparse_matrix(prec_orig).tocsr()
コード例 #2
0
ファイル: test_ginzburg_landau.py プロジェクト: nschloe/pyfvm
def test_keo(filename, control_values):
    filename = download_mesh(filename)
    mu = 1.0e-2

    # read the mesh
    mesh, point_data, field_data, _ = meshplex.read(filename)

    keo = pyfvm.get_fvm_matrix(mesh, edge_kernels=[Energy(mu)])

    tol = 1.0e-13

    # Check that the matrix is Hermitian.
    KK = keo - keo.H
    assert abs(KK.sum()) < tol

    # Check the matrix sum.
    assert abs(control_values[0] - keo.sum()) < tol

    # Check the 1-norm of the matrix |Re(K)| + |Im(K)|.
    # This equals the 1-norm of the matrix defined by the block
    # structure
    #   Re(K) -Im(K)
    #   Im(K)  Re(K).
    K = abs(keo.real) + abs(keo.imag)
    assert abs(control_values[1] - numpy.max(K.sum(0))) < tol
    return
コード例 #3
0
def test_keo(filename, control_values):
    filename = download_mesh(filename)
    mu = 1.0e-2

    # read the mesh
    mesh = meshplex.read(filename)

    keo = pyfvm.get_fvm_matrix(mesh, edge_kernels=[Energy(mu)])

    tol = 1.0e-13

    # Check that the matrix is Hermitian.
    KK = keo - keo.H
    assert abs(KK.sum()) < tol

    # Check the matrix sum.
    assert abs(control_values[0] - keo.sum()) < tol

    # Check the 1-norm of the matrix |Re(K)| + |Im(K)|.
    # This equals the 1-norm of the matrix defined by the block
    # structure
    #   Re(K) -Im(K)
    #   Im(K)  Re(K).
    K = abs(keo.real) + abs(keo.imag)
    assert abs(control_values[1] - numpy.max(K.sum(0))) < tol
    return
コード例 #4
0
 def df_dlmbda(self, psi, mu):
     keo_prime = pyfvm.get_fvm_matrix(self.mesh, edge_kernels=[EnergyPrime(mu)])
     out = (keo_prime * psi) / self.mesh.control_volumes
     # same as in f()
     i_psi = 1j * psi
     out -= self.inner(i_psi, out) / self.inner(i_psi, i_psi) * i_psi
     return out
コード例 #5
0
ファイル: complex_energy_test.py プロジェクト: yurigba/pyfvm
def test():
    class EnergyEdgeKernel:
        def __init__(self):
            self.subdomains = [None]
            return

        def eval(self, mesh, cell_mask):
            edge_ce_ratio = mesh.ce_ratios[..., cell_mask]
            beta = 1.0
            return numpy.array([
                [edge_ce_ratio, -edge_ce_ratio * numpy.exp(1j * beta)],
                [-edge_ce_ratio * numpy.exp(-1j * beta), edge_ce_ratio],
            ])

    vertices, cells = meshzoo.rectangle(0.0, 2.0, 0.0, 1.0, 101, 51)
    mesh = meshplex.MeshTri(vertices, cells)

    matrix = pyfvm.get_fvm_matrix(mesh, [EnergyEdgeKernel()], [], [], [])
    rhs = mesh.control_volumes.copy()

    sa = pyamg.smoothed_aggregation_solver(matrix, smooth="energy")
    u = sa.solve(rhs, tol=1e-10)

    # Cannot write complex data ot VTU; split real and imaginary parts first.
    # <http://stackoverflow.com/a/38902227/353337>
    mesh.write("out.vtk", point_data={"u": u.view("(2,)float")})
    return
コード例 #6
0
    def jacobian(self, psi, mu):
        keo = split_sparse_matrix(
            pyfvm.get_fvm_matrix(self.mesh, edge_kernels=[Energy(mu)]))
        cv = to_real(self.mesh.control_volumes)

        # cv * alpha
        V = numpy.zeros(cv.shape[0])
        V[0::2] = self.V
        alpha = V + self.g * 2.0 * abs2(psi)
        jac = keo.copy()
        diag0 = jac.diagonal(0)
        b = multiply(cv, alpha)[0::2]
        diag0[0::2] += b
        diag0[1::2] += b
        jac.setdiag(diag0, k=0)

        # cv * beta
        beta = self.g * square(psi)
        diag0 = jac.diagonal(0)
        b = multiply(cv, beta)[0::2]
        diag0[0::2] += b
        diag0[1::2] -= b
        jac.setdiag(diag0, k=0)
        #
        b = multiply(cv, beta)[1::2]
        diag1 = jac.diagonal(1)
        diag1[0::2] += b
        jac.setdiag(diag1, k=1)
        #
        diag2 = jac.diagonal(-1)
        diag2[0::2] += b
        jac.setdiag(diag2, k=-1)

        return jac
コード例 #7
0
ファイル: complex_energy_test.py プロジェクト: nschloe/pyfvm
def test():
    class EnergyEdgeKernel(object):
        def __init__(self):
            self.subdomains = [None]
            return

        def eval(self, mesh, cell_mask):
            edge_ce_ratio = mesh.ce_ratios[..., cell_mask]
            beta = 1.0
            return numpy.array(
                [
                    [edge_ce_ratio, -edge_ce_ratio * numpy.exp(1j * beta)],
                    [-edge_ce_ratio * numpy.exp(-1j * beta), edge_ce_ratio],
                ]
            )

    vertices, cells = meshzoo.rectangle(0.0, 2.0, 0.0, 1.0, 101, 51)
    mesh = meshplex.MeshTri(vertices, cells)

    matrix = pyfvm.get_fvm_matrix(mesh, [EnergyEdgeKernel()], [], [], [])
    rhs = mesh.control_volumes.copy()

    sa = pyamg.smoothed_aggregation_solver(matrix, smooth="energy")
    u = sa.solve(rhs, tol=1e-10)

    # Cannot write complex data ot VTU; split real and imaginary parts first.
    # <http://stackoverflow.com/a/38902227/353337>
    mesh.write("out.vtk", point_data={"u": u.view("(2,)float")})
    return
コード例 #8
0
 def df_dlmbda(self, psi, mu):
     keo_prime = split_sparse_matrix(
         pyfvm.get_fvm_matrix(self.mesh, edge_kernels=[EnergyPrime(mu)]))
     out = keo_prime * psi
     # same as in f()
     i_psi = to_real(1j * to_complex(psi))
     out -= self.inner(i_psi, out) / self.inner(i_psi, i_psi) * i_psi
     return out
コード例 #9
0
 def f(self, psi, mu):
     keo = pyfvm.get_fvm_matrix(self.mesh, edge_kernels=[Energy(mu)])
     cv = self.mesh.control_volumes
     out = (keo * psi) / cv + (self.V + self.g * np.abs(psi) ** 2) * psi
     # Algebraically, The inner product of <f(psi), i*psi> is always 0. We project
     # out that component numerically to avoid convergence failure for the Jacobian
     # updates close to a solution. If this is not done, the Krylov method might hang
     # at something like 10^{-7}.
     i_psi = 1j * psi
     out -= self.inner(i_psi, out) / self.inner(i_psi, i_psi) * i_psi
     return out
コード例 #10
0
def test_jacobian(filename, control_values):
    filename = download_mesh(filename)
    mu = 1.0e-2

    mesh = meshplex.read(filename)
    m2 = meshio.read(filename)

    psi = m2.point_data["psi"][:, 0] + 1j * m2.point_data["psi"][:, 1]

    V = -1.0
    g = 1.0
    keo = pyfvm.get_fvm_matrix(mesh, edge_kernels=[Energy(mu)])

    def jacobian(psi):
        def _apply_jacobian(phi):
            cv = mesh.control_volumes
            y = keo * phi / cv + alpha * phi + gPsi0Squared * phi.conj()
            return y

        alpha = V + g * 2.0 * (psi.real**2 + psi.imag**2)
        gPsi0Squared = g * psi**2

        num_unknowns = len(mesh.node_coords)
        return pykry.LinearOperator(
            (num_unknowns, num_unknowns),
            complex,
            dot=_apply_jacobian,
            dot_adj=_apply_jacobian,
        )

    # Get the Jacobian
    J = jacobian(psi)

    tol = 1.0e-12

    num_unknowns = psi.shape[0]

    # [1+i, 1+i, 1+i, ... ]
    phi = numpy.full(num_unknowns, 1 + 1j)
    val = numpy.vdot(phi, mesh.control_volumes * (J * phi)).real
    assert abs(control_values[0] - val) < tol

    # [1, 1, 1, ... ]
    phi = numpy.full(num_unknowns, 1.0, dtype=complex)
    val = numpy.vdot(phi, mesh.control_volumes * (J * phi)).real
    assert abs(control_values[1] - val) < tol

    # [i, i, i, ... ]
    phi = numpy.full(num_unknowns, 1j, dtype=complex)
    val = numpy.vdot(phi, mesh.control_volumes * (J * phi)).real
    assert abs(control_values[2] - val) < tol
    return
コード例 #11
0
ファイル: test_ginzburg_landau.py プロジェクト: nschloe/pyfvm
def test_jacobian(filename, control_values):
    filename = download_mesh(filename)
    mu = 1.0e-2

    mesh, point_data, field_data, _ = meshplex.read(filename)

    psi = point_data["psi"][:, 0] + 1j * point_data["psi"][:, 1]

    V = -1.0
    g = 1.0
    keo = pyfvm.get_fvm_matrix(mesh, edge_kernels=[Energy(mu)])

    def jacobian(psi):
        def _apply_jacobian(phi):
            cv = mesh.control_volumes
            y = keo * phi / cv + alpha * phi + gPsi0Squared * phi.conj()
            return y

        alpha = V + g * 2.0 * (psi.real ** 2 + psi.imag ** 2)
        gPsi0Squared = g * psi ** 2

        num_unknowns = len(mesh.node_coords)
        return pykry.LinearOperator(
            (num_unknowns, num_unknowns),
            complex,
            dot=_apply_jacobian,
            dot_adj=_apply_jacobian,
        )

    # Get the Jacobian
    J = jacobian(psi)

    tol = 1.0e-12

    num_unknowns = psi.shape[0]

    # [1+i, 1+i, 1+i, ... ]
    phi = numpy.full(num_unknowns, 1 + 1j)
    val = numpy.vdot(phi, mesh.control_volumes * (J * phi)).real
    assert abs(control_values[0] - val) < tol

    # [1, 1, 1, ... ]
    phi = numpy.full(num_unknowns, 1.0, dtype=complex)
    val = numpy.vdot(phi, mesh.control_volumes * (J * phi)).real
    assert abs(control_values[1] - val) < tol

    # [i, i, i, ... ]
    phi = numpy.full(num_unknowns, 1j, dtype=complex)
    val = numpy.vdot(phi, mesh.control_volumes * (J * phi)).real
    assert abs(control_values[2] - val) < tol
    return
コード例 #12
0
    def __init__(self):
        a = 20.0
        points, cells = meshzoo.rectangle(-a / 2, a / 2, -a / 2, a / 2, 40, 40)
        self.mesh = meshplex.MeshTri(points, cells)
        self.A, _ = pyfvm.get_fvm_matrix(self.mesh, [Poisson()])

        # k = 1
        # ka = 4.5
        # DD = 8
        # nu = np.sqrt(1 / DD)
        # kbcrit = np.sqrt(1 + ka * nu)

        self.a = 4.0
        self.d1 = 1.0
        self.d2 = 2.0
コード例 #13
0
    def jacobian(self, psi, mu):
        keo = pyfvm.get_fvm_matrix(self.mesh, edge_kernels=[Energy(mu)])
        cv = self.mesh.control_volumes

        def _apply_jacobian(phi):
            return (keo * phi) / cv + alpha * phi + beta * phi.conj()

        alpha = self.V + self.g * 2.0 * (psi.real ** 2 + psi.imag ** 2)
        beta = self.g * psi ** 2

        num_unknowns = len(self.mesh.points)
        return pykry.LinearOperator(
            (num_unknowns, num_unknowns),
            complex,
            dot=_apply_jacobian,
            dot_adj=_apply_jacobian,
        )
コード例 #14
0
    def f(self, psi, mu):
        keo = split_sparse_matrix(
            pyfvm.get_fvm_matrix(self.mesh, edge_kernels=[Energy(mu)]))
        cv = to_real(self.mesh.control_volumes)

        V = numpy.zeros(cv.shape[0])
        V[0::2] = self.V
        out = keo * psi + multiply(cv, multiply(psi, V + self.g * abs2(psi)))

        # Algebraically, The inner product of <f(psi), i*psi> is always 0. We project
        # out that component numerically to avoid convergence failure for the Jacobian
        # updates close to a solution. If this is not done, the Krylov method might hang
        # at something like 10^{-7}.
        i_psi = to_real(1j * to_complex(psi))
        out -= self.inner(i_psi, out) / self.inner(i_psi, i_psi) * i_psi

        return out
コード例 #15
0
def test_f(filename, control_values):
    filename = download_mesh(filename)
    mesh = meshplex.read(filename)

    mu = 1.0e-2
    V = -1.0
    g = 1.0

    keo = pyfvm.get_fvm_matrix(mesh, edge_kernels=[Energy(mu)])

    # compute the Ginzburg-Landau residual
    m2 = meshio.read(filename)
    psi = m2.point_data["psi"][:, 0] + 1j * m2.point_data["psi"][:, 1]
    cv = mesh.control_volumes
    # One divides by the control volumes here. No idea why this has been done in pynosh.
    # Perhaps to make sure that even the small control volumes have a significant
    # contribution to the residual?
    r = keo * psi / cv + psi * (V + g * abs(psi)**2)

    # scale with D for compliance with the Nosh (C++) tests
    if mesh.control_volumes is None:
        mesh.compute_control_volumes()
    r *= mesh.control_volumes

    tol = 1.0e-13
    # For C++ Nosh compatibility:
    # Compute 1-norm of vector (Re(psi[0]), Im(psi[0]), Re(psi[1]), ... )
    alpha = numpy.linalg.norm(r.real, ord=1) + numpy.linalg.norm(r.imag, ord=1)
    assert abs(control_values[0] - alpha) < tol
    assert abs(control_values[1] - numpy.linalg.norm(r, ord=2)) < tol
    # For C++ Nosh compatibility:
    # Compute inf-norm of vector (Re(psi[0]), Im(psi[0]), Re(psi[1]), ... )
    alpha = max(
        numpy.linalg.norm(r.real, ord=numpy.inf),
        numpy.linalg.norm(r.imag, ord=numpy.inf),
    )
    assert abs(control_values[2] - alpha) < tol
    return
コード例 #16
0
ファイル: test_ginzburg_landau.py プロジェクト: nschloe/pyfvm
def test_f(filename, control_values):
    filename = download_mesh(filename)
    mesh, point_data, field_data, _ = meshplex.read(filename)

    mu = 1.0e-2
    V = -1.0
    g = 1.0

    keo = pyfvm.get_fvm_matrix(mesh, edge_kernels=[Energy(mu)])

    # compute the Ginzburg-Landau residual
    psi = point_data["psi"][:, 0] + 1j * point_data["psi"][:, 1]
    cv = mesh.control_volumes
    # One divides by the control volumes here. No idea why this has been done in pynosh.
    # Perhaps to make sure that even the small control volumes have a significant
    # contribution to the residual?
    r = keo * psi / cv + psi * (V + g * abs(psi) ** 2)

    # scale with D for compliance with the Nosh (C++) tests
    if mesh.control_volumes is None:
        mesh.compute_control_volumes()
    r *= mesh.control_volumes

    tol = 1.0e-13
    # For C++ Nosh compatibility:
    # Compute 1-norm of vector (Re(psi[0]), Im(psi[0]), Re(psi[1]), ... )
    alpha = numpy.linalg.norm(r.real, ord=1) + numpy.linalg.norm(r.imag, ord=1)
    assert abs(control_values[0] - alpha) < tol
    assert abs(control_values[1] - numpy.linalg.norm(r, ord=2)) < tol
    # For C++ Nosh compatibility:
    # Compute inf-norm of vector (Re(psi[0]), Im(psi[0]), Re(psi[1]), ... )
    alpha = max(
        numpy.linalg.norm(r.real, ord=numpy.inf),
        numpy.linalg.norm(r.imag, ord=numpy.inf),
    )
    assert abs(control_values[2] - alpha) < tol
    return
コード例 #17
0
    def jacobian_solver(self, psi, mu, rhs):
        keo = pyfvm.get_fvm_matrix(self.mesh, edge_kernels=[Energy(mu)])
        cv = self.mesh.control_volumes

        def prec_inv(psi):
            prec = keo.copy()
            # Add diagonal to avoid singularity for mu = 0. Also, this is a better
            # preconditioner.
            diag = prec.diagonal()
            diag += self.g * 2.0 * (psi.real ** 2 + psi.imag ** 2) * cv
            prec.setdiag(diag)
            return prec

        def prec(psi):
            p = prec_inv(psi)

            def _apply(phi):
                # ml = pyamg.smoothed_aggregation_solver(p, phi)
                # out = ml.solve(b=phi, tol=1e-12)
                out = spsolve(p, phi)
                return out

            num_unknowns = len(self.mesh.points)
            return pykry.LinearOperator(
                (num_unknowns, num_unknowns), complex, dot=_apply, dot_adj=_apply
            )

        jac = self.jacobian(psi, mu)
        out = pykry.gmres(
            A=jac,
            b=rhs,
            M=prec(psi),
            inner_product=self.inner,
            maxiter=100,
            tol=1.0e-12,
            # Minv=prec_inv(psi),
            # U=1j * psi,
        )
        # print("Krylov iterations:", out.iter)
        # print("Krylov residual:", out.resnorms[-1])
        # res = jac * out.xk - rhs
        # print("Krylov residual (explicit):", np.sqrt(self.norm2_r(res)))

        # self.ax1.semilogy(out.resnorms)
        # self.ax1.grid()
        # plt.show()

        # Since
        #
        #     (J_psi) psi = K psi + (-1 +2|psi|^2) psi - psi^2 conj(psi)
        #                 = K psi - psi + psi |psi|^2
        #                 = f(psi),
        #
        # we have (J_psi)(i psi) = i f(psi). The RHS is typically f(psi) or
        # df/dlmbda(psi), but obviously
        #
        #     <f(psi), (J_psi)(i psi)> = <f(psi), i f(psi)> = 0,
        #
        # so the i*psi-component in the solution plays no role if the rhs is f(psi).
        # Using 0 as a starting guess for Krylov, the solution will have no component in
        # the i*psi-direction. This means that the Newton updates won't jump around the
        # solution manifold. It wouldn't matter if they did, though.
        # TODO show this for df/dlmbda as well
        # i_psi = 1j * psi
        # out.xk -= self.inner(i_psi, out.xk) / self.inner(i_psi, i_psi) * i_psi
        # print("solution component i*psi", self.inner(i_psi, out.xk) / np.sqrt(self.inner(i_psi, i_psi)))
        return out.xk
コード例 #18
0
def test():
    mu = 5.0e-2
    V = -1.0
    g = 1.0

    class Energy(object):
        """Specification of the kinetic energy operator.
        """

        def __init__(self):
            self.magnetic_field = mu * numpy.array([0.0, 0.0, 1.0])
            self.subdomains = [None]
            return

        def eval(self, mesh, cell_mask):
            nec = mesh.idx_hierarchy[..., cell_mask]
            X = mesh.node_coords[nec]

            edge_midpoint = 0.5 * (X[0] + X[1])
            edge = X[1] - X[0]
            edge_ce_ratio = mesh.ce_ratios[..., cell_mask]

            # project the magnetic potential on the edge at the midpoint
            magnetic_potential = 0.5 * numpy.cross(self.magnetic_field, edge_midpoint)

            # The dot product <magnetic_potential, edge>, executed for many
            # points at once; cf. <http://stackoverflow.com/a/26168677/353337>.
            beta = numpy.einsum("...k,...k->...", magnetic_potential, edge)

            return numpy.array(
                [
                    [edge_ce_ratio, -edge_ce_ratio * numpy.exp(-1j * beta)],
                    [-edge_ce_ratio * numpy.exp(1j * beta), edge_ce_ratio],
                ]
            )

    vertices, cells = meshzoo.rectangle(-5.0, 5.0, -5.0, 5.0, 51, 51)
    mesh = meshplex.MeshTri(vertices, cells)

    keo = pyfvm.get_fvm_matrix(mesh, edge_kernels=[Energy()])

    def f(psi):
        cv = mesh.control_volumes
        return keo * psi + cv * psi * (V + g * abs(psi) ** 2)

    def jacobian(psi):
        def _apply_jacobian(phi):
            cv = mesh.control_volumes
            y = keo * phi + cv * alpha * phi + cv * gPsi0Squared * phi.conj()
            return y

        alpha = V + g * 2.0 * (psi.real ** 2 + psi.imag ** 2)
        gPsi0Squared = g * psi ** 2

        num_unknowns = len(mesh.node_coords)
        return pykry.LinearOperator(
            (num_unknowns, num_unknowns),
            complex,
            dot=_apply_jacobian,
            dot_adj=_apply_jacobian,
        )

    def jacobian_solver(psi0, rhs):
        jac = jacobian(psi0)
        out = pykry.gmres(
            A=jac,
            b=rhs,
            inner_product=lambda a, b: numpy.dot(a.T.conj(), b).real,
            maxiter=1000,
            tol=1.0e-10,
        )
        return out.xk

    u0 = numpy.ones(len(vertices), dtype=complex)
    u = pyfvm.newton(f, jacobian_solver, u0)

    mesh.write("out.vtk", point_data={"u": u.view("(2,)float")})
    return