-
Notifications
You must be signed in to change notification settings - Fork 14
/
demo.py
108 lines (98 loc) · 5.35 KB
/
demo.py
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
# ------------------------------------------------------------------
# Step 1: import scipy and pyamg packages
# ------------------------------------------------------------------
import numpy as np
import pyamg
import matplotlib.pyplot as plt
# ------------------------------------------------------------------
# Step 2: setup up the system using pyamg.gallery
# ------------------------------------------------------------------
n = 200
X, Y = np.meshgrid(np.linspace(0, 1, n), np.linspace(0, 1, n))
stencil = pyamg.gallery.diffusion_stencil_2d(type='FE', epsilon=0.001, theta=np.pi / 3)
A = pyamg.gallery.stencil_grid(stencil, (n, n), format='csr')
b = np.random.rand(A.shape[0]) # pick a random right hand side
# ------------------------------------------------------------------
# Step 3: setup of the multigrid hierarchy
# ------------------------------------------------------------------
ml = pyamg.smoothed_aggregation_solver(A) # construct the multigrid hierarchy
# ------------------------------------------------------------------
# Step 4: solve the system
# ------------------------------------------------------------------
res1 = []
x = ml.solve(b, tol=1e-12, residuals=res1) # solve Ax=b to a tolerance of 1e-12
# ------------------------------------------------------------------
# Step 5: print details
# ------------------------------------------------------------------
print("\n")
print("Details: Default AMG")
print("--------------------")
print(ml) # print hierarchy information
print("The residual norm is {}".format(np.linalg.norm(b - A * x))) # compute norm of residual vector
# notice that there are 5 (or maybe 6) levels in the hierarchy
#
# we can look at the data in each of the levels
# e.g. the multigrid components on the finest (0) level
# A: operator on level 0
# P: prolongation operator mapping from level 1 to level 0
# R: restriction operator mapping from level 0 to level 1
# B: near null-space modes for level 0
# presmoother: presmoothing function taking arguments (A,x,b)
# postsmoother: postsmoothing function taking arguments (A,x,b)
print("\n")
print("The Multigrid Hierarchy")
print("-----------------------")
for l in range(len(ml.levels)):
An = ml.levels[l].A.shape[0]
Am = ml.levels[l].A.shape[1]
if l == (len(ml.levels)-1):
print(f"A_{l}: {An:>10}x{Am:<10}")
else:
Pn = ml.levels[l].P.shape[0]
Pm = ml.levels[l].P.shape[1]
print(f"A_{l}: {An:>10}x{Am:<10} P_{l}: {Pn:>10}x{Pm:<10}")
# ------------------------------------------------------------------
# Step 6: change the hierarchy
# ------------------------------------------------------------------
# we can also change the details of the hierarchy
ml = pyamg.smoothed_aggregation_solver(A, # the matrix
B=X.reshape(n * n, 1), # the representation of the near null space (this is a poor choice)
BH=None, # the representation of the left near null space
symmetry='hermitian', # indicate that the matrix is Hermitian
strength='evolution', # change the strength of connection
aggregate='standard', # use a standard aggregation method
smooth=('jacobi', {'omega': 4.0 / 3.0, 'degree': 2}), # prolongation smoothing
presmoother=('block_gauss_seidel', {'sweep': 'symmetric'}),
postsmoother=('block_gauss_seidel', {'sweep': 'symmetric'}),
improve_candidates=[('block_gauss_seidel',
{'sweep': 'symmetric', 'iterations': 4}), None],
max_levels=10, # maximum number of levels
max_coarse=5, # maximum number on a coarse level
keep=False) # keep extra operators around in the hierarchy (memory)
# ------------------------------------------------------------------
# Step 7: print details
# ------------------------------------------------------------------
res2 = [] # keep the residual history in the solve
x = ml.solve(b, tol=1e-12, residuals=res2) # solve Ax=b to a tolerance of 1e-12
print("\n")
print("Details: Specialized AMG")
print("------------------------")
print(ml) # print hierarchy information
print("The residual norm is {}".format(np.linalg.norm(b - A * x))) # compute norm of residual vector
print("\n")
# ------------------------------------------------------------------
# Step 8: plot convergence history
# ------------------------------------------------------------------
fig, ax = plt.subplots()
ax.semilogy(res1, label='Default AMG solver')
ax.semilogy(res2, label='Specialized AMG solver')
ax.set_xlabel('Iteration')
ax.set_ylabel('Relative Residual')
ax.grid(True)
plt.legend()
figname = f'./output/amg_convergence.png'
import sys
if '--savefig' in sys.argv:
plt.savefig(figname, bbox_inches='tight', dpi=150)
else:
plt.show()