Ejemplo n.º 1
0
opts.setValue("eps_target_magnitude", None)
opts.setValue("eps_target", 0.)
opts.setValue("eps_tol", 1e-13)
opts.setValue("st_ksp_max_it", 10000)
opts.setValue("st_ksp_rtol", 1e-8)

# opts.setValue("eps_gen_hermitian", None)
# opts.setValue("st_pc_factor_shift_type", "NONZERO")
# opts.setValue("eps_type", "krylovschur")
# opts.setValue("eps_smallest_real", None)
# opts.setValue("eps_tol", 1e-10)
# opts.setValue("eps_ncv", 40)

# Solve for eigenvalues
print('Computing eigenvalues...')
es = SLEPc.EPS().create().create(comm=SLEPc.COMM_WORLD)
es.setDimensions(num_eigenvalues)
es.setOperators(petsc_a, petsc_m)
es.setFromOptions()
print(es.getDimensions())

es.solve()

# Number of converged eigenvalues
nconv = es.getConverged()
eigvecs = []
eigvalues = []

for i in range(nconv):
    print(es.getEigenvalue(i).real)
    vr, vi = petsc_a.getVecs()
Ejemplo n.º 2
0
    def __init__(self, F_form: typing.List, u: typing.List, lmbda: dolfinx.Function,
                 A_form=None, B_form=None, prefix=None):
        """SLEPc problem and solver wrapper.

        Wrapper for a generalised eigenvalue problem obtained from UFL residual forms.

        Parameters
        ----------
        F_form
            Residual forms
        u
            Current solution vectors
        lmbda
            Eigenvalue function. Residual forms must be linear in lmbda for
            linear eigenvalue problems.
        A_form, optional
            Override automatically derived A
        B_form, optional
            Override automatically derived B

        Note
        ----
        In general, eigenvalue problems have form T(lmbda) * x = 0,
        where T(lmbda) is a matrix-valued function.
        Linear eigenvalue problems have T(lmbda) = A + lmbda * B, and if B is not identity matrix
        then this problem is called generalized (linear) eigenvalue problem.

        """
        self.F_form = F_form
        self.u = u
        self.lmbda = lmbda
        self.comm = u[0].function_space.mesh.mpi_comm()

        self.ur = []
        self.ui = []
        for func in u:
            self.ur.append(dolfinx.function.Function(func.function_space, name=func.name))
            self.ui.append(dolfinx.function.Function(func.function_space, name=func.name))

        # Prepare tangent form M0 which has terms involving lambda
        self.M0 = [[None for i in range(len(self.u))] for j in range(len(self.u))]
        for i in range(len(self.u)):
            for j in range(len(self.u)):
                self.M0[i][j] = ufl.algorithms.expand_derivatives(ufl.derivative(
                    F_form[i], self.u[j], ufl.TrialFunction(self.u[j].function_space)))

        if B_form is None:
            B0 = [[None for i in range(len(self.u))] for j in range(len(self.u))]

            for i in range(len(self.u)):
                for j in range(len(self.u)):
                    # Differentiate wrt. lambda and replace all remaining lambda with Zero
                    B0[i][j] = ufl.algorithms.expand_derivatives(ufl.diff(self.M0[i][j], lmbda))
                    B0[i][j] = ufl.replace(B0[i][j], {lmbda: ufl.zero()})

                    if B0[i][j].empty():
                        B0[i][j] = None

            self.B_form = B0
        else:
            self.B_form = B_form

        if A_form is None:
            A0 = [[None for i in range(len(self.u))] for j in range(len(self.u))]

            for i in range(len(self.u)):
                for j in range(len(self.u)):
                    A0[i][j] = ufl.replace(self.M0[i][j], {lmbda: ufl.zero()})

                    if A0[i][j].empty():
                        A0[i][j] = None
                        continue
            self.A_form = A0
        else:
            self.A_form = A_form

        self.eps = SLEPc.EPS().create(self.comm)
        self.eps.setOptionsPrefix(prefix)
        self.eps.setFromOptions()

        self.A = dolfinx.fem.create_matrix_block(self.A_form)

        self.B = None
        if not self.empty_B():
            self.B = dolfinx.fem.create_matrix_block(self.B_form)
Ejemplo n.º 3
0
for row in df.itertuples():
    _, i, j, wcCount = row
    wCount = counts[i]
    cCount = counts[j]
    ppmi = PPMI(wcCount, total, wCount, cCount, alpha=alpha)
    data.append(ppmi)
    rowIndex.append(i)
    columnIndex.append(j)

csr = csr_matrix((data, (rowIndex, columnIndex)), shape=(n, n))
print("Doing SVD")
print("PPMI[99,2]=", csr[99, 2])
A = PETSc.Mat().createAIJ(size=(n, n), csr=(csr.indptr, csr.indices, csr.data))
A.assemble()

svd = SLEPc.SVD()
svd.create()

svd.setOperator(A)
svd.setType(svd.Type.TRLANCZOS)
svd.setDimensions(nsv=50, ncv=100)
svd.setFromOptions()
svd.solve()

iterations = svd.getIterationNumber()
nsv, ncv, mpd = svd.getDimensions()
nconv = svd.getConverged()
v, u = A.createVecs()

U = []
V = []
Ejemplo n.º 4
0
from petsc4py import PETSc
from slepc4py import SLEPc
from numpy import exp
from math import pi

Print = PETSc.Sys.Print

opts = PETSc.Options()
n = opts.getInt('n', 128)
tau = opts.getReal('tau', 0.001)
a = 20
h = pi/(n+1)

# Setup the solver
nep = SLEPc.NEP().create()

# Create problem matrices
#   Identity matrix
Id = PETSc.Mat().create()
Id.setSizes([n, n])
Id.setFromOptions()
Id.setUp()
Id.assemble()
Id.shift(1.0)
Id.setOption(PETSc.Mat.Option.HERMITIAN, True)
#   A = 1/h^2*tridiag(1,-2,1) + a*I
A = PETSc.Mat().create()
A.setSizes([n, n])
A.setFromOptions()
A.setUp()
Ejemplo n.º 5
0
def _init_eigensolver(k=6, which='LM', sigma=None, isherm=True, isgen=False,
                      EPSType=None, st_opts=None, tol=None, A_is_linop=False,
                      B_is_linop=False, maxiter=None, ncv=None, l_win=None,
                      comm=None):
    """Create an advanced eigensystem solver

    Parameters
    ----------
    sigma :
        Target eigenvalue.
    isherm :
        Whether problem is hermitian or not.

    Returns
    -------
        SLEPc solver ready to be called.
    """
    SLEPc, comm = get_slepc(comm=comm)

    eigensolver = SLEPc.EPS().create(comm=comm)

    if st_opts is None:
        st_opts = {}

    if l_win is not None:
        EPSType = {'ciss': 'ciss', None: 'ciss'}[EPSType]
        which = 'ALL'
        rg = eigensolver.getRG()
        rg.setType(SLEPc.RG.Type.INTERVAL)
        rg.setIntervalEndpoints(*l_win, -0.1, 0.1)
    else:
        eigensolver.setDimensions(k, ncv)

    internal = (sigma is not None) or (l_win is not None)

    # pick right backend
    if EPSType is None:
        if (isgen and B_is_linop) or (internal and A_is_linop):
            EPSType = 'gd'
        else:
            EPSType = 'krylovschur'

    # set some preconditioning defaults for 'gd' and 'lobpcg'
    if EPSType in ('gd', 'lobpcg', 'blopex', 'primme'):
        st_opts.setdefault('STType', 'precond')
        st_opts.setdefault('KSPType', 'preonly')
        st_opts.setdefault('PCType', 'none')

    # set some preconditioning defaults for 'jd'
    elif EPSType == 'jd':
        st_opts.setdefault('STType', 'precond')
        st_opts.setdefault('KSPType', 'bcgs')
        st_opts.setdefault('PCType', 'none')

    # set the spectral inverter / preconditioner.
    if st_opts or internal:
        st = _init_spectral_inverter(comm=comm, **st_opts)
        eigensolver.setST(st)

        # NB: `setTarget` must be called *after* `setST`.
        if sigma is not None:
            which = "TR"
            eigensolver.setTarget(sigma)

            if A_is_linop:
                st.setMatMode(SLEPc.ST.MatMode.SHELL)

    _EPS_PROB_TYPES = {
        (False, False): SLEPc.EPS.ProblemType.NHEP,
        (True, False): SLEPc.EPS.ProblemType.HEP,
        (False, True): SLEPc.EPS.ProblemType.GNHEP,
        (True, True): SLEPc.EPS.ProblemType.GHEP,
    }

    eigensolver.setType(EPSType)
    eigensolver.setProblemType(_EPS_PROB_TYPES[(isherm, isgen)])
    eigensolver.setWhichEigenpairs(_which_scipy_to_slepc(which))
    eigensolver.setConvergenceTest(SLEPc.EPS.Conv.REL)
    eigensolver.setTolerances(tol=tol, max_it=maxiter)
    eigensolver.setFromOptions()
    return eigensolver
Ejemplo n.º 6
0
    def solve_GenEO_eigmax(self, V0s, tauGenEO_eigmax):
        """
        Solves the local GenEO eigenvalue problem related to the largest eigenvalue eigmax. 

        Parameters
        ==========

        V0s : list of local PETSc .vecs
            V0s may already contain some local coarse vectors. This routine will possibly add more vectors to the list.

        tauGenEO_eigmax: Real.
            Threshold for selecting eigenvectors for the coarse space.

        """
        if tauGenEO_eigmax > 0:
            eps = SLEPc.EPS().create(comm=PETSc.COMM_SELF)
            eps.setDimensions(nev=self.nev)

            eps.setProblemType(SLEPc.EPS.ProblemType.GHIEP)
            eps.setOperators(self.Atildes, self.As)
            eps.setWhichEigenpairs(SLEPc.EPS.Which.TARGET_REAL)
            eps.setTarget(0.)
            if len(V0s) > 0:
                eps.setDeflationSpace(V0s)
            ST = eps.getST()
            ST.setType("sinvert")
            ST.setKSP(self.ksp_Atildes)
            eps.solve()
            if eps.getConverged() < self.nev:
                PETSc.Sys.Print(
                    'WARNING: Only {} eigenvalues converged for GenEO_eigmax in subdomain {} whereas {} were requested'
                    .format(eps.getConverged(), mpi.COMM_WORLD.rank, self.nev),
                    comm=self.comm)
            if abs(eps.getEigenvalue(eps.getConverged() -
                                     1)) < tauGenEO_eigmax:
                PETSc.Sys.Print(
                    'WARNING: The largest eigenvalue computed for GenEO_eigmax in subdomain {} is {} < the threshold which is {}. Consider setting PCBNN_GenEO_nev to something larger than {}'
                    .format(mpi.COMM_WORLD.rank,
                            eps.getEigenvalue(eps.getConverged() - 1),
                            tauGenEO_eigmax, eps.getConverged()),
                    comm=self.comm)

            for i in range(min(eps.getConverged(), self.maxev)):
                if (abs(eps.getEigenvalue(i)) < tauGenEO_eigmax
                    ):  #TODO tell slepc that the eigenvalues are real
                    V0s.append(self.works.duplicate())
                    eps.getEigenvector(i, V0s[-1])
                    if self.verbose:
                        PETSc.Sys.Print(
                            'GenEO eigenvalue number {} for lambdamax in subdomain {}: {}'
                            .format(i, mpi.COMM_WORLD.rank,
                                    eps.getEigenvalue(i)),
                            comm=self.comm)
                else:
                    if self.verbose:
                        PETSc.Sys.Print(
                            'GenEO eigenvalue number {} for lambdamax in subdomain {}: {} <-- not selected (> {})'
                            .format(i, mpi.COMM_WORLD.rank,
                                    eps.getEigenvalue(i), tauGenEO_eigmax),
                            comm=self.comm)

            self.eps_eigmax = eps  #TODO FIX the only reason for this line is to make sure self.ksp_Atildes and hence PCBNN.ksp is not destroyed
        if self.verbose:
            PETSc.Sys.Print(
                'Subdomain number {} contributes {} coarse vectors after first GenEO'
                .format(mpi.COMM_WORLD.rank, len(V0s)),
                comm=self.comm)
Ejemplo n.º 7
0
def DirectModeSLEPc(L, B, shift, nev):
    """
    Computes generalized eigenvectors and eigenvalues for the problem
    Lq = lambda Bq
    using SLEPc
    inputs : B,L, PETSc Mats
             shift, scalar (same on all procs). Shift parameter for 
               the shift-invert method
             nev, integer. Number of requested eigenvalues

    outputs: omega, complex array(nconv). Conputed eigenvalues
             modes, complex array(nconv,ndofs). Computed eigenvectors
             residual, real array(nconv). Actual residuals for each mode
    
    ALL OUTPUT ARE ONLY ON PROC 0 (=None on other procs)

    TO DO: compute left eigenvectors (adjoint problem)
    """

    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()

    ev = L.getVecRight()
    Lq = ev.duplicate()
    Bq = ev.duplicate()

    ndof = ev.getSize()

    # Setup EPS
    Print("  - Setting up the EPS and the ST")
    SI = SLEPc.ST().create()
    SI.setType(SLEPc.ST.Type.SINVERT)
    SI.setOperators(L, B)
    SI.setShift(shift)
    SI.setFromOptions()

    S = SLEPc.EPS()
    S.create(comm)
    S.setTarget(shift)
    S.setWhichEigenpairs(SLEPc.EPS.Which.TARGET_MAGNITUDE)
    S.setST(SI)
    S.setDimensions(nev=nev, ncv=60)
    S.setTolerances(tol=tol_ev, max_it=100)
    S.setFromOptions()

    # Solve the EVP
    Print("  - Solving the EPS")
    S.solve()

    its = S.getIterationNumber()
    nconv = S.getConverged()

    if rank == 0:
        residual = zeros(nconv)
        omega = zeros(nconv, 'complex')
        modes = zeros([ndof, nconv], 'complex')
    else:
        residual = None
        omega = None
        modes = None

    for i in range(nconv):
        eigval = S.getEigenpair(i, ev)
        L.mult(ev, Lq)
        B.mult(ev, Bq)
        Bq.aypx(-eigval, Lq)
        res = Bq.norm() / ev.norm()
        v = Vec2DOF(ev)

        if rank == 0:
            omega[i] = eigval / (-1j)
            modes[:, i] = v
            residual[i] = res

    return omega, modes, residual
Ejemplo n.º 8
0
v = TestFunction(V)
# Following Ritz (1909)
nu = Constant(0.225)
a = (inner(u.dx(0).dx(0),
           v.dx(0).dx(0)) + inner(u.dx(1).dx(1),
                                  v.dx(1).dx(1)) + nu *
     (inner(u.dx(1).dx(1),
            v.dx(0).dx(0)) + inner(u.dx(0).dx(0),
                                   v.dx(1).dx(1))) + 2 *
     (1 - nu) * inner(u.dx(0).dx(1),
                      v.dx(0).dx(1))) * dx
mss = inner(u, v) * dx
# This prefix allows us to control factorisation package from options.
A = assemble(a, options_prefix="st_").M.handle
M = assemble(mss, options_prefix="st_").M.handle
E = SLEPc.EPS().create(comm=msh.comm)
E.setOperators(A, M)
E.setProblemType(SLEPc.EPS.ProblemType.GHEP)
# Defaults  -eps_nev 5 -eps_tol 1e-11 -eps_target 10 -st_type sinvert
E.setTolerances(tol=1e-11)
E.setTarget(10)
E.setDimensions(nev=10)
E.st.setType(SLEPc.ST.Type.SINVERT)
E.setFromOptions()
E.solve()
Print = PETSc.Sys.Print
Print()
Print("******************************")
Print("*** SLEPc Solution Results ***")
Print("******************************")
Print()
Ejemplo n.º 9
0
def test_curl_curl_eigenvalue(family, order):
    """curl curl eigenvalue problem.

    Solved using H(curl)-conforming finite element method.
    See https://www-users.cse.umn.edu/~arnold/papers/icm2002.pdf for details.
    """
    slepc4py = pytest.importorskip("slepc4py")  # noqa: F841
    from slepc4py import SLEPc

    mesh = create_rectangle(
        MPI.COMM_WORLD,
        [np.array([0.0, 0.0]), np.array([np.pi, np.pi])], [24, 24],
        CellType.triangle)

    element = ufl.FiniteElement(family, ufl.triangle, order)
    V = FunctionSpace(mesh, element)

    u = ufl.TrialFunction(V)
    v = ufl.TestFunction(V)

    a = inner(ufl.curl(u), ufl.curl(v)) * dx
    b = inner(u, v) * dx

    boundary_facets = locate_entities_boundary(
        mesh, mesh.topology.dim - 1,
        lambda x: np.full(x.shape[1], True, dtype=bool))
    boundary_dofs = locate_dofs_topological(V, mesh.topology.dim - 1,
                                            boundary_facets)

    zero_u = Function(V)
    zero_u.x.array[:] = 0.0
    bcs = [dirichletbc(zero_u, boundary_dofs)]

    a, b = form(a), form(b)

    A = assemble_matrix(a, bcs=bcs)
    A.assemble()

    B = assemble_matrix(b, bcs=bcs, diagonal=0.01)
    B.assemble()

    eps = SLEPc.EPS().create()
    eps.setOperators(A, B)
    PETSc.Options()["eps_type"] = "krylovschur"
    PETSc.Options()["eps_gen_hermitian"] = ""
    PETSc.Options()["eps_target_magnitude"] = ""
    PETSc.Options()["eps_target"] = 5.0
    PETSc.Options()["eps_view"] = ""
    PETSc.Options()["eps_nev"] = 12
    eps.setFromOptions()
    eps.solve()

    num_converged = eps.getConverged()
    eigenvalues_unsorted = np.zeros(num_converged, dtype=np.complex128)

    for i in range(0, num_converged):
        eigenvalues_unsorted[i] = eps.getEigenvalue(i)

    assert np.isclose(np.imag(eigenvalues_unsorted), 0.0).all()
    eigenvalues_sorted = np.sort(np.real(eigenvalues_unsorted))[:-1]
    eigenvalues_sorted = eigenvalues_sorted[np.logical_not(
        eigenvalues_sorted < 1E-8)]

    eigenvalues_exact = np.array([1.0, 1.0, 2.0, 4.0, 4.0, 5.0, 5.0, 8.0, 9.0])
    assert np.isclose(eigenvalues_sorted[0:eigenvalues_exact.shape[0]],
                      eigenvalues_exact,
                      rtol=1E-2).all()
Ejemplo n.º 10
0
a = dot(grad(u), grad(v))*dx
m = u*v*dx

print V.dim()

# Assemble the stiffness matrix and the mass matrix.
A = assemble(a)
M = assemble(m)
A = as_backend_type(A).mat()
M = as_backend_type(M).mat()

from slepc4py import SLEPc
from petsc4py import PETSc

# Setup the eigensolver
solver = SLEPc.EPS().create()
solver.setOperators(A, M)
solver.setType(solver.Type.KRYLOVSCHUR)
solver.setDimensions(3, PETSc.DECIDE)
solver.setWhichEigenpairs(solver.Which.SMALLEST_REAL)
solver.setTolerances(1E-8, 1000)

solver.solve()

nconv = solver.getConverged()
niters = solver.getIterationNumber()
if MPI.rank(mesh.mpi_comm()) == 0:
    print "Number of eigenvalues successfully computed: ", nconv
    print "Iterations used", niters

eigenvalues = []
Ejemplo n.º 11
0
    def solve_GenEO_eigmin(self, rbm_vecs, tauGenEO_eigmin):
        """
        Solves the local GenEO eigenvalue problem related to the smallest eigenvalue eigmin. 

        Parameters
        ==========

        rbm_vecs : list of local PETSc .vecs
            rbm_vecs may already contain some local coarse vectors. This routine will possibly add more vectors to the list.

        tauGenEO_eigmin: Real.
            Threshold for selecting eigenvectors for the coarse space.

        """
        if tauGenEO_eigmin > 0:
            #to compute the smallest eigenvalues of the preconditioned matrix, A_scaled must be factorized
            tempksp = PETSc.KSP().create(comm=PETSc.COMM_SELF)
            tempksp.setOperators(self.A_scaled)
            tempksp.setType('preonly')
            temppc = tempksp.getPC()
            temppc.setType('cholesky')
            temppc.setFactorSolverType('mumps')
            temppc.setFactorSetUpSolverType()
            tempF = temppc.getFactorMatrix()
            tempF.setMumpsIcntl(7, 2)
            tempF.setMumpsIcntl(24, 1)
            tempF.setMumpsCntl(3, self.mumpsCntl3)
            temppc.setUp()
            tempnrb = tempF.getMumpsInfog(28)

            for i in range(tempnrb):
                tempF.setMumpsIcntl(25, i+1)
                self.workl.set(0.)
                tempksp.solve(self.workl, self.workl)
                rbm_vecs.append(self.workl.copy())
            
            tempF.setMumpsIcntl(25, 0)
            if self.verbose:
                PETSc.Sys.Print('Subdomain number {} contributes {} coarse vectors as zero energy modes of the scaled local operator (in GenEO for eigmin)'.format(mpi.COMM_WORLD.rank, tempnrb), comm=self.comm)

            #Eigenvalue Problem for smallest eigenvalues
            eps = SLEPc.EPS().create(comm=PETSc.COMM_SELF)
            eps.setDimensions(nev=self.nev)

            eps.setProblemType(SLEPc.EPS.ProblemType.GHIEP)
            eps.setOperators(self.A_scaled,self.Alocal)
            eps.setWhichEigenpairs(SLEPc.EPS.Which.TARGET_REAL)
            eps.setTarget(0.)
            ST = eps.getST()

            ST.setType("sinvert") 
            ST.setKSP(tempksp)

            if len(rbm_vecs) > 0 :
                eps.setDeflationSpace(rbm_vecs)
            eps.solve()
            if eps.getConverged() < self.nev:
                PETSc.Sys.Print('WARNING: Only {} eigenvalues converged for GenEO_eigmin in subdomain {} whereas {} were requested'.format(eps.getConverged(), mpi.COMM_WORLD.rank, self.nev), comm=self.comm)
            for i in range(min(eps.getConverged(),self.maxev)):
                if(abs(eps.getEigenvalue(i))<tauGenEO_eigmin): #TODO tell slepc that the eigenvalues are real
                   rbm_vecs.append(self.workl.duplicate())
                   eps.getEigenvector(i,rbm_vecs[-1])
                   if self.verbose:
                       PETSc.Sys.Print('GenEO eigenvalue number {} for lambdamin in subdomain {}: {}'.format(i, mpi.COMM_WORLD.rank, eps.getEigenvalue(i)), comm=self.comm)
                else:
                    if self.verbose:
                        PETSc.Sys.Print('GenEO eigenvalue number {} for lambdamin in subdomain {}: {} <-- not selected (> {})'.format(i, mpi.COMM_WORLD.rank, eps.getEigenvalue(i), tauGenEO_eigmin), comm=self.comm)
            self.eps_eigmin=eps #the only reason for this line is to make sure self.ksp and hence PCBNN.ksp is not destroyed  
Ejemplo n.º 12
0
def getEigenvalues(func, args, N=64, EigvType="All"):

    import sys, slepc4py
    slepc4py.init(sys.argv)

    from petsc4py import PETSc
    from slepc4py import SLEPc
    import numpy as np

    # Equation
    class A(object):
        def __init__(self):
            pass

        def mult(self, A, x, y):
            y[...] = func(x[...], args)

    context = A()
    A = PETSc.Mat().createPython((N, N), context)
    A.setUp()
    """
            def setupBMatrix():
                B = PETSc.Mat(dtype=complex); B.create()
                B.setSizes([N,N])
                B.setFromOptions()
                for n in range(N):
                    for m in range(N):
                        if m == n : B[n,m] =  - eps *  2. * omega[n]
                        else      : B[n,m] = 0.
                B.assemble()
                return B

            B = setupBMatrix() 
        """

    S = SLEPc.EPS().create()

    S.setOperators(A)
    #S.setOperators(A,B)
    S.setFromOptions()
    A.setFromOptions()
    S.setProblemType(SLEPc.EPS.ProblemType.NHEP)
    S.setBalance()
    S.setDimensions(N)

    #F1 = PETSc.Vec().createSeq(Nv)
    #F1.setValues(range(Nv), getInitialF1(ky))
    #S.setInitialSpace(F1)

    S.setTolerances(tol=1.e-15, max_it=500000)

    S.solve()

    its = S.getIterationNumber()
    sol_type = S.getType()
    nev, ncv, mpd = S.getDimensions()
    tol, maxit = S.getTolerances()
    nconv = S.getConverged()

    print("Number of converged eigenpairs: %d" % nconv)

    eigval = []
    eigvec = []

    if nconv > 0:
        ### (1) Get All eigenvalues ###
        xr, tmp = A.getVecs()
        xi, tmp = A.getVecs()
        for i in range(nconv):
            k = S.getEigenpair(i, xr, xi)
            error = S.computeRelativeError(i)
            #print(" %9f%+9f j  %12g" % (k.real, k.imag, error))
            eigval.append(k.real + k.imag * 1.j)
            eigvec.append(xr[...] + 1.j * xi[...])

    return np.array(eigval), np.array(eigvec)
Ejemplo n.º 13
0
def eigendecompose(space,
                   A_action,
                   *,
                   B_action=None,
                   N_eigenvalues=None,
                   solver_type=None,
                   problem_type=None,
                   which=None,
                   tolerance=1.0e-12,
                   configure=None):
    # First written 2018-03-01
    """
    Matrix-free interface with SLEPc via slepc4py, loosely following
    the slepc4py 3.6.0 demo demo/ex3.py, for use in the calculation of a
    Hessian eigendecomposition with a real control space.

    Arguments:

    space          Eigenvector space.
    A_action       Callable accepting a function and returning a function or
                   NumPy array, defining the complex conjugate of the action
                   of the left-hand-side matrix, e.g. as returned by
                   Hessian.action_fn.
    B_action       (Optional) Callable accepting a function and returning a
                   function or NumPy array, defining the complex conjugate of
                   the action of the right-hand-side matrix.
    N_eigenvalues  (Optional) Number of eigenvalues to attempt to find.
                   Defaults to a full spectrum.
    solver_type    (Optional) The solver type.
    problem_type   (Optional) The problem type. If not supplied
                   slepc4py.SLEPc.EPS.ProblemType.NHEP or
                   slepc4py.SLEPc.EPS.ProblemType.GNHEP are used.
    which          (Optional) Which eigenvalues to find. Defaults to
                   slepc4py.SLEPc.EPS.Which.LARGEST_MAGNITUDE.
    tolerance      (Optional) Tolerance, using slepc4py.SLEPc.EPS.Conv.REL
                   convergence criterion.
    configure      (Optional) Function handle accepting the EPS. Can be used
                   for manual configuration.

    Returns:

    A tuple (lam, V), where lam is an array of eigenvalues. For Hermitian
    problems or with complex PETSc V is a tuple of functions containing
    corresponding eigenvectors. Otherwise V is a tuple (V_r, V_i) where V_r and
    V_i are each tuples of functions containing the real and imaginary parts of
    corresponding eigenvectors.
    """

    import petsc4py.PETSc as PETSc
    import slepc4py.SLEPc as SLEPc

    A_action = wrapped_action(space, A_action)
    if B_action is not None:
        B_action = wrapped_action(space, B_action)

    if problem_type is None:
        if B_action is None:
            problem_type = SLEPc.EPS.ProblemType.NHEP
        else:
            problem_type = SLEPc.EPS.ProblemType.GNHEP
    if which is None:
        which = SLEPc.EPS.Which.LARGEST_MAGNITUDE

    X = space_new(space)
    n, N = function_local_size(X), function_global_size(X)
    del X
    N_ev = N if N_eigenvalues is None else N_eigenvalues

    comm = space_comm(space)  # .Dup()

    A_matrix = PETSc.Mat().createPython(((n, N), (n, N)),
                                        PythonMatrix(A_action),
                                        comm=comm)
    A_matrix.setUp()

    if B_action is None:
        B_matrix = None
    else:
        B_matrix = PETSc.Mat().createPython(((n, N), (n, N)),
                                            PythonMatrix(B_action),
                                            comm=comm)
        B_matrix.setUp()

    esolver = SLEPc.EPS().create(comm=comm)
    if solver_type is not None:
        esolver.setType(solver_type)
    esolver.setProblemType(problem_type)
    if B_matrix is None:
        esolver.setOperators(A_matrix)
    else:
        esolver.setOperators(A_matrix, B_matrix)
    esolver.setWhichEigenpairs(which)
    esolver.setDimensions(nev=N_ev, ncv=SLEPc.DECIDE, mpd=SLEPc.DECIDE)
    esolver.setConvergenceTest(SLEPc.EPS.Conv.REL)
    esolver.setTolerances(tol=tolerance, max_it=SLEPc.DECIDE)
    if configure is not None:
        configure(esolver)
    esolver.setUp()

    assert not _flagged_error[0]
    esolver.solve()
    if _flagged_error[0]:
        raise EigendecompositionException("Error encountered in "
                                          "SLEPc.EPS.solve")
    if esolver.getConverged() < N_ev:
        raise EigendecompositionException("Not all requested eigenpairs "
                                          "converged")

    lam = np.full(
        N_ev,
        np.NAN,
        dtype=PETSc.RealType if esolver.isHermitian() else PETSc.ComplexType)
    v_r = A_matrix.getVecRight()
    V_r = tuple(space_new(space) for n in range(N_ev))
    if issubclass(PETSc.ScalarType, (complex, np.complexfloating)):
        v_i = None
        V_i = None
    else:
        v_i = A_matrix.getVecRight()
        if esolver.isHermitian():
            V_i = None
        else:
            V_i = tuple(space_new(space) for n in range(N_ev))
    for i in range(lam.shape[0]):
        lam_i = esolver.getEigenpair(i, v_r, v_i)
        if esolver.isHermitian():
            assert lam_i.imag == 0.0
            lam[i] = lam_i.real
            if v_i is not None:
                with v_i as v_i_a:
                    assert abs(v_i_a).max() == 0.0
            # else:
            #     # Complex note: If v_i is None then v_r may be non-real
            #     pass
            with v_r as v_r_a:
                function_set_values(V_r[i], v_r_a)
        else:
            lam[i] = lam_i
            with v_r as v_r_a:
                function_set_values(V_r[i], v_r_a)
            if v_i is not None:
                with v_i as v_i_a:
                    function_set_values(V_i[i], v_i_a)

    # comm.Free()

    if V_i is None:
        return lam, V_r
    else:
        return lam, (V_r, V_i)
Ejemplo n.º 14
0
    def solve_eig(self):
        if self.solver == 'PETSc':

            import slepc4py
            import sys
            from petsc4py import PETSc
            from slepc4py import SLEPc

            opts = PETSc.Options()
            n = opts.getInt('n', self.N)

            A = PETSc.Mat().create()
            A.setSizes([n, n])
            A.setFromOptions()
            A.setUp()
            A = PETSc.Mat().createDense(size=self.A.shape, array=self.A)
            A.assemble()

            B = PETSc.Mat().create()
            B.setSizes([n, n])
            B.setFromOptions()
            B.setUp()
            B = PETSc.Mat().createDense(size=self.B.shape, array=self.B)
            B.assemble()

            E = SLEPc.EPS()
            E.create()
            E.setOperators(A, B)
            E.setProblemType(SLEPc.EPS.ProblemType.PGNHEP)
            E.setFromOptions()
            E.solve()

            Print = PETSc.Sys.Print

            Print()
            Print("******************************")
            Print("*** SLEPc Solution Results ***")
            Print("******************************")
            Print()

            its = E.getIterationNumber()
            Print("Number of iterations of the method: %d" % its)

            eps_type = E.getType()
            Print("Solution method: %s" % eps_type)

            nev, ncv, mpd = E.getDimensions()
            Print("Number of requested eigenvalues: %d" % nev)

            tol, maxit = E.getTolerances()
            Print("Stopping condition: tol=%.4g, maxit=%d" % (tol, maxit))

            nconv = E.getConverged()
            Print("Number of converged eigenpairs %d" % nconv)

            vec_k = np.zeros(n) * (0 + 1j)
            vec_vr = np.zeros([n, n]) * (0 + 1j)
            vec_vi = np.zeros([n, n]) * (0 + 1j)

            if nconv > 0:
                # Create the results vectors
                vr, wr = A.getVecs()
                vi, wi = A.getVecs()
                #
                Print()
                Print("        k          ||Ax-kx||/||kx|| ")
                Print("----------------- ------------------")
                for i in range(nconv):
                    k = E.getEigenpair(i, vr, vi)
                    er = PETSc.Vec.getArray(vr)
                    ei = PETSc.Vec.getArray(vi)
                    vec_k[i] = k
                    vec_vr[i] = er
                    vec_vi[i] = ei

                    error = E.computeError(i)

                    if k.imag != 0.0:
                        Print(" %9f%+9f j %12g" % (k.real, k.imag, error))
                    else:
                        Print(" %12f      %12g" % (k.real, error))
                Print()

            self.eigv = vec_k
            self.eigf = vec_vr + vec_vi
        """ solve the eigenvalues problem with the LINPACK subrutines"""
        self.eigv, self.eigf = lin.eig(self.A, self.B)
        #self.eigv, self.eigf = lins.eigs(self.A, k=10, M=self.B, which='LI')
        # doesent work ARPACK problems with Arnoldi factorization

        # remove the infinite and nan eigenvectors, and their eigenfunctions
        selector = np.isfinite(self.eigv)
        self.eigv = self.eigv[selector]
        self.eigf = self.eigf[:, selector]
Ejemplo n.º 15
0
def get_null_space(A, npairs, comm=PETSc.COMM_WORLD):
    """
    Returns 'npairs' eigenpairs with eigenvalues close to 0. Uses shift-and-invert.
    Parameters:
    -----------
    A: scipy CSR matrix, or numpy array or PETSc mat 
    npairs : integer
        Number of eigenvalues/vectors to return
    comm: MPI communicator

    Returns:
    --------
    evals: 1D array of npairs, eigenvalues from largest to smallest
    evecs: 2D array of (n, npairs) where n is size of A matrix
    """
    matrixtype = str(type(A))
    if 'scipy' in matrixtype:
        n = A.shape[0]
        A = get_petsc_matrix(A, comm)
    elif 'petsc' in matrixtype:
        n = A.getSize()
    elif 'numpy' in matrixtype:
        A = csr_matrix(A)
        n = A.shape[0]
        A = get_petsc_matrix(A, comm)
    else:
        Print(
            'Matrix type {} is not compatible. Use scipy CSR or PETSc AIJ type.'
            .format(type(A)))
    mpisize = comm.size
    Print('Matrix size: {}'.format(n))
    eps = SLEPc.EPS()
    eps.create()
    eps.setOperators(A)
    eps.setProblemType(SLEPc.EPS.ProblemType.HEP)
    eps.setWhichEigenpairs(SLEPc.EPS.Which.TARGET_REAL)
    eps.setTarget(0.)
    eps.setDimensions(nev=npairs, ncv=SLEPc.DECIDE, mpd=SLEPc.DECIDE)
    st = eps.getST()
    ksp = st.getKSP()
    pc = ksp.getPC()
    pc.setType(PETSc.PC.Type.CHOLESKY)
    pc.setFactorShift(shift_type=A.FactorShiftType.POSITIVE_DEFINITE)
    pc.setFactorSolverPackage('mumps')
    st.setType(SLEPc.ST.Type.SINVERT)
    eps.setTolerances(tol=1.e-14)
    eps.setFromOptions()  #Use command line options
    eps.setUp()
    eps.solve()
    nconv = eps.getConverged()
    vr = A.getVecLeft()
    vi = A.getVecLeft()
    if nconv < npairs:
        Print("{} eigenvalues required, {} converged.".format(npairs, nconv))
        npairs = nconv
    evals = np.zeros(npairs)
    evecs = np.zeros((n, npairs))
    for i in range(npairs):
        k = eps.getEigenpair(i, vr, vi)
        if abs(k.imag) > 1.e-10:
            Print("Imaginary eigenvalue: {} + {}j".format(k.real, k.imag))
            Print("Error: {}".format(eps.computeError(i)))
        if mpisize > 1:
            evecs[:, i] = get_numpy_array(vr)
        else:
            evecs[:, i] = vr.getArray()
        evals[i] = k.real
    return evals, evecs
Ejemplo n.º 16
0
zero_tol = 1e-8
smallest_singular_values = smallest_singular_values[
    smallest_singular_values > zero_tol]
condition_number = largest_singular_values.max(
) / smallest_singular_values.min()

time_scipy = time.time() - time_begin_scipy

print(f'Is symmetric? {petsc_mat.isSymmetric(tol=1e-8)}')
print(f'nnz: {nnz}')
print(f'DoFs: {W.dim()}')
print(f'Condition Number (scipy): {condition_number}')

time_begin_slepc = time.time()

S = SLEPc.SVD()
S.create()
S.setOperator(petsc_mat)
S.setType(SLEPc.SVD.Type.LAPACK)
S.setWhichSingularTriplets(which=S.Which.LARGEST)
S.setFromOptions()
S.solve()

# Create the results vectors
vr, vi = petsc_mat.getVecs()
nconv = S.getConverged()
singular_values_list = list()
num_of_extreme_singular_values = 5
if nconv > 0:
    for i in range(num_of_extreme_singular_values):
        singular_value_low = S.getSingularTriplet(i, vr, vi)
Ejemplo n.º 17
0
def get_eigenpairs(A, npairs=8, largest=True, comm=PETSc.COMM_WORLD):
    """
    Parameters:
    -----------
    A: scipy CSR matrix, or numpy array or PETSc mat 
    npairs: int, number of eigenpairs required
    largest: boolean, True (False) if largest (smallest) magnitude eigenvalues are requried
    comm: MPI communicator
    Returns:
    --------
    evals: 1D array of npairs, eigenvalues from largest to smallest
    evecs: 2D array of (n, npairs) where n is size of A matrix
    """
    matrixtype = str(type(A))
    if 'scipy' in matrixtype:
        n = A.shape[0]
        A = get_petsc_matrix(A, comm)
    elif 'petsc' in matrixtype:
        n = A.getSize()
    elif 'numpy' in matrixtype:
        A = csr_matrix(A)
        n = A.shape[0]
        A = get_petsc_matrix(A, comm)
    else:
        Print(
            'Matrix type {} is not compatible. Use scipy CSR or PETSc AIJ type.'
            .format(type(A)))
    mpisize = comm.size
    Print('Matrix size: {}'.format(n))
    eps = SLEPc.EPS()
    eps.create()
    eps.setOperators(A)
    eps.setProblemType(SLEPc.EPS.ProblemType.HEP)
    if largest:
        eps.setWhichEigenpairs(SLEPc.EPS.Which.LARGEST_REAL)
    else:
        eps.setWhichEigenpairs(SLEPc.EPS.Which.SMALLEST_REAL)
    eps.setDimensions(nev=npairs, ncv=SLEPc.DECIDE, mpd=SLEPc.DECIDE)
    eps.setTolerances(tol=1.e-14)
    eps.setFromOptions()  #Use command line options
    eps.setUp()
    eps.solve()
    nconv = eps.getConverged()
    vr = A.getVecLeft()
    vi = A.getVecLeft()
    if nconv < npairs:
        Print("{} eigenvalues required, {} converged.".format(npairs, nconv))
        npairs = nconv
    evals = np.zeros(npairs)
    evecs = np.zeros((n, npairs))
    for i in range(npairs):
        k = eps.getEigenpair(i, vr, vi)
        if abs(k.imag) > 1.e-10:
            Print("Imaginary eigenvalue: {} + {}j".format(k.real, k.imag))
            Print("Error: {}".format(eps.computeError(i)))
        if mpisize > 1:
            evecs[:, i] = get_numpy_array(vr)
        else:
            evecs[:, i] = vr.getArray()
        evals[i] = k.real
    return evals, evecs
Ejemplo n.º 18
0
def test_moore_spence():

    try:
        from slepc4py import SLEPc
    except ImportError:
        pytest.skip(msg="SLEPc unavailable, skipping eigenvalue test")

    msh = IntervalMesh(1000, 1)
    V = FunctionSpace(msh, "CG", 1)
    R = FunctionSpace(msh, "R", 0)

    # elastica residual
    def residual(theta, lmbda, ttheta):
        return inner(grad(theta),
                     grad(ttheta)) * dx - lmbda**2 * sin(theta) * ttheta * dx

    th = Function(V)
    x = SpatialCoordinate(msh)[0]
    tth = TestFunction(V)
    lm = Constant(3.142)

    # Using guess for parameter lm, solve for state theta (th)
    A = residual(th, lm, tth)
    bcs = [DirichletBC(V, 0.0, "on_boundary")]
    solve(A == 0, th, bcs=bcs)

    # Now solve eigenvalue problem for $F_u(u, \lambda)\phi = r\phi$
    # Want eigenmode phi with minimal eigenvalue r
    B = derivative(residual(th, lm, TestFunction(V)), th, TrialFunction(V))

    petsc_M = assemble(inner(TestFunction(V), TrialFunction(V)) * dx,
                       bcs=bcs).M.handle
    petsc_B = assemble(B, bcs=bcs).M.handle

    num_eigenvalues = 1

    opts = PETSc.Options()
    opts.setValue("eps_target_magnitude", None)
    opts.setValue("eps_target", 0)
    opts.setValue("st_type", "sinvert")

    es = SLEPc.EPS().create(comm=COMM_WORLD)
    es.setDimensions(num_eigenvalues)
    es.setOperators(petsc_B, petsc_M)
    es.setProblemType(SLEPc.EPS.ProblemType.GHEP)
    es.setFromOptions()
    es.solve()

    ev_re, ev_im = petsc_B.getVecs()
    es.getEigenpair(0, ev_re, ev_im)
    eigenmode = Function(V)
    eigenmode.vector().set_local(ev_re)

    Z = MixedFunctionSpace([V, R, V])

    # Set initial guesses for state, parameter, null eigenmode
    z = Function(Z)
    z.split()[0].assign(th)
    z.split()[1].assign(lm)
    z.split()[2].assign(eigenmode)

    # Write Moore-Spence system of equations
    theta, lmbda, phi = split(z)
    ttheta, tlmbda, tphi = TestFunctions(Z)
    F1 = residual(theta, lmbda, ttheta)
    F2 = derivative(residual(theta, lmbda, tphi), z, as_vector([phi, 0, 0]))
    F3 = (inner(phi, phi) - 1) * tlmbda * dx

    F = F1 + F2 + F3

    bcs = [
        DirichletBC(Z.sub(0), 0.0, "on_boundary"),
        DirichletBC(Z.sub(2), 0.0, "on_boundary")
    ]

    # Need to fieldsplit onto the real variable as assembly doesn't work with R
    sp = {
        "mat_type": "matfree",
        "snes_type": "newtonls",
        "snes_monitor": None,
        "snes_converged_reason": None,
        "snes_linesearch_type": "basic",
        "ksp_type": "fgmres",
        "ksp_monitor_true_residual": None,
        "ksp_max_it": 10,
        "pc_type": "fieldsplit",
        "pc_fieldsplit_type": "schur",
        "pc_fieldsplit_schur_fact_type": "full",
        "pc_fieldsplit_0_fields": "0,2",
        "pc_fieldsplit_1_fields": "1",
        "fieldsplit_0_ksp_type": "preonly",
        "fieldsplit_0_pc_type": "python",
        "fieldsplit_0_pc_python_type": "firedrake.AssembledPC",
        "fieldsplit_0_assembled_pc_type": "lu",
        "fieldsplit_0_assembled_pc_factor_mat_solver_type": "mumps",
        "fieldsplit_0_assembled_mat_mumps_icntl_14": 200,
        "mat_mumps_icntl_14": 200,
        "fieldsplit_1_ksp_type": "gmres",
        "fieldsplit_1_ksp_monitor_true_residual": None,
        "fieldsplit_1_ksp_max_it": 1,
        "fieldsplit_1_ksp_convergence_test": "skip",
        "fieldsplit_1_pc_type": "none",
    }

    solve(F == 0, z, bcs=bcs, solver_parameters=sp)
    with z.sub(1).dat.vec_ro as x:
        param = x.norm()

    assert abs(param - pi) < 1.0e-4
Ejemplo n.º 19
0
            row = index
            cols = [index - xsize, index - 1, index, index + 1, index + xsize]
            data = [-1, -1, diag, -1, -1]

            # ovo se moze i sa MatZeroRowsColumns (vjerojatno je efikasnije)
            if y == 0 or x == 0 or x == (xsize - 1) or y == (ysize - 1):
                cols = [index]
                data = [diag]

            A.setValues(row, cols, data)

    A.assemblyBegin()
    A.assemblyEnd()

    # postavi eigenvalue solver
    E = SLEPc.EPS()
    E.create()

    E.setOperators(A)
    # matrica nije hermitska zbog rubnih uvjeta
    E.setProblemType(SLEPc.EPS.ProblemType.NHEP)
    # vrati 3 svojstvene vrijednosti
    E.setDimensions(3, PETSc.DECIDE, PETSc.DECIDE)
    # prvo najmanja pa onda veće
    E.setWhichEigenpairs(SLEPc.EPS.Which.SMALLEST_MAGNITUDE)
    E.setFromOptions()
    E.solve()

    # stvori vektore za rješenje
    xr, xi = A.createVecs()
Ejemplo n.º 20
0
def mfn_multiply_slepc(mat, vec,
                       fntype='exp',
                       MFNType='AUTO',
                       comm=None,
                       isherm=False):
    """Compute the action of ``func(mat) @ vec``.

    Parameters
    ----------
    mat : matrix-like
        Matrix to compute function action of.
    vec : vector-like
        Vector to compute matrix function action on.
    func : {'exp', 'sqrt', 'log'}, optional
        Function to use.
    MFNType : {'krylov', 'expokit'}, optional
        Method of computing the matrix function action, 'expokit' is only
        available for func='exp'.
    comm : mpi4py.MPI.Comm instance, optional
        The mpi communicator.
    isherm : bool, optional
        If `mat` is known to be hermitian, this might speed things up in
        some circumstances.

    Returns
    -------
    fvec : np.matrix
        The vector output of ``func(mat) @ vec``.
    """
    SLEPc, comm = get_slepc(comm=comm)

    mat = convert_mat_to_petsc(mat, comm=comm)

    if isherm:
        mat.setOption(mat.Option.HERMITIAN, True)

    vec = convert_vec_to_petsc(vec, comm=comm)
    out = new_petsc_vec(vec.size, comm=comm)

    if MFNType.upper() == 'AUTO':
        if (fntype == 'exp') and (vec.size <= 2**16):
            MFNType = 'EXPOKIT'
        else:
            MFNType = 'KRYLOV'

    # set up the matrix function options and objects
    mfn = SLEPc.MFN().create(comm=comm)
    mfn.setType(getattr(SLEPc.MFN.Type, MFNType.upper()))
    mfn_fn = mfn.getFN()
    mfn_fn.setType(getattr(SLEPc.FN.Type, fntype.upper()))
    mfn_fn.setScale(1.0, 1.0)
    mfn.setFromOptions()

    mfn.setOperator(mat)
    # 'solve' / perform the matrix function
    mfn.solve(vec, out)

    # --> gather the (distributed) petsc vector to a numpy matrix on master
    all_out = gather_petsc_array(
        out, comm=comm, out_shape=(-1, 1), matrix=True)

    comm.Barrier()
    mfn.destroy()
    return all_out
Ejemplo n.º 21
0
def sorted_krylov_schur(
    P: Union[spmatrix, np.ndarray], k: int, z: str = "LM", tol: float = 1e-16
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
    r"""
    Calculate an orthonormal basis of the subspace associated with the `k`
    dominant eigenvalues of `P` using the Krylov-Schur method as implemented in SLEPc.

    This functions requires :mod:`petsc4py` and :mod:`slepc4py`.

    Parameters
    ----------
    %(P)s
    %(k)s
    %(z)s
    tol
        Convergence criterion used by SLEPc internally. If you are dealing
        with ill-conditioned matrices, consider decreasing this value to
        get accurate results.

    Returns
    -------
    Tuple of the following:

    R
        %(R_sort)s
    Q
        %(Q_sort)s
    eigenvalues
        %(eigenvalues_k)s
    eigenvalues_error
        Array of shape `(k,)` containing the error, based on the residual
        norm, of the `i`th eigenpair at index `i`.
    """  # noqa: D205, D400
    # We like to thank A. Sikorski and M. Weber for pointing us to SLEPc for partial Schur decompositions of
    # sparse matrices.
    # Further parts of sorted_krylov_schur were developed based on the function krylov_schur
    # https://github.com/zib-cmd/cmdtools/blob/1c6b6d8e1c35bb487fcf247c5c1c622b4b665b0a/src/cmdtools/analysis/pcca.py#L64,
    # written by Alexander Sikorski.
    from petsc4py import PETSc
    from slepc4py import SLEPc

    M = PETSc.Mat().create()
    _initialize_matrix(M, P)
    # Creates EPS object.
    E = SLEPc.EPS()
    E.create()
    # Set the matrix associated with the eigenvalue problem.
    E.setOperators(M)
    # Select the particular solver to be used in the EPS object: Krylov-Schur
    E.setType(SLEPc.EPS.Type.KRYLOVSCHUR)
    # Set the number of eigenvalues to compute and the dimension of the subspace.
    E.setDimensions(nev=k)
    # set the tolerance used in the convergence criterion
    E.setTolerances(tol=tol)

    # Specify which portion of the spectrum is to be sought.
    # LARGEST_MAGNITUDE: Largest magnitude (default).
    # LARGEST_REAL: Largest real parts.
    # All possible Options can be found here:
    # (see: https://slepc.upv.es/slepc4py-current/docs/apiref/slepc4py.SLEPc.EPS.Which-class.html)
    if z == "LM":
        E.setWhichEigenpairs(E.Which.LARGEST_MAGNITUDE)
    elif z == "LR":
        E.setWhichEigenpairs(E.Which.LARGEST_REAL)
    else:
        raise ValueError(f"Invalid spectrum sorting options `{z}`. Valid options are: 'LM', 'LR'.")

    # Solve the eigensystem.
    E.solve()

    # getInvariantSubspace() gets an orthonormal basis of the computed invariant subspace.
    # It returns a list of vectors.
    # The returned real vectors span an invariant subspace associated with the computed eigenvalues.
    # We take the sequence of 1-D arrays and stack them as columns to make a single 2-D array.
    Q = np.column_stack([x.array for x in E.getInvariantSubspace()])

    # Get the schur form
    R = E.getDS().getMat(SLEPc.DS.MatType.A)
    R.view()
    R = R.getDenseArray().astype(np.float64)

    # Gets the number of converged eigenpairs.
    nconv = E.getConverged()

    # Warn, if nconv smaller than k.
    if nconv < k:
        warnings.warn(f"The number of converged eigenpairs is `{nconv}`, but `{k}` were requested.")

    # Collect the k dominant eigenvalues.
    eigenvalues = []
    eigenvalues_error = []
    for i in range(nconv):
        # Get the i-th eigenvalue as computed by solve().
        eigenval = E.getEigenvalue(i)
        eigenvalues.append(eigenval)
        # Computes the error (based on the residual norm) associated with the i-th computed eigenpair.
        eigenval_error = E.computeError(i)
        eigenvalues_error.append(eigenval_error)

    # convert lists with eigenvalues and errors to arrays (while keeping excess eigenvalues and errors)
    eigenvalues = np.asarray(eigenvalues)
    eigenvalues_error = np.asarray(eigenvalues_error)

    return R, Q, eigenvalues, eigenvalues_error