Skip to content

Commit a33fbeb

Browse files
author
Daniel Ruprecht
committed
script to test that normalisation procedure for acoustic-advection problem reproduces correct frequencies for unit interval
1 parent e8915aa commit a33fbeb

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed

scripts/advac_disp.py

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import numpy as np
2+
from scipy.sparse import linalg
3+
from pylab import rcParams
4+
import matplotlib.pyplot as plt
5+
from matplotlib.patches import Polygon
6+
from subprocess import call
7+
import sympy
8+
import warnings
9+
10+
def selectomega(omega):
11+
assert np.size(omega)==2, "Should have 2 entries..."
12+
return omega[1]
13+
14+
def findomegasystem(Z):
15+
assert np.array_equal(np.shape(Z), [2,2]), "Must be 2x2 matrix..."
16+
omega = sympy.Symbol('omega')
17+
expf = sympy.exp(-1j*omega)
18+
func = (expf - Z[0,0])*(expf - Z[1,1]) - Z[1,0]*Z[0,1]
19+
solsym = sympy.solve(func, omega)
20+
sols = np.array([complex(solsym[0]), complex(solsym[1])], dtype='complex')
21+
return sols
22+
23+
def findomega(Z):
24+
assert np.size(Z)==2, 'Not a vector of length 2...'
25+
omega = sympy.Symbol('omega')
26+
expf = sympy.exp(-1j*omega)
27+
func = (expf - Z[0])*(expf - Z[1])
28+
solsym = sympy.solve(func, omega)
29+
sols = np.array([complex(solsym[0]), complex(solsym[1])], dtype='complex')
30+
return sols
31+
32+
def findroots(R, n):
33+
assert abs(n - float(int(n)))<1e-14, "n must be an integer or a float equal to an integer"
34+
p = np.zeros(n+1, dtype='complex')
35+
p[-1] = -R
36+
p[0] = 1.0
37+
return np.roots(p)
38+
39+
def normalise(R, T, targets, verbose=False, exact=None):
40+
roots = findroots(R, T)
41+
if verbose:
42+
print ""
43+
print "roots:"
44+
print roots
45+
for x in roots:
46+
assert abs(x**T-R)<1e-10, ("Element in roots not a proper root: err=%5.3e" % abs(x**T-R))
47+
48+
resi = np.zeros((np.size(roots),np.size(targets)))
49+
for i in range(0,np.size(targets)):
50+
for j in range(0,np.size(roots)):
51+
resi[j,i] = abs( roots[j] - targets[i] )
52+
53+
# Select root that generates smallest residual across all targets:
54+
# find row number of smallest element in resi
55+
minind = np.argmin(resi) / np.size(targets)
56+
if verbose:
57+
print ("Target values: %s" % targets)
58+
print ("Residuals: %s" % resi)
59+
print ("Selected row: %s" % minind)
60+
print ("Selected value: %s" % roots[minind])
61+
if not exact==None:
62+
print ("Exact values: %s" % exact)
63+
return roots[minind]
64+
65+
66+
Tend = 4.0
67+
nslices = int(Tend)
68+
Nsamples = 80
69+
k_vec = np.linspace(0.0, np.pi, Nsamples+1, endpoint=False)
70+
k_vec = k_vec[1:]
71+
72+
Uadv = 0.1
73+
cspeed = 1.0
74+
75+
phase = np.zeros((2,Nsamples))
76+
amp_factor = np.zeros((2,Nsamples))
77+
targets = np.zeros((2,Nsamples), dtype = 'complex')
78+
79+
imax = 21
80+
#imax = Nsamples
81+
for i in range(17,imax):
82+
print ("---- i = %2i ---- " % i)
83+
Lmat = -1j*k_vec[i]*np.array([ [Uadv, cspeed], [cspeed, Uadv] ], dtype = 'complex')
84+
85+
stab = linalg.expm(Lmat*Tend)
86+
87+
# if i==0, compute targets from contiuous stability function
88+
stab_unit = linalg.expm(Lmat)
89+
90+
# analytic frequencies match frequencies computed from unit interval system
91+
omegas_unit = findomegasystem(stab_unit)
92+
phase[0,i] = Uadv + cspeed
93+
phase[1,i] = selectomega(omegas_unit).real/k_vec[i]
94+
95+
# diagonalise unit system and verify that frequencies do not change
96+
Dunit, Vunit = np.linalg.eig(stab_unit)
97+
#Dunit = np.sort(Dunit)
98+
if i==0:
99+
targets[:,i] = Dunit
100+
101+
omegas_diag_unit = findomega(Dunit)
102+
103+
err_omega = np.linalg.norm(omegas_unit - omegas_diag_unit, np.inf)
104+
print ("Defect between unit and unit-diagonalised frequencies: %5.3E" % err_omega)
105+
106+
# normalise stab function
107+
D, V = np.linalg.eig(stab)
108+
omegas_diag_full = findomega(D)
109+
110+
err_omega = np.linalg.norm(omegas_diag_full/Tend - omegas_diag_unit, np.inf)
111+
print ""
112+
print omegas_diag_unit
113+
print omegas_diag_full/Tend
114+
print (">>>> Defect between omegas from diagonalised unit system and diagonalised full system: %5.3E" % err_omega)
115+
116+
D = np.sort(D)
117+
Dtilde = np.zeros(2, dtype='complex')
118+
for j in range(0,2):
119+
Dtilde[j] = normalise(D[j], Tend, targets=targets[:,i], verbose=True, exact=Dunit)
120+
#Dtilde[j] = normalise(D[j], Tend, targets=Dunit, verbose=False)
121+
#Dtilde = np.sort(Dtilde)
122+
err_eigv = np.linalg.norm(Dtilde - Dunit, np.inf)
123+
print ("Defect between normalised and unit stability function eigenvalues: %5.3E" % err_eigv)
124+
125+
if (i<imax-1):
126+
targets[:,i+1] = Dtilde
127+
128+
# normalised stability function matches unit interval stability function
129+
stab_unit_sorted = V.dot(np.diag(Dunit).dot(np.linalg.inv(V)))
130+
stab_normalised = V.dot(np.diag(Dtilde).dot(np.linalg.inv(V)))
131+
err_stab = np.linalg.norm(stab_normalised - stab_unit_sorted, np.infty)
132+
print ("Defect between unit interval and normalised stability matrix: %5.3E" % err_stab)
133+
### NOTE: The defects here are caused by different ordering of eigenvalues!
134+
135+
# frequencies of unit interval system match frequencies of normalised system
136+
omegas_diag_normalised = findomega(Dtilde)
137+
err_omega = np.linalg.norm(omegas_diag_unit - omegas_diag_normalised, np.inf)
138+
print ("Defect between frequencies from diagonalised normalised system and diagonalised unit intervall: %5.3E" % err_omega)
139+
# end of loop body over k_vec
140+
141+
print "------"
142+
143+
#rcParams['figure.figsize'] = 1.5, 1.5
144+
if True:
145+
fs = 14
146+
fig = plt.figure()
147+
plt.plot(k_vec, phase[0,:], '--', color='k', linewidth=1.5, label='Exact')
148+
plt.plot(k_vec, phase[1,:], '-', color='g', linewidth=1.5, label='Solved')
149+
plt.xlabel('Wave number', fontsize=fs, labelpad=0.25)
150+
plt.ylabel('Phase speed', fontsize=fs, labelpad=0.5)
151+
plt.xlim([k_vec[0], k_vec[-1:]])
152+
plt.ylim([0.0, 1.1*np.max(phase)])
153+
fig.gca().tick_params(axis='both', labelsize=fs)
154+
plt.legend(loc='lower left', fontsize=fs, prop={'size':fs-2})
155+
156+
fig = plt.figure()
157+
plt.plot(k_vec, amp_factor[0,:], '--', color='k', linewidth=1.5, label='Exact')
158+
plt.plot(k_vec, amp_factor[1,:], '-', color='g', linewidth=1.5, label='Solved')
159+
plt.xlabel('Wave number', fontsize=fs, labelpad=0.25)
160+
plt.ylabel('Amplification factor', fontsize=fs, labelpad=0.5)
161+
fig.gca().tick_params(axis='both', labelsize=fs)
162+
plt.xlim([k_vec[0], k_vec[-1:]])
163+
# plt.ylim([k_vec[0], k_vec[-1:]])
164+
plt.legend(loc='lower left', fontsize=fs, prop={'size':fs-2})
165+
plt.gca().set_ylim([0.0, 1.1])
166+
#plt.xticks([0, 1, 2, 3], fontsize=fs)
167+
plt.show()

0 commit comments

Comments
 (0)