44
55Dummy advection which use only static geostrophic current, which didn't resolve the complex circulation of the ocean.
66"""
7- import numpy as np
7+ import re
8+
89from matplotlib import pyplot as plt
910from matplotlib .animation import FuncAnimation
11+ from numpy import arange , isnan , meshgrid , ones
1012
1113import py_eddy_tracker .gui
1214from py_eddy_tracker import data
3234fig = plt .figure (figsize = (10 , 5 ))
3335ax = fig .add_axes ([0 , 0 , 1 , 1 ], projection = "full_axes" )
3436ax .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 )
3638a .filled (ax , facecolors = "r" , alpha = 0.1 ), c .filled (ax , facecolors = "b" , alpha = 0.1 )
3739_ = ax .quiver (x .T , y .T , g .grid ("u" ), g .grid ("v" ), scale = 20 )
3840
4143class VideoAnimation (FuncAnimation ):
4244 def _repr_html_ (self , * args , ** kwargs ):
4345 """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+ )
4550
4651 def save (self , * args , ** kwargs ):
4752 if args [0 ].endswith ("gif" ):
@@ -56,26 +61,27 @@ def save(self, *args, **kwargs):
5661# %%
5762# Anim
5863# ----
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 ))
6167x , y = x .reshape (- 1 ), y .reshape (- 1 )
6268# 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 ()
6572
73+ # %%
6674# Movie properties
67- kwargs = dict (frames = np . arange (51 ), interval = 90 )
75+ kwargs = dict (frames = arange (51 ), interval = 100 )
6876kw_p = dict (nb_step = 2 , time_step = 21600 )
6977frame_t = kw_p ["nb_step" ] * kw_p ["time_step" ] / 86400.0
7078
7179
72- def anim_ax (generator , ** kw ):
80+ # %%
81+ # Method
82+ def anim_ax (** kw ):
7383 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 )
7985 ax = fig .add_axes ([0 , 0 , 1 , 1 ], projection = "full_axes" )
8086 ax .set_xlim (19 , 30 ), ax .set_ylim (31 , 36.5 ), ax .grid ()
8187 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):
94100# %%
95101# Filament forward
96102# ^^^^^^^^^^^^^^^^
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 )
99107ani = VideoAnimation (fig , update , ** kwargs , fargs = (frame_t ,))
100108
101109# %%
102- # Filament backward
110+ # Particle forward
103111# ^^^^^^^^^^^^^^^^^
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 )
106121ani = VideoAnimation (fig , update , ** kwargs , fargs = (- frame_t ,))
107122
108123# %%
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