-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathadvect.py
117 lines (94 loc) · 2.88 KB
/
advect.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
109
110
111
112
113
114
115
116
117
#!/usr/bin/env python3
from functools import partial
from typing import AnyStr
from contextlib import contextmanager
import time
import numpy as np
import scipy.fftpack as fft
from netCDF4 import Dataset
import matplotlib.pyplot as plt
from ode import OdeSolver
dt = 0.02
@contextmanager
def Timer(tag=''):
start = time.time()
try:
yield
finally:
tot = time.time() - start
print(f'{tag:s} {tot:.02f}')
class Grid:
nx = 360
xmin = 0.0
xmax = 360.0
xi = np.linspace(xmin, xmax, nx+1)
x = (xi[1:] + xi[:-1])/2
dx = (xmax - xmin)/nx
def __init__(self, scheme:AnyStr):
self.scheme = getattr(self, '_scheme_'+scheme)
def tend(self, s, u):
return self.scheme(s, u)
@classmethod
def _scheme_fd(cls, s, u):
f = s*u # flux
weights = (
(2, -1/12),
(1, 2/3),
(-1, -2/3),
(-2, 1/12)
)
return sum(w*np.roll(f, shit) for shit, w in weights)/cls.dx
@classmethod
def _scheme_spec(cls, s, u):
f = s*u # flux
fspec = fft.fft(f)
freq = fft.fftfreq(len(f), d=cls.dx)
dfdxspec = -fspec*complex(0, 2*np.pi)*freq
return np.real(fft.ifft(dfdxspec))
@classmethod
def _scheme_fv(cls, s, u):
f = s*u # flux
fs1 = np.roll(f, 1)
fsn1 = np.roll(f, -1)
c = u*dt/cls.dx
r = (f - fs1)/(fsn1 - f + 1.0e-6)
phi = np.maximum(0.0, np.minimum(2*r, 1.0))
phi = np.maximum(np.minimum(r, 2.0), phi)
fmid = f + phi*((1-c)/2)*(fsn1 - f)
return -np.diff(fmid, prepend=fmid[-1])/cls.dx
# plt.plot(phi, label='Zhang')
# plt.plot(np.reshape(np.loadtxt('data.txt'), (-1, )), label='Wu')
# plt.legend()
# plt.show()
# import sys; sys.exit()
def read_init():
with Dataset('ic_homework3.nc', 'r') as dset:
ic = dset.variables['N'][:]
ic = np.array(ic)
ic.setflags(write=False)
return ic
class Model(OdeSolver):
ic = read_init()
def __init__(self, scheme):
tend = partial(Grid(scheme).tend, u=10.0)
odescheme = 'euler' if scheme == 'fv' else 'rk4'
super().__init__(tend, dt=dt, scheme=odescheme)
def iter_states(self):
return super().iter_states(self.ic)
def main():
nstep = int(1.8e4)
plt.plot(Model.ic, label='exact', linestyle='-', linewidth=4.0)
for scheme in ('fd', 'spec', 'fv'):
model = Model(scheme)
with Timer(scheme):
for i, state in zip(range(nstep), model.iter_states()):
if i %100 == 0:
print(scheme, f'nstep {i:04d}')
plt.plot(state, label=scheme, marker='', linestyle='-', markersize=0.2)
plt.legend()
plt.xlabel(r'Lontitude ($^\circ$)')
plt.ylabel('N')
plt.title(f'NSTEP = {nstep}')
plt.savefig(f'{nstep:d}steps.eps')
if __name__ == '__main__':
main()