2
2
"""
3
3
Class to load and manipulate RegularGrid and UnRegularGrid
4
4
"""
5
- import logging
6
5
from datetime import datetime
6
+ import logging
7
7
8
8
from cv2 import filter2D
9
9
from matplotlib .path import Path as BasePath
10
10
from netCDF4 import Dataset
11
- from numba import njit , prange
12
- from numba import types as numba_types
13
- from numpy import (arange , array , ceil , concatenate , cos , deg2rad , empty ,
14
- errstate , exp , float_ , floor , histogram2d , int_ , interp ,
15
- isnan , linspace , ma )
16
- from numpy import mean as np_mean
17
- from numpy import (meshgrid , nan , nanmean , ones , percentile , pi , radians ,
18
- round_ , sin , sinc , where , zeros )
11
+ from numba import njit , prange , types as numba_types
12
+ from numpy import (
13
+ arange ,
14
+ array ,
15
+ ceil ,
16
+ concatenate ,
17
+ cos ,
18
+ deg2rad ,
19
+ empty ,
20
+ errstate ,
21
+ exp ,
22
+ float_ ,
23
+ floor ,
24
+ histogram2d ,
25
+ int_ ,
26
+ interp ,
27
+ isnan ,
28
+ linspace ,
29
+ ma ,
30
+ mean as np_mean ,
31
+ meshgrid ,
32
+ nan ,
33
+ nanmean ,
34
+ ones ,
35
+ percentile ,
36
+ pi ,
37
+ radians ,
38
+ round_ ,
39
+ sin ,
40
+ sinc ,
41
+ where ,
42
+ zeros ,
43
+ )
19
44
from pint import UnitRegistry
20
45
from scipy .interpolate import RectBivariateSpline , interp1d
21
46
from scipy .ndimage import gaussian_filter
26
51
from .. import VAR_DESCR
27
52
from ..data import get_demo_path
28
53
from ..eddy_feature import Amplitude , Contours
29
- from ..generic import (bbox_indice_regular , coordinates_to_local , distance ,
30
- interp2d_geo , local_to_coordinates , nearest_grd_indice ,
31
- uniform_resample )
54
+ from ..generic import (
55
+ bbox_indice_regular ,
56
+ coordinates_to_local ,
57
+ distance ,
58
+ interp2d_geo ,
59
+ local_to_coordinates ,
60
+ nearest_grd_indice ,
61
+ uniform_resample ,
62
+ )
32
63
from ..observations .observation import EddiesObservations
33
- from ..poly import (create_vertice , fit_circle , get_pixel_in_regular ,
34
- poly_area , poly_contain_poly , visvalingam ,
35
- winding_number_poly )
64
+ from ..poly import (
65
+ create_vertice ,
66
+ fit_circle ,
67
+ get_pixel_in_regular ,
68
+ poly_area ,
69
+ poly_contain_poly ,
70
+ visvalingam ,
71
+ winding_number_poly ,
72
+ )
36
73
37
74
logger = logging .getLogger ("pet" )
38
75
@@ -86,7 +123,7 @@ def value_on_regular_contour(x_g, y_g, z_g, m_g, vertices, num_fac=2, fixed_size
86
123
87
124
@njit (cache = True )
88
125
def mean_on_regular_contour (
89
- x_g , y_g , z_g , m_g , vertices , num_fac = 2 , fixed_size = None , nan_remove = False
126
+ x_g , y_g , z_g , m_g , vertices , num_fac = 2 , fixed_size = - 1 , nan_remove = False
90
127
):
91
128
x_val , y_val = vertices [:, 0 ], vertices [:, 1 ]
92
129
x_new , y_new = uniform_resample (x_val , y_val , num_fac , fixed_size )
@@ -406,8 +443,8 @@ def setup_coordinates(self):
406
443
x_name , y_name = self .coordinates
407
444
if self .is_centered :
408
445
# logger.info("Grid center")
409
- self .x_c = self .vars [x_name ].astype ("float64" )
410
- self .y_c = self .vars [y_name ].astype ("float64" )
446
+ self .x_c = array ( self .vars [x_name ].astype ("float64" ) )
447
+ self .y_c = array ( self .vars [y_name ].astype ("float64" ) )
411
448
412
449
self .x_bounds = concatenate ((self .x_c , (2 * self .x_c [- 1 ] - self .x_c [- 2 ],)))
413
450
self .y_bounds = concatenate ((self .y_c , (2 * self .y_c [- 1 ] - self .y_c [- 2 ],)))
@@ -419,8 +456,8 @@ def setup_coordinates(self):
419
456
self .y_bounds [- 1 ] -= d_y [- 1 ] / 2
420
457
421
458
else :
422
- self .x_bounds = self .vars [x_name ].astype ("float64" )
423
- self .y_bounds = self .vars [y_name ].astype ("float64" )
459
+ self .x_bounds = array ( self .vars [x_name ].astype ("float64" ) )
460
+ self .y_bounds = array ( self .vars [y_name ].astype ("float64" ) )
424
461
425
462
if len (self .x_dim ) == 1 :
426
463
self .x_c = self .x_bounds .copy ()
@@ -757,7 +794,7 @@ def eddy_identification(
757
794
758
795
# Test of the rotating sense: cyclone or anticyclone
759
796
if has_value (
760
- data , i_x_in , i_y_in , cvalues , below = anticyclonic_search
797
+ data . data , i_x_in , i_y_in , cvalues , below = anticyclonic_search
761
798
):
762
799
continue
763
800
@@ -788,7 +825,6 @@ def eddy_identification(
788
825
contour .reject = 4
789
826
continue
790
827
if reset_centroid :
791
-
792
828
if self .is_circular ():
793
829
centi = self .normalize_x_indice (reset_centroid [0 ])
794
830
else :
@@ -1285,8 +1321,8 @@ def compute_pixel_path(self, x0, y0, x1, y1):
1285
1321
def clean_land (self , name ):
1286
1322
"""Function to remove all land pixel"""
1287
1323
mask_land = self .__class__ (get_demo_path ("mask_1_60.nc" ), "lon" , "lat" )
1288
- x ,y = meshgrid (self .x_c , self .y_c )
1289
- m = mask_land .interp (' mask' , x .reshape (- 1 ), y .reshape (- 1 ), ' nearest' )
1324
+ x , y = meshgrid (self .x_c , self .y_c )
1325
+ m = mask_land .interp (" mask" , x .reshape (- 1 ), y .reshape (- 1 ), " nearest" )
1290
1326
data = self .grid (name )
1291
1327
self .vars [name ] = ma .array (data , mask = m .reshape (x .shape ).T )
1292
1328
@@ -1310,7 +1346,7 @@ def get_step_in_km(self, lat, wave_length):
1310
1346
min_wave_length = max (step_x_km , step_y_km ) * 2
1311
1347
if wave_length < min_wave_length :
1312
1348
logger .error (
1313
- "wave_length too short for resolution, must be > %d km" ,
1349
+ "Wave_length too short for resolution, must be > %d km" ,
1314
1350
ceil (min_wave_length ),
1315
1351
)
1316
1352
raise Exception ()
@@ -1361,6 +1397,24 @@ def kernel_lanczos(self, lat, wave_length, order=1):
1361
1397
kernel [dist_norm > order ] = 0
1362
1398
return self .finalize_kernel (kernel , order , half_x_pt , half_y_pt )
1363
1399
1400
+ def kernel_loess (self , lat , wave_length , order = 1 ):
1401
+ """
1402
+ https://fr.wikipedia.org/wiki/R%C3%A9gression_locale
1403
+ """
1404
+ order = self .check_order (order )
1405
+ half_x_pt , half_y_pt , dist_norm = self .estimate_kernel_shape (
1406
+ lat , wave_length , order
1407
+ )
1408
+
1409
+ def inc_func (xdist ):
1410
+ f = zeros (xdist .size )
1411
+ f [abs (xdist ) < 1 ] = 1
1412
+ return f
1413
+
1414
+ kernel = (1 - abs (dist_norm ) ** 3 ) ** 3
1415
+ kernel [abs (dist_norm ) > order ] = 0
1416
+ return self .finalize_kernel (kernel , order , half_x_pt , half_y_pt )
1417
+
1364
1418
def kernel_bessel (self , lat , wave_length , order = 1 ):
1365
1419
"""wave_length in km
1366
1420
order must be int
@@ -1638,11 +1692,13 @@ def compute_finite_difference(self, data, schema=1, mode="reflect", vertical=Fal
1638
1692
data1 [- schema :] = nan
1639
1693
data2 [:schema ] = nan
1640
1694
1641
- d = self .EARTH_RADIUS * 2 * pi / 360 * 2 * schema
1695
+ # Distance for one degree
1696
+ d = self .EARTH_RADIUS * 2 * pi / 360
1697
+ # Mulitply by 2 step
1642
1698
if vertical :
1643
- d *= self .ystep
1699
+ d *= self .ystep * 2 * schema
1644
1700
else :
1645
- d *= self .xstep * cos (deg2rad (self .y_c ))
1701
+ d *= self .xstep * cos (deg2rad (self .y_c )) * 2 * schema
1646
1702
return (data1 - data2 ) / d
1647
1703
1648
1704
def compute_stencil (
@@ -1855,7 +1911,7 @@ def speed_coef_mean(self, contour):
1855
1911
return mean_on_regular_contour (
1856
1912
self .x_c ,
1857
1913
self .y_c ,
1858
- self ._speed_ev ,
1914
+ self ._speed_ev . data ,
1859
1915
self ._speed_ev .mask ,
1860
1916
contour .vertices ,
1861
1917
nan_remove = True ,
@@ -1945,7 +2001,7 @@ def interp(self, grid_name, lons, lats, method="bilinear"):
1945
2001
g = self .grid (grid_name )
1946
2002
m = self .get_mask (g )
1947
2003
return interp2d_geo (
1948
- self .x_c , self .y_c , g , m , lons , lats , nearest = method == "nearest"
2004
+ self .x_c , self .y_c , g . data , m , lons , lats , nearest = method == "nearest"
1949
2005
)
1950
2006
1951
2007
def uv_for_advection (
@@ -1981,7 +2037,7 @@ def uv_for_advection(
1981
2037
u = - u
1982
2038
v = - v
1983
2039
m = u .mask + v .mask
1984
- return u , v , m
2040
+ return u . data , v . data , m
1985
2041
1986
2042
def advect (self , x , y , u_name , v_name , nb_step = 10 , rk4 = True , ** kw ):
1987
2043
"""
0 commit comments