File: ex1.py

package info (click to toggle)
slepc4py 3.24.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,760 kB
  • sloc: python: 6,916; makefile: 129; ansic: 98; sh: 46
file content (236 lines) | stat: -rw-r--r-- 8,094 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# ex1.py: Standard symmetric eigenproblem for the 1-D Laplacian
# =============================================================
#
# This example computes eigenvalues and eigenvectors of the discrete Laplacian
# on a one-dimensional domain with finite differences.
#
# The full source code for this demo can be `downloaded here
# <../_static/ex1.py>`__.

# The first thing to do is initialize the libraries. This is normally not
# required, as it is done automatically at import time. However, if you want to
# gain access to the facilities for setting command-line options, the
# following lines must be executed by the main script prior to any petsc4py or
# slepc4py calls:

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

# Next, we have to import the relevant modules. Normally, both PETSc and SLEPc
# modules have to be imported in all slepc4py programs. It may be useful to
# import NumPy as well:

from petsc4py import PETSc
from slepc4py import SLEPc
import numpy

# At this point, we can use any petsc4py and slepc4py operations. For instance,
# the following lines allow the user to specify an integer command-line
# argument ``n`` with a default value of 30 (see below for example usage
# of command-line options):

opts = PETSc.Options()
n = opts.getInt('n', 30)

# It is necessary to build a matrix to define an eigenproblem (or two in the
# case of generalized eigenproblems). The following fragment of code creates
# the matrix object and then fills the non-zero elements one by one. The matrix
# of this particular example is tridiagonal, with value 2 in the diagonal, and
# -1 in off-diagonal positions. See petsc4py documentation for details about
# matrix objects:

A = PETSc.Mat(); A.create()
A.setSizes([n, n])
A.setFromOptions()

rstart, rend = A.getOwnershipRange()

# first row
if rstart == 0:
  A[0, :2] = [2, -1]
  rstart += 1
# last row
if rend == n:
  A[n-1, -2:] = [-1, 2]
  rend -= 1
# other rows
for i in range(rstart, rend):
  A[i, i-1:i+2] = [-1, 2, -1]

A.assemble()

# The solver object is created in a similar way as other objects in petsc4py:

E = SLEPc.EPS(); E.create()

# Once the object is created, the eigenvalue problem must be specified. At
# least one matrix must be provided. The problem type must be indicated as
# well, in this case it is HEP (Hermitian eigenvalue problem). Apart from
# these, other settings could be provided here (for instance, the tolerance for
# the computation). After all options have been set, the user should call the
# `setFromOptions() <EPS.setFromOptions()>` operation, so that any options
# specified at run time in the command line are passed to the solver object:

E.setOperators(A)
E.setProblemType(SLEPc.EPS.ProblemType.HEP)

history = []
def monitor(eps, its, nconv, eig, err):
    if nconv<len(err): history.append(err[nconv])
E.setMonitor(monitor)

E.setFromOptions()

# After that, the `solve() <EPS.solve()>` method will run the selected
# eigensolver, keeping the solution stored internally:

E.solve()

# Once the computation has finished, we are ready to print the results. First,
# some informative data can be retrieved from the solver object:

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

# For retrieving the solution, it is necessary to find out how many eigenpairs
# have converged to the requested precision:

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

# For each of the ``nconv`` eigenpairs, we can retrieve the eigenvalue ``k``,
# and the eigenvector, which is represented by means of two petsc4py vectors
# ``vr`` and ``vi`` (the real and imaginary part of the eigenvector, since for
# real matrices the eigenvalue and eigenvector may be complex). In this
# example we know that both the eigenvalue and eigenvector are real, so only
# one vector ``v`` is needed. We also compute the corresponding relative errors
# in order to make sure that the computed solution is indeed correct:

if nconv > 0:
  # Create the results vectors
  v, _ = A.createVecs()
  #
  Print()
  Print("        k          ||Ax-kx||/||kx|| ")
  Print("----------------- ------------------")
  for i in range(nconv):
    k = E.getEigenpair(i, v)
    error = E.computeError(i)
    Print( " %12f       %12g" % (k, error) )
  Print()

#
# Example of command-line usage
# -----------------------------
#
# Now we illustrate how to specify command-line options in order to extract the
# full potential of slepc4py.
#
# A simple execution of the ``demo/ex1.py`` script will result in the following
# output:
#
# .. code-block:: console
#
#   $ python demo/ex1.py
#
#   ******************************
#   *** SLEPc Solution Results ***
#   ******************************
#
#   Number of iterations of the method: 4
#   Solution method: krylovschur
#   Number of requested eigenvalues: 1
#   Stopping condition: tol=1e-07, maxit=100
#   Number of converged eigenpairs 4
#
#       k          ||Ax-kx||/||kx||
#   ----------------- ------------------
#        3.989739        5.76012e-09
#        3.959060        1.41957e-08
#        3.908279        6.74118e-08
#        3.837916        8.34269e-08
#
# For specifying different setting for the solver parameters, we can use SLEPc
# command-line options with the ``-eps`` prefix. For instance, to change the number
# of requested eigenvalues and the tolerance:
#
# .. code-block:: console
#
#   $ python demo/ex1.py -eps_nev 10 -eps_tol 1e-11
#
# The method used by the solver object can also be set at run time:
#
# .. code-block:: console
#
#   $ python demo/ex1.py -eps_type subspace
#
# All the above settings can also be changed within the source code by making
# use of the appropriate slepc4py method. Since options can be set from within
# the code and the command-line, it is often useful to view the particular
# settings that are currently being used:
#
# .. code-block:: console
#
#   $ python demo/ex1.py -eps_view
#
#   EPS Object: 1 MPI process
#     type: krylovschur
#       50% of basis vectors kept after restart
#       using the locking variant
#     problem type: symmetric eigenvalue problem
#     selected portion of the spectrum: largest eigenvalues in magnitude
#     number of eigenvalues (nev): 1
#     number of column vectors (ncv): 16
#     maximum dimension of projected problem (mpd): 16
#     maximum number of iterations: 100
#     tolerance: 1e-08
#     convergence test: relative to the eigenvalue
#   BV Object: 1 MPI process
#     type: mat
#     17 columns of global length 30
#     orthogonalization method: classical Gram-Schmidt
#     orthogonalization refinement: if needed (eta: 0.7071)
#     block orthogonalization method: GS
#     doing matmult as a single matrix-matrix product
#   DS Object: 1 MPI process
#     type: hep
#     solving the problem with: Implicit QR method (_steqr)
#   ST Object: 1 MPI process
#     type: shift
#     shift: 0
#     number of matrices: 1
#
# Note that for computing eigenvalues of smallest magnitude we can use the
# option ``-eps_smallest_magnitude``, but for interior eigenvalues things are
# not so straightforward. One possibility is to try with harmonic extraction,
# for instance to get the eigenvalues closest to 0.6:
#
# .. code-block:: console
#
#   $ python demo/ex1.py -eps_harmonic -eps_target 0.6
#
# Depending on the problem, harmonic extraction may fail to converge. In those
# cases, it is necessary to specify a spectral transformation other than the
# default. In the command-line, this is indicated with the ``-st_`` prefix. For
# example, shift-and-invert with a value of the shift equal to 0.6 would be:
#
# .. code-block:: console
#
#   $ python demo/ex1.py -st_type sinvert -eps_target 0.6