Skip to content

Commit 9f43829

Browse files
committed
add theta to fsle example
1 parent 77ff344 commit 9f43829

File tree

2 files changed

+58
-18
lines changed

2 files changed

+58
-18
lines changed

examples/07_cube_manipulation/pet_fsle_med.py

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
from matplotlib import pyplot as plt
1616
from numba import njit
17-
from numpy import arange, empty, isnan, log2, ma, meshgrid, zeros
17+
from numpy import arange, arctan2, empty, isnan, log2, ma, meshgrid, ones, pi, zeros
1818

1919
from py_eddy_tracker import start_logger
2020
from py_eddy_tracker.data import get_path
@@ -39,7 +39,7 @@
3939
# Methods to compute FSLE
4040
# -----------------------
4141
@njit(cache=True, fastmath=True)
42-
def check_p(x, y, g, m, dt, dist_init=0.02, dist_max=0.6):
42+
def check_p(x, y, flse, theta, m_set, m, dt, dist_init=0.02, dist_max=0.6):
4343
"""
4444
Check if distance between eastern or northern particle to center particle is bigger than `dist_max`
4545
"""
@@ -60,11 +60,17 @@ def check_p(x, y, g, m, dt, dist_init=0.02, dist_max=0.6):
6060
de = dxe ** 2 + dye ** 2
6161

6262
if dn >= delta or de >= delta:
63-
s1 = dxe ** 2 + dxn ** 2 + dye ** 2 + dyn ** 2
63+
s1 = dn + de
64+
at1 = 2 * (dxe * dxn + dye * dyn)
65+
at2 = de - dn
6466
s2 = ((dxn + dye) ** 2 + (dxe - dyn) ** 2) * (
6567
(dxn - dye) ** 2 + (dxe + dyn) ** 2
6668
)
67-
g[i] = 1 / (2 * dt) * log2(1 / (2 * dist_init ** 2) * (s1 + s2 ** 0.5))
69+
flse[i] = 1 / (2 * dt) * log2(1 / (2 * dist_init ** 2) * (s1 + s2 ** 0.5))
70+
theta[i] = arctan2(at1, at2 + s2) * 180 / pi
71+
# To know where value are set
72+
m_set[i] = False
73+
# To stop partcile advection
6874
m[i0], m[i_n], m[i_e] = True, True, True
6975

7076

@@ -110,10 +116,9 @@ def build_triplet(x, y, step=0.02):
110116
# Particles
111117
# ---------
112118
x0_, y0_ = -5, 30
113-
lon_p, lat_p = arange(x0_, x0_ + 43, step_grid_out), arange(
114-
y0_, y0_ + 16, step_grid_out
115-
)
116-
x0, y0 = meshgrid(lon_p, lat_p)
119+
lon_p = arange(x0_, x0_ + 43, step_grid_out)
120+
lat_p = arange(y0_, y0_ + 16, step_grid_out)
121+
y0, x0 = meshgrid(lat_p, lon_p)
117122
grid_shape = x0.shape
118123
x0, y0 = x0.reshape(-1), y0.reshape(-1)
119124
# Identify all particle not on land
@@ -126,6 +131,8 @@ def build_triplet(x, y, step=0.02):
126131

127132
# Array to compute fsle
128133
fsle = zeros(x0.shape[0], dtype="f4")
134+
theta = zeros(x0.shape[0], dtype="f4")
135+
mask = ones(x0.shape[0], dtype="f4")
129136
x, y = build_triplet(x0, y0, dist_init)
130137
used = zeros(x.shape[0], dtype="bool")
131138

@@ -137,20 +144,23 @@ def build_triplet(x, y, step=0.02):
137144
for i in range(time_step_by_days * nb_days):
138145
t, xt, yt = p.__next__()
139146
dt = t / 86400.0 - t0
140-
check_p(xt, yt, fsle, used, dt, dist_max=dist_max, dist_init=dist_init)
147+
check_p(xt, yt, fsle, theta, mask, used, dt, dist_max=dist_max, dist_init=dist_init)
141148

142149
# Get index with original_position
143150
i = ((x0 - x0_) / step_grid_out).astype("i4")
144151
j = ((y0 - y0_) / step_grid_out).astype("i4")
145152
fsle_ = empty(grid_shape, dtype="f4")
146-
used_ = zeros(grid_shape, dtype="bool")
147-
fsle_[j, i] = fsle
148-
used_[j, i] = used[::3]
153+
theta_ = empty(grid_shape, dtype="f4")
154+
mask_ = ones(grid_shape, dtype="bool")
155+
fsle_[i, j] = fsle
156+
theta_[i, j] = theta
157+
mask_[i, j] = mask
149158
# Create a grid object
150159
fsle_custom = RegularGridDataset.with_array(
151160
coordinates=("lon", "lat"),
152161
datas=dict(
153-
fsle=ma.array(fsle_.T, mask=~used_.T),
162+
fsle=ma.array(fsle_, mask=mask_),
163+
theta=ma.array(theta_, mask=mask_),
154164
lon=lon_p,
155165
lat=lat_p,
156166
),
@@ -169,3 +179,15 @@ def build_triplet(x, y, step=0.02):
169179
m = fsle_custom.display(ax, 1 / fsle_custom.grid("fsle"), **kw)
170180
ax.grid()
171181
cb = plt.colorbar(m, cax=fig.add_axes([0.94, 0.05, 0.01, 0.9]))
182+
# %%
183+
# Display Theta
184+
# -------------
185+
fig = plt.figure(figsize=(13, 5), dpi=150)
186+
ax = fig.add_axes([0.03, 0.03, 0.90, 0.94])
187+
ax.set_xlim(-6, 36.5), ax.set_ylim(30, 46)
188+
ax.set_aspect("equal")
189+
ax.set_title("Theta from finite size lyapunov exponent", weight="bold")
190+
kw = dict(cmap="Spectral_r", vmin=-180, vmax=180)
191+
m = fsle_custom.display(ax, fsle_custom.grid("theta"), **kw)
192+
ax.grid()
193+
cb = plt.colorbar(m, cax=fig.add_axes([0.94, 0.05, 0.01, 0.9]))

notebooks/python_module/07_cube_manipulation/pet_fsle_med.ipynb

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
},
2727
"outputs": [],
2828
"source": [
29-
"from matplotlib import pyplot as plt\nfrom numba import njit\nfrom numpy import arange, empty, isnan, log2, ma, meshgrid, zeros\n\nfrom py_eddy_tracker import start_logger\nfrom py_eddy_tracker.data import get_path\nfrom py_eddy_tracker.dataset.grid import GridCollection, RegularGridDataset\n\nstart_logger().setLevel(\"ERROR\")"
29+
"from matplotlib import pyplot as plt\nfrom numba import njit\nfrom numpy import arange, arctan2, empty, isnan, log2, ma, meshgrid, ones, pi, zeros\n\nfrom py_eddy_tracker import start_logger\nfrom py_eddy_tracker.data import get_path\nfrom py_eddy_tracker.dataset.grid import GridCollection, RegularGridDataset\n\nstart_logger().setLevel(\"ERROR\")"
3030
]
3131
},
3232
{
@@ -62,7 +62,7 @@
6262
},
6363
"outputs": [],
6464
"source": [
65-
"@njit(cache=True, fastmath=True)\ndef check_p(x, y, g, m, dt, dist_init=0.02, dist_max=0.6):\n \"\"\"\n Check if distance between eastern or northern particle to center particle is bigger than `dist_max`\n \"\"\"\n nb_p = x.shape[0] // 3\n delta = dist_max ** 2\n for i in range(nb_p):\n i0 = i * 3\n i_n = i0 + 1\n i_e = i0 + 2\n # If particle already set, we skip\n if m[i0] or m[i_n] or m[i_e]:\n continue\n # Distance with north\n dxn, dyn = x[i0] - x[i_n], y[i0] - y[i_n]\n dn = dxn ** 2 + dyn ** 2\n # Distance with east\n dxe, dye = x[i0] - x[i_e], y[i0] - y[i_e]\n de = dxe ** 2 + dye ** 2\n\n if dn >= delta or de >= delta:\n s1 = dxe ** 2 + dxn ** 2 + dye ** 2 + dyn ** 2\n s2 = ((dxn + dye) ** 2 + (dxe - dyn) ** 2) * (\n (dxn - dye) ** 2 + (dxe + dyn) ** 2\n )\n g[i] = 1 / (2 * dt) * log2(1 / (2 * dist_init ** 2) * (s1 + s2 ** 0.5))\n m[i0], m[i_n], m[i_e] = True, True, True\n\n\n@njit(cache=True)\ndef build_triplet(x, y, step=0.02):\n \"\"\"\n Triplet building for each position we add east and north point with defined step\n \"\"\"\n nb_x = x.shape[0]\n x_ = empty(nb_x * 3, dtype=x.dtype)\n y_ = empty(nb_x * 3, dtype=y.dtype)\n for i in range(nb_x):\n i0 = i * 3\n i_n, i_e = i0 + 1, i0 + 2\n x__, y__ = x[i], y[i]\n x_[i0], y_[i0] = x__, y__\n x_[i_n], y_[i_n] = x__, y__ + step\n x_[i_e], y_[i_e] = x__ + step, y__\n return x_, y_"
65+
"@njit(cache=True, fastmath=True)\ndef check_p(x, y, flse, theta, m_set, m, dt, dist_init=0.02, dist_max=0.6):\n \"\"\"\n Check if distance between eastern or northern particle to center particle is bigger than `dist_max`\n \"\"\"\n nb_p = x.shape[0] // 3\n delta = dist_max ** 2\n for i in range(nb_p):\n i0 = i * 3\n i_n = i0 + 1\n i_e = i0 + 2\n # If particle already set, we skip\n if m[i0] or m[i_n] or m[i_e]:\n continue\n # Distance with north\n dxn, dyn = x[i0] - x[i_n], y[i0] - y[i_n]\n dn = dxn ** 2 + dyn ** 2\n # Distance with east\n dxe, dye = x[i0] - x[i_e], y[i0] - y[i_e]\n de = dxe ** 2 + dye ** 2\n\n if dn >= delta or de >= delta:\n s1 = dn + de\n at1 = 2 * (dxe * dxn + dye * dyn)\n at2 = de - dn\n s2 = ((dxn + dye) ** 2 + (dxe - dyn) ** 2) * (\n (dxn - dye) ** 2 + (dxe + dyn) ** 2\n )\n flse[i] = 1 / (2 * dt) * log2(1 / (2 * dist_init ** 2) * (s1 + s2 ** 0.5))\n theta[i] = arctan2(at1, at2 + s2) * 180 / pi\n # To know where value are set\n m_set[i] = False\n # To stop partcile advection\n m[i0], m[i_n], m[i_e] = True, True, True\n\n\n@njit(cache=True)\ndef build_triplet(x, y, step=0.02):\n \"\"\"\n Triplet building for each position we add east and north point with defined step\n \"\"\"\n nb_x = x.shape[0]\n x_ = empty(nb_x * 3, dtype=x.dtype)\n y_ = empty(nb_x * 3, dtype=y.dtype)\n for i in range(nb_x):\n i0 = i * 3\n i_n, i_e = i0 + 1, i0 + 2\n x__, y__ = x[i], y[i]\n x_[i0], y_[i0] = x__, y__\n x_[i_n], y_[i_n] = x__, y__ + step\n x_[i_e], y_[i_e] = x__ + step, y__\n return x_, y_"
6666
]
6767
},
6868
{
@@ -80,7 +80,7 @@
8080
},
8181
"outputs": [],
8282
"source": [
83-
"# Step in degrees for ouput\nstep_grid_out = 1/25.\n# Initial separation in degrees\ndist_init = 1/50.\n# Final separation in degrees\ndist_max = 1/5.\n# Time of start\nt0 = 20268\n# Number of time step by days\ntime_step_by_days = 5\n# Maximal time of advection\n# Here we limit because our data cube cover only 3 month\nnb_days = 85\n# Backward or forward\nbackward=True"
83+
"# Step in degrees for ouput\nstep_grid_out = 1 / 25.0\n# Initial separation in degrees\ndist_init = 1 / 50.0\n# Final separation in degrees\ndist_max = 1 / 5.0\n# Time of start\nt0 = 20268\n# Number of time step by days\ntime_step_by_days = 5\n# Maximal time of advection\n# Here we limit because our data cube cover only 3 month\nnb_days = 85\n# Backward or forward\nbackward = True"
8484
]
8585
},
8686
{
@@ -98,7 +98,7 @@
9898
},
9999
"outputs": [],
100100
"source": [
101-
"x0_, y0_ = -5, 30\nlon_p, lat_p = arange(x0_, x0_ + 43, step_grid_out), arange(y0_, y0_ + 16, step_grid_out)\nx0, y0 = meshgrid(lon_p, lat_p)\ngrid_shape = x0.shape\nx0, y0 = x0.reshape(-1), y0.reshape(-1)\n# Identify all particle not on land\nm = ~isnan(c[t0].interp(\"adt\", x0, y0))\nx0, y0 = x0[m], y0[m]"
101+
"x0_, y0_ = -5, 30\nlon_p = arange(x0_, x0_ + 43, step_grid_out)\nlat_p = arange(y0_, y0_ + 16, step_grid_out)\ny0, x0 = meshgrid(lat_p, lon_p)\ngrid_shape = x0.shape\nx0, y0 = x0.reshape(-1), y0.reshape(-1)\n# Identify all particle not on land\nm = ~isnan(c[t0].interp(\"adt\", x0, y0))\nx0, y0 = x0[m], y0[m]"
102102
]
103103
},
104104
{
@@ -116,7 +116,7 @@
116116
},
117117
"outputs": [],
118118
"source": [
119-
"# Array to compute fsle\nfsle = zeros(x0.shape[0], dtype=\"f4\")\nx, y = build_triplet(x0, y0, dist_init)\nused = zeros(x.shape[0], dtype=\"bool\")\n\n# advection generator\nkw = dict(t_init=t0, nb_step=1, backward=backward, mask_particule=used)\np = c.advect(x, y, \"u\", \"v\", time_step=86400 / time_step_by_days, **kw)\n\n# We check at each step of advection if particle distance is over `dist_max`\nfor i in range(time_step_by_days * nb_days):\n t, xt, yt = p.__next__()\n dt = t / 86400.0 - t0\n check_p(xt, yt, fsle, used, dt, dist_max=dist_max, dist_init=dist_init)\n\n# Get index with original_position\ni = ((x0 - x0_) / step_grid_out).astype(\"i4\")\nj = ((y0 - y0_) / step_grid_out).astype(\"i4\")\nfsle_ = empty(grid_shape, dtype=\"f4\")\nused_ = zeros(grid_shape, dtype=\"bool\")\nfsle_[j, i] = fsle\nused_[j, i] = used[::3]\n# Create a grid object\nfsle_custom = RegularGridDataset.with_array(\n coordinates=(\"lon\", \"lat\"),\n datas=dict(\n fsle=ma.array(fsle_.T, mask=~used_.T),\n lon=lon_p,\n lat=lat_p,\n ),\n centered=True,\n)"
119+
"# Array to compute fsle\nfsle = zeros(x0.shape[0], dtype=\"f4\")\ntheta = zeros(x0.shape[0], dtype=\"f4\")\nmask = ones(x0.shape[0], dtype=\"f4\")\nx, y = build_triplet(x0, y0, dist_init)\nused = zeros(x.shape[0], dtype=\"bool\")\n\n# advection generator\nkw = dict(t_init=t0, nb_step=1, backward=backward, mask_particule=used)\np = c.advect(x, y, \"u\", \"v\", time_step=86400 / time_step_by_days, **kw)\n\n# We check at each step of advection if particle distance is over `dist_max`\nfor i in range(time_step_by_days * nb_days):\n t, xt, yt = p.__next__()\n dt = t / 86400.0 - t0\n check_p(xt, yt, fsle, theta, mask, used, dt, dist_max=dist_max, dist_init=dist_init)\n\n# Get index with original_position\ni = ((x0 - x0_) / step_grid_out).astype(\"i4\")\nj = ((y0 - y0_) / step_grid_out).astype(\"i4\")\nfsle_ = empty(grid_shape, dtype=\"f4\")\ntheta_ = empty(grid_shape, dtype=\"f4\")\nmask_ = ones(grid_shape, dtype=\"bool\")\nfsle_[i, j] = fsle\ntheta_[i, j] = theta\nmask_[i, j] = mask\n# Create a grid object\nfsle_custom = RegularGridDataset.with_array(\n coordinates=(\"lon\", \"lat\"),\n datas=dict(\n fsle=ma.array(fsle_, mask=mask_),\n theta=ma.array(theta_, mask=mask_),\n lon=lon_p,\n lat=lat_p,\n ),\n centered=True,\n)"
120120
]
121121
},
122122
{
@@ -136,6 +136,24 @@
136136
"source": [
137137
"fig = plt.figure(figsize=(13, 5), dpi=150)\nax = fig.add_axes([0.03, 0.03, 0.90, 0.94])\nax.set_xlim(-6, 36.5), ax.set_ylim(30, 46)\nax.set_aspect(\"equal\")\nax.set_title(\"Finite size lyapunov exponent\", weight=\"bold\")\nkw = dict(cmap=\"viridis_r\", vmin=-15, vmax=0)\nm = fsle_custom.display(ax, 1 / fsle_custom.grid(\"fsle\"), **kw)\nax.grid()\ncb = plt.colorbar(m, cax=fig.add_axes([0.94, 0.05, 0.01, 0.9]))"
138138
]
139+
},
140+
{
141+
"cell_type": "markdown",
142+
"metadata": {},
143+
"source": [
144+
"## Display Theta\n\n"
145+
]
146+
},
147+
{
148+
"cell_type": "code",
149+
"execution_count": null,
150+
"metadata": {
151+
"collapsed": false
152+
},
153+
"outputs": [],
154+
"source": [
155+
"fig = plt.figure(figsize=(13, 5), dpi=150)\nax = fig.add_axes([0.03, 0.03, 0.90, 0.94])\nax.set_xlim(-6, 36.5), ax.set_ylim(30, 46)\nax.set_aspect(\"equal\")\nax.set_title(\"Theta from finite size lyapunov exponent\", weight=\"bold\")\nkw = dict(cmap=\"Spectral_r\", vmin=-180, vmax=180)\nm = fsle_custom.display(ax, fsle_custom.grid(\"theta\"), **kw)\nax.grid()\ncb = plt.colorbar(m, cax=fig.add_axes([0.94, 0.05, 0.01, 0.9]))"
156+
]
139157
}
140158
],
141159
"metadata": {

0 commit comments

Comments
 (0)