示例#1
0
 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
示例#2
0
    def jacobian_solver(self, psi, mu, rhs):
        def _apply_jacobian(phi):
            out = ((0.5 * self.A * phi) / self.mesh.control_volumes +
                   (self.V - mu + 2.0 *
                    (psi.real**2 + psi.imag**2)) * phi + psi**2 * phi.conj())
            # out[self.mesh.is_boundary_node] = 1.0
            return out

        n = len(self.mesh.points)
        jac = pykry.LinearOperator((n, n),
                                   complex,
                                   dot=_apply_jacobian,
                                   dot_adj=_apply_jacobian)

        def prec(psi):
            def _apply(phi):
                prec = 0.5 * self.A
                diag = prec.diagonal()
                cv = self.mesh.control_volumes
                diag += (self.V + 2.0 * (psi.real**2 + psi.imag**2)) * cv
                prec.setdiag(diag)
                # TODO pyamg solve
                out = spsolve(prec, phi)
                return out

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

        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,
        )
        return out.xk
    def jacobian_solver(self, psi, mu, rhs):
        abs_psi2 = numpy.zeros(psi.shape[0])
        abs_psi2[0::2] += psi[0::2]**2 + psi[1::2]**2
        cv = to_real(self.mesh.control_volumes)

        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()

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

            def _apply(phi):
                out = spsolve(p, phi)
                return out

            num_unknowns = len(self.mesh.node_coords)
            return pykry.LinearOperator((2 * num_unknowns, 2 * num_unknowns),
                                        float,
                                        dot=_apply,
                                        dot_adj=_apply)

        jac = self.jacobian(psi, mu)

        # Cannot use direct solve since jacobian is always singular
        # return spsolve(jac, rhs)

        out = pykry.gmres(
            A=jac,
            b=rhs,
            # TODO enable preconditioner
            # M=prec(psi),
            inner_product=self.inner,
            maxiter=100,
            tol=1.0e-12,
        )
        return out.xk
示例#4
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