示例#1
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))
示例#2
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
示例#3
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)
示例#4
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))
示例#5
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")
示例#6
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")