Exemple #1
0
    def solve(self, mesh, num=5):
        """ Solve for num eigenvalues based on the mesh. """
        # conforming elements
        V = FunctionSpace(mesh, "CG", self.degree)
        u = TrialFunction(V)
        v = TestFunction(V)

        # weak formulation
        a = inner(grad(u), grad(v)) * dx
        b = u * v * ds
        A = PETScMatrix()
        B = PETScMatrix()
        A = assemble(a, tensor=A)
        B = assemble(b, tensor=B)

        # find eigenvalues
        eigensolver = SLEPcEigenSolver(A, B)
        eigensolver.parameters["spectral_transform"] = "shift-and-invert"
        eigensolver.parameters["problem_type"] = "gen_hermitian"
        eigensolver.parameters["spectrum"] = "smallest real"
        eigensolver.parameters["spectral_shift"] = 1.0E-10
        eigensolver.solve(num + 1)

        # extract solutions
        lst = [
            eigensolver.get_eigenpair(i)
            for i in range(1, eigensolver.get_number_converged())
        ]
        for k in range(len(lst)):
            u = Function(V)
            u.vector()[:] = lst[k][2]
            lst[k] = (lst[k][0], u)  # pair (eigenvalue,eigenfunction)
        return np.array(lst)
Exemple #2
0
 def setup_solver(self):
     shift = (2.0*pi*self.eigenmode_guess)**2
     self.esolver = SLEPcEigenSolver(self._A, self._B) 
     self.esolver.parameters["solver"] = "krylov-schur"
     self.esolver.parameters["tolerance"] = 1e-12
     self.esolver.parameters["spectral_transform"] = "shift-and-invert"
     self.esolver.parameters["spectral_shift"] = shift
     self.esolver.parameters["spectrum"] = "target magnitude"
Exemple #3
0
    def solve(self, mesh, num=5):
        """ Solve for num eigenvalues based on the mesh. """
        # conforming elements
        V = FunctionSpace(mesh, "CG", self.degree)
        u = TrialFunction(V)
        v = TestFunction(V)

        # weak formulation
        a = inner(grad(u), grad(v)) * dx
        b = u * v * ds
        A = PETScMatrix()
        B = PETScMatrix()
        A = assemble(a, tensor=A)
        B = assemble(b, tensor=B)

        # find eigenvalues
        eigensolver = SLEPcEigenSolver(A, B)
        eigensolver.parameters["spectral_transform"] = "shift-and-invert"
        eigensolver.parameters["problem_type"] = "gen_hermitian"
        eigensolver.parameters["spectrum"] = "smallest real"
        eigensolver.parameters["spectral_shift"] = 1.0E-10
        eigensolver.solve(num + 1)

        # extract solutions
        lst = [
            eigensolver.get_eigenpair(i) for i in range(
                1,
                eigensolver.get_number_converged())]
        for k in range(len(lst)):
            u = Function(V)
            u.vector()[:] = lst[k][2]
            lst[k] = (lst[k][0], u)  # pair (eigenvalue,eigenfunction)
        return np.array(lst)
Exemple #4
0
 def __init__(self, V, A, B=None, bcs=None):
     self.V = V
     if bcs is not None:
         self._set_boundary_conditions(bcs)
     A = self._assemble_if_form(A)
     if B is not None:
         B = self._assemble_if_form(B)
     self._set_operators(A, B)
     if self.B is not None:
         self.eigen_solver = SLEPcEigenSolver(self.condensed_A,
                                              self.condensed_B)
     else:
         self.eigen_solver = SLEPcEigenSolver(self.condensed_A)
Exemple #5
0
 def __init__(self, mesh, materials):
     """ init class always require mesh and materials to
     build the weak form """
     self.mesh = mesh
     self.materials = materials #FIXME throw error if not all domains are initilized
     self.eigenmode_guess = 1.0
     self.n_modes = 10 # number of modes to solve for      
     self.plot_eigenmodes = True
     self._A = PETScMatrix()
     self._B = PETScMatrix()	
     self.esolver = SLEPcEigenSolver(self._A, self._B)
Exemple #6
0
 def _assemble(self):
     # Get input:
     self.gamma = self.Parameters['gamma']
     if self.Parameters.has_key('beta'): self.beta = self.Parameters['beta']
     else: self.beta = 0.0
     self.Vm = self.Parameters['Vm']
     if self.Parameters.has_key('m0'):
         self.m0 = self.Parameters['m0'].copy(deepcopy=True)
         isFunction(self.m0)
     else:
         self.m0 = Function(self.Vm)
     self.mtrial = TrialFunction(self.Vm)
     self.mtest = TestFunction(self.Vm)
     self.mysample = Function(self.Vm)
     self.draw = Function(self.Vm)
     # Assemble:
     self.R = assemble(inner(nabla_grad(self.mtrial), \
     nabla_grad(self.mtest))*dx)
     self.M = PETScMatrix()
     assemble(inner(self.mtrial, self.mtest) * dx, tensor=self.M)
     # preconditioner is Gamma^{-1}:
     if self.beta > 1e-16:
         self.precond = self.gamma * self.R + self.beta * self.M
     else:
         self.precond = self.gamma * self.R + (1e-14) * self.M
     # Discrete operator K:
     self.K = self.gamma * self.R + self.beta * self.M
     # Get eigenvalues for M:
     self.eigsolM = SLEPcEigenSolver(self.M)
     self.eigsolM.solve()
     # Solver for M^{-1}:
     self.solverM = LUSolver()
     self.solverM.parameters['reuse_factorization'] = True
     self.solverM.parameters['symmetric'] = True
     self.solverM.set_operator(self.M)
     # Solver for K^{-1}:
     self.solverK = LUSolver()
     self.solverK.parameters['reuse_factorization'] = True
     self.solverK.parameters['symmetric'] = True
     self.solverK.set_operator(self.K)
def evaluate_evp(basis):
    """Evaluate EVP"""
    assert HAVE_SLEPC
    # get FEniCS function space
    V = basis._fefs

    # Define basis and bilinear form
    u = TrialFunction(V)
    v = TestFunction(V)
    a = inner(nabla_grad(u), nabla_grad(v)) * dx

    # Assemble stiffness form
    A = PETScMatrix()
    assemble(a, tensor=A)

    # Create eigensolver
    eigensolver = SLEPcEigenSolver(A)

    # Compute all eigenvalues of A x = \lambda x
    print "Computing eigenvalues..."
    eigensolver.solve()
    return eigensolver
Exemple #8
0
def slepc_solver(A, M, is_hermitian):
    '''Smallest eigenvalue'''
    #TODO Set this up with preconditioners!!
    solver = SLEPcEigenSolver(A, M)
    solver.parameters['spectrum'] = 'smallest magnitude'

    if is_hermitian:
        solver.parameters['problem_type'] = 'gen_hermitian'
    else:
        raise NotImplementedError

    solver.solve(3)

    eigw = [solver.get_eigenpair(i)[0]
            for i in range(solver.get_number_converged())]

    return eigw
Exemple #9
0
 def _assemble(self):
     # Get input:
     self.gamma = self.Parameters['gamma']
     if self.Parameters.has_key('beta'): self.beta = self.Parameters['beta']
     else:   self.beta = 0.0
     self.Vm = self.Parameters['Vm']
     if self.Parameters.has_key('m0'):   
         self.m0 = self.Parameters['m0'].copy(deepcopy=True)
         isFunction(self.m0)
     else:   self.m0 = Function(self.Vm)
     self.mtrial = TrialFunction(self.Vm)
     self.mtest = TestFunction(self.Vm)
     self.mysample = Function(self.Vm)
     self.draw = Function(self.Vm)
     # Assemble:
     self.R = assemble(inner(nabla_grad(self.mtrial), \
     nabla_grad(self.mtest))*dx)
     self.M = PETScMatrix()
     assemble(inner(self.mtrial, self.mtest)*dx, tensor=self.M)
     # preconditioner is Gamma^{-1}:
     if self.beta > 1e-16: self.precond = self.gamma*self.R + self.beta*self.M
     else:   self.precond = self.gamma*self.R + (1e-14)*self.M
     # Discrete operator K:
     self.K = self.gamma*self.R + self.beta*self.M
     # Get eigenvalues for M:
     self.eigsolM = SLEPcEigenSolver(self.M)
     self.eigsolM.solve()
     # Solver for M^{-1}:
     self.solverM = LUSolver()
     self.solverM.parameters['reuse_factorization'] = True
     self.solverM.parameters['symmetric'] = True
     self.solverM.set_operator(self.M)
     # Solver for K^{-1}:
     self.solverK = LUSolver()
     self.solverK.parameters['reuse_factorization'] = True
     self.solverK.parameters['symmetric'] = True
     self.solverK.set_operator(self.K)
Exemple #10
0
def compute_eig(M, filename, parameters=[]):
    """ Compute eigenvalues of a PETScMatrix M,
    and print to filename """
    mpirank = MPI.rank(M.mpi_comm())

    if mpirank == 0:    print '\t\tCompute eigenvalues'
    eigsolver = SLEPcEigenSolver(M)
    eigsolver.parameters.update(parameters)
    eigsolver.solve()

    if mpirank == 0:    
        print '\t\tSort eigenvalues'
        eig = []
        for ii in range(eigsolver.get_number_converged()):
            eig.append(eigsolver.get_eigenvalue(ii)[0])
        eig.sort()

        print '\t\tPrint results to file'
        np.savetxt(filename, np.array(eig))
Exemple #11
0
    def solve(self):
        """ Find eigenvalues for transformed mesh. """
        self.progress("Building mesh.")
        # build transformed mesh
        mesh = self.refineMesh()
        # dim = mesh.topology().dim()
        if self.bcLast:
            mesh = transform_mesh(mesh, self.transformList)
            Robin, Steklov, shift, bcs = get_bc_parts(mesh, self.bcList)
        else:
            Robin, Steklov, shift, bcs = get_bc_parts(mesh, self.bcList)
            mesh = transform_mesh(mesh, self.transformList)
            # boundary conditions computed on non-transformed mesh
            # copy the values to transformed mesh
            fun = FacetFunction("size_t", mesh, shift)
            fun.array()[:] = bcs.array()[:]
            bcs = fun
        ds = Measure('ds', domain=mesh, subdomain_data=bcs)
        V = FunctionSpace(mesh, self.method, self.deg)
        u = TrialFunction(V)
        v = TestFunction(V)
        self.progress("Assembling matrices.")
        wTop = Expression(self.wTop)
        wBottom = Expression(self.wBottom)

        #
        # build stiffness matrix form
        #
        s = dot(grad(u), grad(v)) * wTop * dx
        # add Robin parts
        for bc in Robin:
            s += Constant(bc.parValue) * u * v * wTop * ds(bc.value + shift)

        #
        # build mass matrix form
        #
        if len(Steklov) > 0:
            m = 0
            for bc in Steklov:
                m += Constant(
                    bc.parValue) * u * v * wBottom * ds(bc.value + shift)
        else:
            m = u * v * wBottom * dx

        # assemble
        # if USE_EIGEN:
        #     S, M = EigenMatrix(), EigenMatrix()
        # tempv = EigenVector()
        # else:
        S, M = PETScMatrix(), PETScMatrix()
        # tempv = PETScVector()

        if not np.any(bcs.array() == shift + 1):
            # no Dirichlet parts
            assemble(s, tensor=S)
            assemble(m, tensor=M)
        else:
            #
            # with EIGEN we could
            #   apply Dirichlet condition symmetrically
            #   completely remove rows and columns
            #
            # Dirichlet parts are marked with shift+1
            #
            # temp = Constant(0)*v*dx
            bc = DirichletBC(V, Constant(0.0), bcs, shift + 1)
            # assemble_system(s, temp, bc, A_tensor=S, b_tensor=tempv)
            # assemble_system(m, temp, bc, A_tensor=M, b_tensor=tempv)
            assemble(s, tensor=S)
            bc.apply(S)
            assemble(m, tensor=M)
            # bc.zero(M)

        # if USE_EIGEN:
        #    M = M.sparray()
        #    M.eliminate_zeros()
        #    print M.shape
        #    indices = M.indptr[:-1] - M.indptr[1:] < 0
        #    M = M[indices, :].tocsc()[:, indices]
        #    S = S.sparray()[indices, :].tocsc()[:, indices]
        #    print M.shape
        #
        # solve the eigenvalue problem
        #
        self.progress("Solving eigenvalue problem.")
        eigensolver = SLEPcEigenSolver(S, M)
        eigensolver.parameters["problem_type"] = "gen_hermitian"
        eigensolver.parameters["solver"] = "krylov-schur"
        if self.target is not None:
            eigensolver.parameters["spectrum"] = "target real"
            eigensolver.parameters["spectral_shift"] = self.target
        else:
            eigensolver.parameters["spectrum"] = "smallest magnitude"
            eigensolver.parameters["spectral_shift"] = -0.01
        eigensolver.parameters["spectral_transform"] = "shift-and-invert"
        eigensolver.solve(self.number)
        self.progress("Generating eigenfunctions.")
        if eigensolver.get_number_converged() == 0:
            return None
        eigf = []
        eigv = []
        if self.deg > 1:
            mesh = refine(mesh)
        W = FunctionSpace(mesh, 'CG', 1)
        for i in range(eigensolver.get_number_converged()):
            pair = eigensolver.get_eigenpair(i)[::2]
            eigv.append(pair[0])
            u = Function(V)
            u.vector()[:] = pair[1]
            eigf.append(interpolate(u, W))
        return eigv, eigf
Exemple #12
0
class EigenSolver(AbstractEigenSolver):
    def __init__(self, V, A, B=None, bcs=None):
        self.V = V
        if bcs is not None:
            self._set_boundary_conditions(bcs)
        A = self._assemble_if_form(A)
        if B is not None:
            B = self._assemble_if_form(B)
        self._set_operators(A, B)
        if self.B is not None:
            self.eigen_solver = SLEPcEigenSolver(self.condensed_A,
                                                 self.condensed_B)
        else:
            self.eigen_solver = SLEPcEigenSolver(self.condensed_A)

    @staticmethod
    @overload
    def _assemble_if_form(mat: Form):
        return assemble(mat, keep_diagonal=True)

    @staticmethod
    @overload
    def _assemble_if_form(mat: ParametrizedTensorFactory):
        return evaluate(mat)

    @staticmethod
    @overload
    def _assemble_if_form(mat: Matrix.Type()):
        return mat

    def _set_boundary_conditions(self, bcs):
        # List all local and constrained local dofs
        local_dofs = set()
        constrained_local_dofs = set()
        for bc in bcs:
            dofmap = bc.function_space().dofmap()
            local_range = dofmap.ownership_range()
            local_dofs.update(list(range(local_range[0], local_range[1])))
            constrained_local_dofs.update([
                dofmap.local_to_global_index(local_dof_index)
                for local_dof_index in bc.get_boundary_values().keys()
            ])

        # List all unconstrained dofs
        unconstrained_local_dofs = local_dofs.difference(
            constrained_local_dofs)
        unconstrained_local_dofs = list(unconstrained_local_dofs)

        # Generate IS accordingly
        comm = bcs[0].function_space().mesh().mpi_comm()
        for bc in bcs:
            assert comm == bc.function_space().mesh().mpi_comm()
        self._is = PETSc.IS().createGeneral(unconstrained_local_dofs, comm)

    def _set_operators(self, A, B):
        if hasattr(self, "_is"):  # there were Dirichlet BCs
            (self.A, self.condensed_A) = self._condense_matrix(A)
            if B is not None:
                (self.B, self.condensed_B) = self._condense_matrix(B)
            else:
                (self.B, self.condensed_B) = (None, None)
        else:
            (self.A, self.condensed_A) = (as_backend_type(A),
                                          as_backend_type(A))
            if B is not None:
                (self.B, self.condensed_B) = (as_backend_type(B),
                                              as_backend_type(B))
            else:
                (self.B, self.condensed_B) = (None, None)

    def _condense_matrix(self, mat):
        mat = as_backend_type(mat)

        petsc_version = PETSc.Sys().getVersionInfo()
        if petsc_version["major"] == 3 and petsc_version["minor"] <= 7:
            condensed_mat = mat.mat().getSubMatrix(self._is, self._is)
        else:
            condensed_mat = mat.mat().createSubMatrix(self._is, self._is)

        return mat, PETScMatrix(condensed_mat)

    def set_parameters(self, parameters):
        self.eigen_solver.parameters.update(parameters)

    def solve(self, n_eigs=None):
        assert n_eigs is not None
        self.eigen_solver.solve(n_eigs)

    def get_eigenvalue(self, i):
        return self.eigen_solver.get_eigenvalue(i)

    def get_eigenvector(self, i):
        # Helper functions
        if has_pybind11():
            cpp_code = """
                #include <pybind11/pybind11.h>
                #include <dolfin/la/PETScVector.h>
                #include <dolfin/la/SLEPcEigenSolver.h>
                
                PetscInt get_converged(std::shared_ptr<dolfin::SLEPcEigenSolver> eigen_solver)
                {
                    PetscInt num_computed_eigenvalues;
                    EPSGetConverged(eigen_solver->eps(), &num_computed_eigenvalues);
                    return num_computed_eigenvalues;
                }
                
                void get_eigen_pair(std::shared_ptr<dolfin::SLEPcEigenSolver> eigen_solver, std::size_t i, std::shared_ptr<dolfin::PETScVector> condensed_real_vector, std::shared_ptr<dolfin::PETScVector> condensed_imag_vector)
                {
                    const PetscInt ii = static_cast<PetscInt>(i);
                    double real_value;
                    double imag_value;
                    EPSGetEigenpair(eigen_solver->eps(), ii, &real_value, &imag_value, condensed_real_vector->vec(), condensed_imag_vector->vec());
                }
                
                PYBIND11_MODULE(SIGNATURE, m)
                {
                    m.def("get_converged", &get_converged);
                    m.def("get_eigen_pair", &get_eigen_pair);
                }
            """

            cpp_module = compile_cpp_code(cpp_code)
            get_converged = cpp_module.get_converged
            get_eigen_pair = cpp_module.get_eigen_pair
        else:

            def get_converged(eigen_solver):
                return eigen_solver.eps().getConverged()

            def get_eigen_pair(eigen_solver, i, condensed_real_vector,
                               condensed_imag_vector):
                eigen_solver.eps().getEigenpair(i, condensed_real_vector.vec(),
                                                condensed_imag_vector.vec())

        # Get number of computed eigenvectors/values
        num_computed_eigenvalues = get_converged(self.eigen_solver)

        if (i < num_computed_eigenvalues):
            # Initialize eigenvectors
            real_vector = PETScVector()
            imag_vector = PETScVector()
            self.A.init_vector(real_vector, 0)
            self.A.init_vector(imag_vector, 0)

            # Condense input vectors
            if hasattr(self, "_is"):  # there were Dirichlet BCs
                condensed_real_vector = PETScVector(
                    real_vector.vec().getSubVector(self._is))
                condensed_imag_vector = PETScVector(
                    imag_vector.vec().getSubVector(self._is))
            else:
                condensed_real_vector = real_vector
                condensed_imag_vector = imag_vector

            # Get eigenpairs
            get_eigen_pair(self.eigen_solver, i, condensed_real_vector,
                           condensed_imag_vector)

            # Restore input vectors
            if hasattr(self, "_is"):  # there were Dirichlet BCs
                real_vector.vec().restoreSubVector(self._is,
                                                   condensed_real_vector.vec())
                imag_vector.vec().restoreSubVector(self._is,
                                                   condensed_imag_vector.vec())

            # Return as Function
            return (Function(self.V,
                             real_vector), Function(self.V, imag_vector))
        else:
            raise RuntimeError("Requested eigenpair has not been computed")
Exemple #13
0
class BilaplacianPrior(GaussianPrior):
    """Gaussian prior
    Parameters must be a dictionary containing:
        gamma = multiplicative factor applied to <Grad u, Grad v> term
        beta = multiplicative factor applied to <u,v> term (default=0.0)
        m0 = mean (or reference parameter when used as regularization)
        Vm = function space for parameter
    cost = 1/2 * (m-m0)^T.R.(m-m0)"""
    def _assemble(self):
        # Get input:
        self.gamma = self.Parameters['gamma']
        if self.Parameters.has_key('beta'): self.beta = self.Parameters['beta']
        else:   self.beta = 0.0
        self.Vm = self.Parameters['Vm']
        if self.Parameters.has_key('m0'):   
            self.m0 = self.Parameters['m0'].copy(deepcopy=True)
            isFunction(self.m0)
        else:   self.m0 = Function(self.Vm)
        self.mtrial = TrialFunction(self.Vm)
        self.mtest = TestFunction(self.Vm)
        self.mysample = Function(self.Vm)
        self.draw = Function(self.Vm)
        # Assemble:
        self.R = assemble(inner(nabla_grad(self.mtrial), \
        nabla_grad(self.mtest))*dx)
        self.M = PETScMatrix()
        assemble(inner(self.mtrial, self.mtest)*dx, tensor=self.M)
        # preconditioner is Gamma^{-1}:
        if self.beta > 1e-16: self.precond = self.gamma*self.R + self.beta*self.M
        else:   self.precond = self.gamma*self.R + (1e-14)*self.M
        # Discrete operator K:
        self.K = self.gamma*self.R + self.beta*self.M
        # Get eigenvalues for M:
        self.eigsolM = SLEPcEigenSolver(self.M)
        self.eigsolM.solve()
        # Solver for M^{-1}:
        self.solverM = LUSolver()
        self.solverM.parameters['reuse_factorization'] = True
        self.solverM.parameters['symmetric'] = True
        self.solverM.set_operator(self.M)
        # Solver for K^{-1}:
        self.solverK = LUSolver()
        self.solverK.parameters['reuse_factorization'] = True
        self.solverK.parameters['symmetric'] = True
        self.solverK.set_operator(self.K)

    def Minvpriordot(self, vect):
        """Here M.Gamma^{-1} = K M^{-1} K"""
        mhat = Function(self.Vm)
        self.solverM.solve(mhat.vector(), self.K*vect)
        return self.K * mhat.vector()

    def apply_sqrtM(self, vect):
        """Compute M^{1/2}.vect from Vector() vect"""
        sqrtMv = Function(self.Vm)
        for ii in range(self.Vm.dim()):
            r, c, rx, cx = self.eigsolM.get_eigenpair(ii)
            RX = Vector(rx)
            sqrtMv.vector().axpy(np.sqrt(r)*np.dot(rx.array(), vect.array()), RX)
        return sqrtMv.vector()

    def Ldot(self, vect):   
        """Here L = K^{-1} M^{1/2}"""
        Lb = Function(self.Vm)
        self.solverK.solve(Lb.vector(), self.apply_sqrtM(vect))
        return Lb.vector()
Exemple #14
0
class ELSolver(ModeSolver):
    """ fully tensorial elastic mode solver  """

    def __init__(self,mesh,materials):
        super(ELSolver, self).__init__(mesh, materials)
        self.q_b = 0.0
        self.lagrange_order = 2
        self._VComplex = None

    def assemble_matrices(self):
        V = VectorElement("Lagrange", self.mesh.ufl_cell(),
                          self.lagrange_order, dim = 3)
        self._VComplex = FunctionSpace(self.mesh, V*V)
        u = TrialFunction(self._VComplex)
        (ur, ui) = split(u)
        v = TestFunction(self._VComplex)
        (vr, vi) = split(v)

        A_ij = None
        B_ij = None

        # construct matrices for each domain
        if not isinstance(self.materials, collections.Iterable):
            material = self.materials
            C = as_matrix(material.el.C)
            rho = material.el.rho
            DX  = material.domain
            A_ij = LHS(self.q_b, C, ur, ui, vr, vi, DX)
            B_ij = RHS(rho, ur, ui, vr, vi, DX)


        else:
            counter = 0 # a work around for summing forms
            for material in self.materials:
                C = as_matrix(material.el.C)
                rho = material.el.rho
                DX  = material.domain
                
                if counter == 0:
                    A_ij = LHS(self.q_b, C, ur, ui, vr, vi, DX)
                    B_ij = RHS(rho, ur, ui, vr, vi, DX)
                    counter += 1
                else:
                    a_ij = LHS(self.q_b, C, ur, ui, vr, vi, DX)
                    b_ij = RHS(rho, ur, ui, vr, vi, DX)

                    A_ij += a_ij
                    B_ij += b_ij


        # assemble the matrices
        assemble(A_ij, tensor=self._A)
        assemble(B_ij, tensor=self._B)

    def setup_solver(self):
        shift = (2.0*pi*self.eigenmode_guess)**2
        self.esolver = SLEPcEigenSolver(self._A, self._B) 
        self.esolver.parameters["solver"] = "krylov-schur"
        self.esolver.parameters["tolerance"] = 1e-12
        self.esolver.parameters["spectral_transform"] = "shift-and-invert"
        self.esolver.parameters["spectral_shift"] = shift
        self.esolver.parameters["spectrum"] = "target magnitude"


    def set_clamped_walls(self):
        bcs = build_clamped_walls(self._VComplex)
        bcs.apply(self._A)
        bcs.apply(self._B)

    def set_free_walls(self):
        # this is the natural BC when no changes are made
        # to the assembled matrices
        pass
    
    
    def calculate_power(self, eigenvalue_index):
        
        r, c, rx, cx = self.esolver.get_eigenpair(eigenvalue_index)
        u = Function(self._VComplex, rx)
        omega_sqrd = r*(1e9)**2

         # construct matrices for each domain
        if not isinstance(self.materials, collections.Iterable):
            material = self.materials
            rho = material.el.rho
            DX  = material.domain
            norm = assemble(dot(u, rho*u)*DX)
            p = 0.5*omega_sqrd*norm
            return p
           

        else:
            p = 0.0
            for material in self.materials:
                rho = material.el.rho
                DX  = material.domain
                norm = assemble(dot(u, rho*u)*DX)
                p +=  0.5*omega_sqrd*norm
            return p


    def compute_eigenvalues(self):
        self.esolver.solve(self.n_modes)
        if self.esolver.get_number_converged()==0:
            print( 'Eigensolver did not calculate eigenmodes. Increase log level')
        for i in range(0,self.esolver.get_number_converged(),1):
            r, c = self.esolver.get_eigenvalue(i)
            try:
                f_b = (r)**0.5/(2*pi)
                print('Frequency {} GHz'.format(f_b))

                if self.plot_eigenmodes == True:
                    # TODO save plots to a folder
                    r, c, xr, xi = self.esolver.get_eigenpair(i)
                    f = Function(self._VComplex, xr)
                    plot_displacement(self.mesh, f)
            except:
                print("Found negative frequency")

    def extract_field(self, eigenvalue_index):
         r, c, xr, xi = self.esolver.get_eigenpair(eigenvalue_index)
         f = Function(self._VComplex, xr)
         f_b = (r)**0.5/(2*pi)
         return (f, f_b)
Exemple #15
0
def standard_solver(K, M):
    solver = SLEPcEigenSolver(K, M)
    solver.parameters['spectrum'] = 'smallest magnitude'
    solver.parameters['tolerance'] = 1e-4
    solver.parameters['problem_type'] = 'pos_gen_non_hermitian'
    return solver
Exemple #16
0
class BilaplacianPrior(GaussianPrior):
    """Gaussian prior
    Parameters must be a dictionary containing:
        gamma = multiplicative factor applied to <Grad u, Grad v> term
        beta = multiplicative factor applied to <u,v> term (default=0.0)
        m0 = mean (or reference parameter when used as regularization)
        Vm = function space for parameter
    cost = 1/2 * (m-m0)^T.R.(m-m0)"""
    def _assemble(self):
        # Get input:
        self.gamma = self.Parameters['gamma']
        if self.Parameters.has_key('beta'): self.beta = self.Parameters['beta']
        else: self.beta = 0.0
        self.Vm = self.Parameters['Vm']
        if self.Parameters.has_key('m0'):
            self.m0 = self.Parameters['m0'].copy(deepcopy=True)
            isFunction(self.m0)
        else:
            self.m0 = Function(self.Vm)
        self.mtrial = TrialFunction(self.Vm)
        self.mtest = TestFunction(self.Vm)
        self.mysample = Function(self.Vm)
        self.draw = Function(self.Vm)
        # Assemble:
        self.R = assemble(inner(nabla_grad(self.mtrial), \
        nabla_grad(self.mtest))*dx)
        self.M = PETScMatrix()
        assemble(inner(self.mtrial, self.mtest) * dx, tensor=self.M)
        # preconditioner is Gamma^{-1}:
        if self.beta > 1e-16:
            self.precond = self.gamma * self.R + self.beta * self.M
        else:
            self.precond = self.gamma * self.R + (1e-14) * self.M
        # Discrete operator K:
        self.K = self.gamma * self.R + self.beta * self.M
        # Get eigenvalues for M:
        self.eigsolM = SLEPcEigenSolver(self.M)
        self.eigsolM.solve()
        # Solver for M^{-1}:
        self.solverM = LUSolver()
        self.solverM.parameters['reuse_factorization'] = True
        self.solverM.parameters['symmetric'] = True
        self.solverM.set_operator(self.M)
        # Solver for K^{-1}:
        self.solverK = LUSolver()
        self.solverK.parameters['reuse_factorization'] = True
        self.solverK.parameters['symmetric'] = True
        self.solverK.set_operator(self.K)

    def Minvpriordot(self, vect):
        """Here M.Gamma^{-1} = K M^{-1} K"""
        mhat = Function(self.Vm)
        self.solverM.solve(mhat.vector(), self.K * vect)
        return self.K * mhat.vector()

    def apply_sqrtM(self, vect):
        """Compute M^{1/2}.vect from Vector() vect"""
        sqrtMv = Function(self.Vm)
        for ii in range(self.Vm.dim()):
            r, c, rx, cx = self.eigsolM.get_eigenpair(ii)
            RX = Vector(rx)
            sqrtMv.vector().axpy(
                np.sqrt(r) * np.dot(rx.array(), vect.array()), RX)
        return sqrtMv.vector()

    def Ldot(self, vect):
        """Here L = K^{-1} M^{1/2}"""
        Lb = Function(self.Vm)
        self.solverK.solve(Lb.vector(), self.apply_sqrtM(vect))
        return Lb.vector()
Exemple #17
0
    def solve(self):
        """ Find eigenvalues for transformed mesh. """
        self.progress("Building mesh.")
        # build transformed mesh
        mesh = self.refineMesh()
        # dim = mesh.topology().dim()
        if self.bcLast:
            mesh = transform_mesh(mesh, self.transformList)
            Robin, Steklov, shift, bcs = get_bc_parts(mesh, self.bcList)
        else:
            Robin, Steklov, shift, bcs = get_bc_parts(mesh, self.bcList)
            mesh = transform_mesh(mesh, self.transformList)
            # boundary conditions computed on non-transformed mesh
            # copy the values to transformed mesh
            fun = FacetFunction("size_t", mesh, shift)
            fun.array()[:] = bcs.array()[:]
            bcs = fun
        ds = Measure('ds', domain=mesh, subdomain_data=bcs)
        V = FunctionSpace(mesh, self.method, self.deg)
        u = TrialFunction(V)
        v = TestFunction(V)
        self.progress("Assembling matrices.")
        wTop = Expression(self.wTop, degree=self.deg)
        wBottom = Expression(self.wBottom, degree=self.deg)

        #
        # build stiffness matrix form
        #
        s = dot(grad(u), grad(v))*wTop*dx
        # add Robin parts
        for bc in Robin:
            s += Constant(bc.parValue)*u*v*wTop*ds(bc.value+shift)

        #
        # build mass matrix form
        #
        if len(Steklov) > 0:
            m = 0
            for bc in Steklov:
                m += Constant(bc.parValue)*u*v*wBottom*ds(bc.value+shift)
        else:
            m = u*v*wBottom*dx

        # assemble
        # if USE_EIGEN:
        #     S, M = EigenMatrix(), EigenMatrix()
            # tempv = EigenVector()
        # else:
        S, M = PETScMatrix(), PETScMatrix()
        # tempv = PETScVector()

        if not np.any(bcs.array() == shift+1):
            # no Dirichlet parts
            assemble(s, tensor=S)
            assemble(m, tensor=M)
        else:
            #
            # with EIGEN we could
            #   apply Dirichlet condition symmetrically
            #   completely remove rows and columns
            #
            # Dirichlet parts are marked with shift+1
            #
            # temp = Constant(0)*v*dx
            bc = DirichletBC(V, Constant(0.0), bcs, shift+1)
            # assemble_system(s, temp, bc, A_tensor=S, b_tensor=tempv)
            # assemble_system(m, temp, bc, A_tensor=M, b_tensor=tempv)
            assemble(s, tensor=S)
            bc.apply(S)
            assemble(m, tensor=M)
            # bc.zero(M)

        # if USE_EIGEN:
        #    M = M.sparray()
        #    M.eliminate_zeros()
        #    print M.shape
        #    indices = M.indptr[:-1] - M.indptr[1:] < 0
        #    M = M[indices, :].tocsc()[:, indices]
        #    S = S.sparray()[indices, :].tocsc()[:, indices]
        #    print M.shape
        #
        # solve the eigenvalue problem
        #
        self.progress("Solving eigenvalue problem.")
        eigensolver = SLEPcEigenSolver(S, M)
        eigensolver.parameters["problem_type"] = "gen_hermitian"
        eigensolver.parameters["solver"] = "krylov-schur"
        if self.target is not None:
            eigensolver.parameters["spectrum"] = "target real"
            eigensolver.parameters["spectral_shift"] = self.target
        else:
            eigensolver.parameters["spectrum"] = "smallest magnitude"
            eigensolver.parameters["spectral_shift"] = -0.01
        eigensolver.parameters["spectral_transform"] = "shift-and-invert"
        eigensolver.solve(self.number)
        self.progress("Generating eigenfunctions.")
        if eigensolver.get_number_converged() == 0:
            return None
        eigf = []
        eigv = []
        if self.deg > 1:
            mesh = refine(mesh)
        W = FunctionSpace(mesh, 'CG', 1)
        for i in range(eigensolver.get_number_converged()):
            pair = eigensolver.get_eigenpair(i)[::2]
            eigv.append(pair[0])
            u = Function(V)
            u.vector()[:] = pair[1]
            eigf.append(interpolate(u, W))
        return eigv, eigf
Exemple #18
0
    def solve(self, n=None):
        """
        solve(n=None):

        Solve the eigenvalue problem and return the converged
        eigenvalues

        n indicates the number of eigenvalues to be calculated
        """

        # Standard eigenvalue problem
        if self.b is None:
            A = PETScMatrix()
            assemble(self.a, tensor=A)

            if self.bc:
                self.bc.apply(A)

            solver = SLEPcEigenSolver(A)
            solver.solve()

        # Generalized eigenvalue problem
        else:
            A = PETScMatrix()
            assemble(self.a, tensor=A)
            B = PETScMatrix()
            assemble(self.b, tensor=B)

            # Set options for eigensolver
            solver = SLEPcEigenSolver(A, B)
            for key, key_info in self.parameters.iterdata():
                solver.parameters[key] = self.parameters[key]

            if n is None:
                n = A.size(0)

            if self.bc:
                self.bc.apply(A)
                self.bc.apply(B)

            solver.solve(n)

        # Pick real part of eigenvalues computed
        m = solver.get_number_converged()

        complex_eps = 0.001
        eigenvalues = [solver.get_eigenvalue(i)[0] for i in range(m)
                       if abs(solver.get_eigenvalue(i)[1]) < complex_eps]

        if len(eigenvalues) == 0:
            raise RuntimeError("No real-valued eigenvalues found")

        # Compute all eigenvalues if eigenvalue is zero and not only
        # testing for stability
        if (n < A.size(0)
            and abs(eigenvalues[0]) < ascot_parameters["eps"]
            and not ascot_parameters["only_stable"]):

            info("Only zero eigenvalues detected. Computing all.")
            solver.solve(A.size(0))
            m = solver.get_number_converged()
            eigenvalues = [solver.get_eigenvalue(i)[0] for i in range(m)
                           if abs(solver.get_eigenvalue(i)[1]) < 0.1]

        return eigenvalues
Exemple #19
0
def project(expr, space):
    u, v = TrialFunction(space), TestFunction(space)
    a = inner(u, v)*dx
    L = inner(expr, v)*dx
    A, b = PETScMatrix(), PETScVector()
    assemble_system(a, L, A_tensor=A, b_tensor=b)

    uh = Function(space)
    x = uh.vector()
    solve(A, x, b, 'lu')

    lmax = SLEPcEigenSolver(A)
    lmax.parameters["spectrum"] = "largest magnitude"
    lmax.parameters["problem_type"] = "hermitian"
    lmax.solve(2)
    lmax = max([lmax.get_eigenpair(i)[0] for i in range(lmax.get_number_converged())])

    lmin = SLEPcEigenSolver(A)
    lmin.parameters["spectrum"] = "smallest magnitude"
    lmin.parameters["problem_type"] = "hermitian"
    lmin.solve(2)
    lmin = max([lmin.get_eigenpair(i)[0] for i in range(lmin.get_number_converged())])

    print space.dim(), 'Cond number', lmax/lmin



    
    return uh
Exemple #20
0
class EigenSolver(AbstractEigenSolver):
    def __init__(self, V, A, B=None, bcs=None):
        self.V = V
        if bcs is not None:
            self._set_boundary_conditions(bcs)
        A = self._assemble_if_form(A)
        if B is not None:
            B = self._assemble_if_form(B)
        self._set_operators(A, B)
        if self.B is not None:
            self.eigen_solver = SLEPcEigenSolver(self.condensed_A,
                                                 self.condensed_B)
        else:
            self.eigen_solver = SLEPcEigenSolver(self.condensed_A)

    @staticmethod
    @overload
    def _assemble_if_form(mat: Form):
        return assemble(mat, keep_diagonal=True)

    @staticmethod
    @overload
    def _assemble_if_form(mat: ParametrizedTensorFactory):
        return evaluate(mat)

    @staticmethod
    @overload
    def _assemble_if_form(mat: Matrix.Type()):
        return mat

    def _set_boundary_conditions(self, bcs):
        # List all local and constrained local dofs
        local_dofs = set()
        constrained_local_dofs = set()
        for bc in bcs:
            dofmap = bc.function_space().dofmap()
            local_range = dofmap.ownership_range()
            local_dofs.update(list(range(local_range[0], local_range[1])))
            constrained_local_dofs.update([
                dofmap.local_to_global_index(local_dof_index)
                for local_dof_index in bc.get_boundary_values().keys()
            ])

        # List all unconstrained dofs
        unconstrained_local_dofs = local_dofs.difference(
            constrained_local_dofs)
        unconstrained_local_dofs = list(unconstrained_local_dofs)

        # Generate IS accordingly
        comm = bcs[0].function_space().mesh().mpi_comm()
        for bc in bcs:
            assert comm == bc.function_space().mesh().mpi_comm()
        self._is = PETSc.IS().createGeneral(unconstrained_local_dofs, comm)

    def _set_operators(self, A, B):
        if hasattr(self, "_is"):  # there were Dirichlet BCs
            (self.A, self.condensed_A) = self._condense_matrix(A)
            if B is not None:
                (self.B, self.condensed_B) = self._condense_matrix(B)
            else:
                (self.B, self.condensed_B) = (None, None)
        else:
            (self.A, self.condensed_A) = (as_backend_type(A),
                                          as_backend_type(A))
            if B is not None:
                (self.B, self.condensed_B) = (as_backend_type(B),
                                              as_backend_type(B))
            else:
                (self.B, self.condensed_B) = (None, None)

    def _condense_matrix(self, mat):
        mat = as_backend_type(mat)

        petsc_version = PETSc.Sys().getVersionInfo()
        if petsc_version["major"] == 3 and petsc_version["minor"] <= 7:
            condensed_mat = mat.mat().getSubMatrix(self._is, self._is)
        else:
            condensed_mat = mat.mat().createSubMatrix(self._is, self._is)

        return mat, PETScMatrix(condensed_mat)

    def set_parameters(self, parameters):
        # Helper functions
        cpp_code = """
            #include <pybind11/pybind11.h>
            #include <dolfin/la/PETScLUSolver.h> // defines PCFactorSetMatSolverType macro for PETSc <= 3.8
            #include <dolfin/la/SLEPcEigenSolver.h>
            
            void throw_error(PetscErrorCode ierr, std::string reason);
            
            void set_linear_solver(std::shared_ptr<dolfin::SLEPcEigenSolver> eigen_solver, std::string lu_method)
            {
                ST st;
                KSP ksp;
                PC pc;
                PetscErrorCode ierr;
                
                ierr = EPSGetST(eigen_solver->eps(), &st);
                if (ierr != 0) throw_error(ierr, "EPSGetST");
                ierr = STGetKSP(st, &ksp);
                if (ierr != 0) throw_error(ierr, "STGetKSP");
                ierr = KSPGetPC(ksp, &pc);
                if (ierr != 0) throw_error(ierr, "KSPGetPC");
                
                ierr = STSetType(st, STSINVERT);
                if (ierr != 0) throw_error(ierr, "STSetType");
                ierr = KSPSetType(ksp, KSPPREONLY);
                if (ierr != 0) throw_error(ierr, "KSPSetType");
                ierr = PCSetType(pc, PCLU);
                if (ierr != 0) throw_error(ierr, "PCSetType");
                
                ierr = PCFactorSetMatSolverType(pc, lu_method.c_str());
                if (ierr != 0) throw_error(ierr, "PCFactorSetMatSolverType");
            }
            
            void throw_error(PetscErrorCode ierr, std::string reason)
            {
                throw std::runtime_error("Error in set_linear_solver: reason " + reason + ", error code " + std::to_string(ierr));
            }
            
            PYBIND11_MODULE(SIGNATURE, m)
            {
                m.def("set_linear_solver", &set_linear_solver);
            }
        """

        cpp_module = compile_cpp_code(cpp_code)
        set_linear_solver = cpp_module.set_linear_solver

        if "spectral_transform" in parameters and parameters[
                "spectral_transform"] == "shift-and-invert":
            parameters["spectrum"] = "target real"
            if "linear_solver" in parameters:
                set_linear_solver(self.eigen_solver,
                                  parameters["linear_solver"])
                parameters.pop("linear_solver")
        self.eigen_solver.parameters.update(parameters)

    def solve(self, n_eigs=None):
        assert n_eigs is not None
        self.eigen_solver.solve(n_eigs)
        assert self.eigen_solver.get_number_converged() >= n_eigs

    def get_eigenvalue(self, i):
        assert i < self.eigen_solver.get_number_converged()
        return self.eigen_solver.get_eigenvalue(i)

    def get_eigenvector(self, i):
        assert i < self.eigen_solver.get_number_converged()

        # Initialize eigenvectors
        real_vector = PETScVector()
        imag_vector = PETScVector()
        self.A.init_vector(real_vector, 0)
        self.A.init_vector(imag_vector, 0)

        # Condense input vectors
        if hasattr(self, "_is"):  # there were Dirichlet BCs
            condensed_real_vector = PETScVector(real_vector.vec().getSubVector(
                self._is))
            condensed_imag_vector = PETScVector(imag_vector.vec().getSubVector(
                self._is))
        else:
            condensed_real_vector = real_vector
            condensed_imag_vector = imag_vector

        # Get eigenpairs
        if dolfin_version.startswith(
                "2018.1"):  # TODO remove when 2018.2.0 is released
            # Helper functions
            cpp_code = """
                #include <pybind11/pybind11.h>
                #include <dolfin/la/PETScVector.h>
                #include <dolfin/la/SLEPcEigenSolver.h>
                
                void get_eigen_pair(std::shared_ptr<dolfin::SLEPcEigenSolver> eigen_solver, std::shared_ptr<dolfin::PETScVector> condensed_real_vector, std::shared_ptr<dolfin::PETScVector> condensed_imag_vector, std::size_t i)
                {
                    const PetscInt ii = static_cast<PetscInt>(i);
                    double real_value;
                    double imag_value;
                    EPSGetEigenpair(eigen_solver->eps(), ii, &real_value, &imag_value, condensed_real_vector->vec(), condensed_imag_vector->vec());
                }
                
                PYBIND11_MODULE(SIGNATURE, m)
                {
                    m.def("get_eigen_pair", &get_eigen_pair);
                }
            """

            get_eigen_pair = compile_cpp_code(cpp_code).get_eigen_pair
            get_eigen_pair(self.eigen_solver, condensed_real_vector,
                           condensed_imag_vector, i)
        else:
            self.eigen_solver.get_eigenpair(condensed_real_vector,
                                            condensed_imag_vector, i)

        # Restore input vectors
        if hasattr(self, "_is"):  # there were Dirichlet BCs
            real_vector.vec().restoreSubVector(self._is,
                                               condensed_real_vector.vec())
            imag_vector.vec().restoreSubVector(self._is,
                                               condensed_imag_vector.vec())

        # Return as Function
        return (Function(self.V, real_vector), Function(self.V, imag_vector))
Exemple #21
0
class EMSolver(ModeSolver):
    """ electromagnetic mode solver """

    def __init__(self,mesh,materials,  wavelength):
        super(EMSolver, self).__init__(mesh, materials)   
        self.wavelength = wavelength
        self.mesh_unit = 1e-6
        self._combined_space = None
        self._finite_element = None
        self.nedelec_order = 1
        self.lagrange_order = 1
        self._k_o_squared = (2.0*pi/self.wavelength)**2

    def assemble_matrices(self):
        nedelec = FiniteElement( "Nedelec 1st kind H(curl)",
                                 self.mesh.ufl_cell(), self.nedelec_order)
        lagrange = FiniteElement( "Lagrange", self.mesh.ufl_cell(),
                                  self.lagrange_order)
        self._finite_element = nedelec*lagrange
        self._combined_space = FunctionSpace(self.mesh, nedelec*lagrange)
        # define the test and trial functions from the combined space

        (N_i, L_i) = TestFunctions(self._combined_space)
        (N_j, L_j) = TrialFunctions(self._combined_space)

        # construct matrices for each domain
        if not isinstance(self.materials, collections.Iterable):
            material = self.materials
            u_r = material.em.u_r
            e_r = material.em.e_r
            DX  = material.domain
            (A_ij, B_ij) = em_weak_form(N_i, N_j, L_i, L_j, u_r, e_r,
                                            self._k_o_squared,DX)

        else:
            counter = 0 # a work around for summing forms
            for material in self.materials:
                u_r = material.em.u_r
                e_r = material.em.e_r
                DX  = material.domain
                if counter == 0:
                    (A_ij, B_ij) = em_weak_form(N_i, N_j, L_i, L_j, u_r, e_r,
                                            self._k_o_squared, DX)
                    counter += 1
                else:
                    (a_ij, b_ij) = em_weak_form(N_i, N_j, L_i, L_j, u_r, e_r,
                                            self._k_o_squared, DX)
                    A_ij += a_ij
                    B_ij += b_ij

        # assemble the matrices
        assemble(A_ij, tensor=self._A)
        assemble(B_ij, tensor=self._B)


    def setup_solver(self):
        self.esolver= SLEPcEigenSolver(self._A, self._B) 
        shift = -(2.0*pi*self.eigenmode_guess/self.wavelength)**2
        self.esolver.parameters["solver"] = "krylov-schur"
        self.esolver.parameters["tolerance"] = 1e-12
        self.esolver.parameters["spectral_transform"] = "shift-and-invert"        
        self.esolver.parameters["spectrum"] = "target magnitude"
        self.esolver.parameters["spectral_shift"] = shift  


    def set_electric_walls(self):
        bcs = build_electric_walls(self._combined_space)
        bcs.apply(self._A)
        bcs.apply(self._B)

    def extract_normalized_field(self, eigenvalue_index):
        """ extract and rescale the E field from the solver  
            note that Ex, Ey, are real, Ez is imaginary """
        r, c, rx, cx = self.esolver.get_eigenpair(eigenvalue_index)
        e_raw = Function(self._combined_space, rx)
        n_eff = ((-r)**0.5)*self.wavelength/(2*pi)
        gamma = (abs(r))**0.5
        E = as_vector([e_raw[0], e_raw[1], gamma*e_raw[2]])
        return (E, n_eff)


    def calculate_power(self, eigenvalue_index, ng):
        """ 1. note the normalization of Ez in the equations
            2. assume u_r = 1 everywhere  """

        r, c, rx, cx = self.esolver.get_eigenpair(eigenvalue_index)
        f = Function(self._combined_space, rx)
        gamma_sqrd = abs(r)
        (Et, Ez) = split(f)        

         # construct matrices for each domain
        if not isinstance(self.materials, collections.Iterable):
            material = self.materials
            e_r = material.em.e_r
            DX  = material.domain

            int_t = assemble(dot(Et,Et)*DX)
            int_z = assemble(Ez*Ez*DX)*gamma_sqrd 
            power = 0.5*(c0/ng*eps0*e_r*(int_t+ int_z))
            return power

        else:
            power = 0.0
            for material in self.materials:
                e_r = material.em.e_r
                DX  = material.domain
                int_t = assemble(dot(Et,Et)*DX)
                int_z = assemble(Ez*Ez*DX)*gamma_sqrd 
                power += 0.5*(c0/ng*eps0*e_r*(int_t + int_z))
            return power


    def compute_eigenvalues(self):
        self.esolver.solve(self.n_modes)
        if self.esolver.get_number_converged()==0:
            print('Eigensolver did not converge')
        for i in range(0,self.esolver.get_number_converged(),1):
            r, c = self.esolver.get_eigenvalue(i)
            try:
                f_b = ((-r)**0.5)*self.wavelength/(2*pi)
                print('Effective index: {} '.format(f_b))
                if self.plot_eigenmodes == True:
                    # TODO save plots to a folder
                    r, c, xr, xi = self.esolver.get_eigenpair(i)
                    e_raw = Function(self._combined_space, xr)
                    plot_transverse_field(e_raw)
            except:
                print("Found negative frequency")