4
4
5
5
Dummy advection which use only static geostrophic current, which didn't resolve the complex circulation of the ocean.
6
6
"""
7
- import numpy as np
7
+ import re
8
+
8
9
from matplotlib import pyplot as plt
9
10
from matplotlib .animation import FuncAnimation
11
+ from numpy import arange , isnan , meshgrid , ones
10
12
11
13
import py_eddy_tracker .gui
12
14
from py_eddy_tracker import data
32
34
fig = plt .figure (figsize = (10 , 5 ))
33
35
ax = fig .add_axes ([0 , 0 , 1 , 1 ], projection = "full_axes" )
34
36
ax .set_xlim (19 , 30 ), ax .set_ylim (31 , 36.5 ), ax .grid ()
35
- x , y = np . meshgrid (g .x_c , g .y_c )
37
+ x , y = meshgrid (g .x_c , g .y_c )
36
38
a .filled (ax , facecolors = "r" , alpha = 0.1 ), c .filled (ax , facecolors = "b" , alpha = 0.1 )
37
39
_ = ax .quiver (x .T , y .T , g .grid ("u" ), g .grid ("v" ), scale = 20 )
38
40
41
43
class VideoAnimation (FuncAnimation ):
42
44
def _repr_html_ (self , * args , ** kwargs ):
43
45
"""To get video in html and have a player"""
44
- return self .to_html5_video ()
46
+ content = self .to_html5_video ()
47
+ return re .sub (
48
+ r'width="[0-9]*"\sheight="[0-9]*"' , 'width="100%" height="100%"' , content
49
+ )
45
50
46
51
def save (self , * args , ** kwargs ):
47
52
if args [0 ].endswith ("gif" ):
@@ -56,26 +61,27 @@ def save(self, *args, **kwargs):
56
61
# %%
57
62
# Anim
58
63
# ----
59
- # Particules positions
60
- x , y = np .meshgrid (np .arange (13 , 36 , 0.125 ), np .arange (28 , 40 , 0.125 ))
64
+ # Particles setup
65
+ step_p = 1 / 8
66
+ x , y = meshgrid (arange (13 , 36 , step_p ), arange (28 , 40 , step_p ))
61
67
x , y = x .reshape (- 1 ), y .reshape (- 1 )
62
68
# Remove all original position that we can't advect at first place
63
- m = ~ np .isnan (g .interp ("u" , x , y ))
64
- x , y = x [m ], y [m ]
69
+ m = ~ isnan (g .interp ("u" , x , y ))
70
+ x0 , y0 = x [m ], y [m ]
71
+ x , y = x0 .copy (), y0 .copy ()
65
72
73
+ # %%
66
74
# Movie properties
67
- kwargs = dict (frames = np . arange (51 ), interval = 90 )
75
+ kwargs = dict (frames = arange (51 ), interval = 100 )
68
76
kw_p = dict (nb_step = 2 , time_step = 21600 )
69
77
frame_t = kw_p ["nb_step" ] * kw_p ["time_step" ] / 86400.0
70
78
71
79
72
- def anim_ax (generator , ** kw ):
80
+ # %%
81
+ # Method
82
+ def anim_ax (** kw ):
73
83
t = 0
74
- for _ in range (4 ):
75
- generator .__next__ ()
76
- t += frame_t
77
-
78
- fig = plt .figure (figsize = (10 , 5 ), dpi = 64 )
84
+ fig = plt .figure (figsize = (10 , 5 ), dpi = 55 )
79
85
ax = fig .add_axes ([0 , 0 , 1 , 1 ], projection = "full_axes" )
80
86
ax .set_xlim (19 , 30 ), ax .set_ylim (31 , 36.5 ), ax .grid ()
81
87
a .filled (ax , facecolors = "r" , alpha = 0.1 ), c .filled (ax , facecolors = "b" , alpha = 0.1 )
@@ -94,20 +100,74 @@ def update(i_frame, t_step):
94
100
# %%
95
101
# Filament forward
96
102
# ^^^^^^^^^^^^^^^^
97
- p = g .filament (x , y , "u" , "v" , ** kw_p , filament_size = 4 , rk4 = True )
98
- fig , txt , l , t = anim_ax (p , lw = 0.5 )
103
+ # Draw 3 last position in one path for each particles.,
104
+ # it could be run backward with `backward=True` option in filament method
105
+ p = g .filament (x , y , "u" , "v" , ** kw_p , filament_size = 3 )
106
+ fig , txt , l , t = anim_ax (lw = 0.5 )
99
107
ani = VideoAnimation (fig , update , ** kwargs , fargs = (frame_t ,))
100
108
101
109
# %%
102
- # Filament backward
110
+ # Particle forward
103
111
# ^^^^^^^^^^^^^^^^^
104
- p = g .filament (x , y , "u" , "v" , ** kw_p , filament_size = 4 , backward = True , rk4 = True )
105
- fig , txt , l , t = anim_ax (p , lw = 0.5 )
112
+ # Forward advection of particles
113
+ p = g .advect (x , y , "u" , "v" , ** kw_p )
114
+ fig , txt , l , t = anim_ax (ls = "" , marker = "." , markersize = 1 )
115
+ ani = VideoAnimation (fig , update , ** kwargs , fargs = (frame_t ,))
116
+
117
+ # %%
118
+ # We get last position and run backward until original position
119
+ p = g .advect (x , y , "u" , "v" , ** kw_p , backward = True )
120
+ fig , txt , l , _ = anim_ax (ls = "" , marker = "." , markersize = 1 )
106
121
ani = VideoAnimation (fig , update , ** kwargs , fargs = (- frame_t ,))
107
122
108
123
# %%
109
- # Particule forward
110
- # ^^^^^^^^^^^^^^^^^
111
- p = g .advect (x , y , "u" , "v" , ** kw_p , rk4 = True )
112
- fig , txt , l , t = anim_ax (p , ls = "" , marker = "." , markersize = 1 )
113
- ani = VideoAnimation (fig , update , ** kwargs , fargs = (frame_t ,))
124
+ # Particles stat
125
+ # --------------
126
+
127
+ # %%
128
+ # Time_step settings
129
+ # ^^^^^^^^^^^^^^^^^^
130
+ # Dummy experiment to test advection precision, we run particles 50 days forward and backward ad different time step
131
+ # and we measure distance between new positions and original positions.
132
+ fig = plt .figure ()
133
+ ax = fig .add_subplot (111 )
134
+ ax .grid ()
135
+ kw = dict (
136
+ bins = arange (0 , 50 , 0.001 ),
137
+ cumulative = True ,
138
+ weights = ones (x0 .shape ) / x0 .shape [0 ] * 100.0 ,
139
+ histtype = "step" ,
140
+ )
141
+ for time_step in (10800 , 21600 , 43200 , 86400 ):
142
+ x , y = x0 .copy (), y0 .copy ()
143
+ kw_advect = dict (nb_step = int (50 * 86400 / time_step ), time_step = time_step )
144
+ g .advect (x , y , "u" , "v" , ** kw_advect ).__next__ ()
145
+ g .advect (x , y , "u" , "v" , ** kw_advect , backward = True ).__next__ ()
146
+ d = ((x - x0 ) ** 2 + (y - y0 ) ** 2 ) ** 0.5
147
+ ax .hist (d , ** kw , label = f"{ 86400. / time_step :.0f} time step by day" )
148
+ ax .set_xlim (0 , 0.25 ), ax .set_ylim (0 , 100 ), ax .legend (loc = "lower right" )
149
+ ax .set_title ("Distance after 50 days forward and 50 days backward" )
150
+ ax .set_xlabel ("Distance between original position and final position (in degrees)" )
151
+ _ = ax .set_ylabel ("Percent of particles with distance lesser than" )
152
+
153
+ # %%
154
+ # Time duration
155
+ # ^^^^^^^^^^^^^
156
+ # We keep same time_step but change time duration
157
+ fig = plt .figure ()
158
+ ax = fig .add_subplot (111 )
159
+ ax .grid ()
160
+ time_step = 10800
161
+ for duration in (5 , 50 , 100 ):
162
+ x , y = x0 .copy (), y0 .copy ()
163
+ kw_advect = dict (nb_step = int (duration * 86400 / time_step ), time_step = time_step )
164
+ g .advect (x , y , "u" , "v" , ** kw_advect ).__next__ ()
165
+ g .advect (x , y , "u" , "v" , ** kw_advect , backward = True ).__next__ ()
166
+ d = ((x - x0 ) ** 2 + (y - y0 ) ** 2 ) ** 0.5
167
+ ax .hist (d , ** kw , label = f"Time duration { duration } days" )
168
+ ax .set_xlim (0 , 0.25 ), ax .set_ylim (0 , 100 ), ax .legend (loc = "lower right" )
169
+ ax .set_title (
170
+ "Distance after N days forward and N days backward\n with a time step of 1/8 days"
171
+ )
172
+ ax .set_xlabel ("Distance between original position and final position (in degrees)" )
173
+ _ = ax .set_ylabel ("Percent of particles with distance lesser than " )
0 commit comments