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()
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)
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 = []
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()
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
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)
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
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()
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()
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 = []
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
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)
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)
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]
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
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)
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
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
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()
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
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