66 sin , deg2rad , pi , ones , cos , ma , int8 , histogram2d , arange , float_ , \
77 linspace , errstate , int_ , column_stack , interp , meshgrid , nan , ceil , sinc , float64 , isnan , \
88 floor , percentile , zeros
9+ from numpy .linalg import lstsq
910from datetime import datetime
1011from scipy .special import j1
1112from netCDF4 import Dataset
1415from scipy .spatial import cKDTree
1516from scipy .signal import welch
1617from cv2 import filter2D
17- from numba import jit
18+ from numba import njit , prange
1819from matplotlib .path import Path as BasePath
1920from matplotlib .contour import QuadContourSet as BaseQuadContourSet
2021from pyproj import Proj
2122from pint import UnitRegistry
22- from ..tools import fit_circle_c , distance_vector , winding_number_poly , poly_contain_poly , \
23- distance , distance_point_vector
23+ from ..tools import distance_vector , winding_number_poly , poly_contain_poly , distance , distance_point_vector
2424from ..observations import EddiesObservations
2525from ..eddy_feature import Amplitude , Contours
2626from .. import VAR_DESCR
@@ -115,7 +115,7 @@ def _fit_circle_path(self):
115115
116116 c_x , c_y = proj (self .lon , self .lat )
117117 try :
118- centlon_e , centlat_e , eddy_radius_e , aerr = fit_circle_c (c_x , c_y )
118+ centlon_e , centlat_e , eddy_radius_e , aerr = fit_circle_c_numba (c_x , c_y )
119119 centlon_e , centlat_e = proj (centlon_e , centlat_e , inverse = True )
120120 centlon_e = (centlon_e - lon_mean + 180 ) % 360 + lon_mean - 180
121121 self ._circle_params = centlon_e , centlat_e , eddy_radius_e , aerr
@@ -130,6 +130,74 @@ def _fit_circle_path(self):
130130 self ._circle_params = 0 , - 90 , nan , nan
131131
132132
133+ @njit (cache = True )
134+ def fit_circle_c_numba (x_vec , y_vec ):
135+ nb_elt = x_vec .shape [0 ]
136+ p_inon_x = empty (nb_elt )
137+ p_inon_y = empty (nb_elt )
138+
139+ x_mean = x_vec .mean ()
140+ y_mean = y_vec .mean ()
141+
142+ norme = (x_vec - x_mean ) ** 2 + (y_vec - y_mean ) ** 2
143+ norme_max = norme .max ()
144+ scale = norme_max ** .5
145+
146+ # Form matrix equation and solve it
147+ # Maybe put f4
148+ datas = ones ((nb_elt , 3 ))
149+ datas [:, 0 ] = 2. * (x_vec - x_mean ) / scale
150+ datas [:, 1 ] = 2. * (y_vec - y_mean ) / scale
151+
152+ (center_x , center_y , radius ), residuals , rank , s = lstsq (datas , norme / norme_max )
153+
154+ # Unscale data and get circle variables
155+ radius += center_x ** 2 + center_y ** 2
156+ radius **= .5
157+ center_x *= scale
158+ center_y *= scale
159+ # radius of fitted circle
160+ radius *= scale
161+ # center X-position of fitted circle
162+ center_x += x_mean
163+ # center Y-position of fitted circle
164+ center_y += y_mean
165+
166+ # area of fitted circle
167+ c_area = (radius ** 2 ) * pi
168+
169+ # Find distance between circle center and contour points_inside_poly
170+ for i_elt in range (nb_elt ):
171+ # Find distance between circle center and contour points_inside_poly
172+ dist_poly = ((x_vec [i_elt ] - center_x ) ** 2 + (y_vec [i_elt ] - center_y ) ** 2 ) ** .5
173+ # Indices of polygon points outside circle
174+ # p_inon_? : polygon x or y points inside & on the circle
175+ if dist_poly > radius :
176+ p_inon_y [i_elt ] = center_y + radius * (y_vec [i_elt ] - center_y ) / dist_poly
177+ p_inon_x [i_elt ] = center_x - (center_x - x_vec [i_elt ]) * (center_y - p_inon_y [i_elt ]) / (
178+ center_y - y_vec [i_elt ])
179+ else :
180+ p_inon_x [i_elt ] = x_vec [i_elt ]
181+ p_inon_y [i_elt ] = y_vec [i_elt ]
182+
183+ # Area of closed contour/polygon enclosed by the circle
184+ p_area_incirc = 0
185+ p_area = 0
186+ for i_elt in range (nb_elt - 1 ):
187+ # Indices of polygon points outside circle
188+ # p_inon_? : polygon x or y points inside & on the circle
189+ p_area_incirc += p_inon_x [i_elt ] * p_inon_y [1 + i_elt ] - p_inon_x [i_elt + 1 ] * p_inon_y [i_elt ]
190+ # Shape test
191+ # Area and centroid of closed contour/polygon
192+ p_area += x_vec [i_elt ] * y_vec [1 + i_elt ] - x_vec [1 + i_elt ] * y_vec [i_elt ]
193+ p_area = abs (p_area ) * .5
194+
195+ p_area_incirc = abs (p_area_incirc ) * .5
196+
197+ a_err = (c_area - 2 * p_area_incirc + p_area ) * 100. / c_area
198+ return center_x , center_y , radius , a_err
199+
200+
133201BasePath .fit_circle = fit_circle_path
134202BasePath ._fit_circle_path = _fit_circle_path
135203
@@ -502,12 +570,12 @@ def eddy_identification(self, grid_height, uname, vname, date, step=0.005, shape
502570 # First, get position based on innermost
503571 # contour
504572 c_x , c_y = proj (inner_contour .lon , inner_contour .lat )
505- centx_s , centy_s , _ , _ = fit_circle_c (c_x , c_y )
573+ centx_s , centy_s , _ , _ = fit_circle_c_numba (c_x , c_y )
506574 centlon_s , centlat_s = proj (centx_s , centy_s , inverse = True )
507575 # Second, get speed-based radius based on
508576 # contour of max uavg
509577 c_x , c_y = proj (speed_contour .lon , speed_contour .lat )
510- _ , _ , eddy_radius_s , aerr_s = fit_circle_c (c_x , c_y )
578+ _ , _ , eddy_radius_s , aerr_s = fit_circle_c_numba (c_x , c_y )
511579
512580 # Instantiate new EddyObservation object
513581 properties = EddiesObservations (size = 1 , track_extra_variables = track_extra_variables ,
@@ -1192,26 +1260,26 @@ def interp(self, grid_name, lons, lats):
11921260 new z
11931261 """
11941262 z = empty (lons .shape , dtype = 'f4' ).reshape (- 1 )
1195- g = self .grid (grid_name ). astype ( 'f4' )
1263+ g = self .grid (grid_name )
11961264 interp_numba (
1197- self .x_c . astype ( 'f4' ) ,
1198- self .y_c . astype ( 'f4' ) ,
1265+ self .x_c ,
1266+ self .y_c ,
11991267 g ,
1200- lons .reshape (- 1 ). astype ( 'f4' ) ,
1201- lats .reshape (- 1 ). astype ( 'f4' ) ,
1268+ lons .reshape (- 1 ),
1269+ lats .reshape (- 1 ),
12021270 z ,
12031271 g .fill_value
12041272 )
12051273 return z
12061274
12071275
1208- @jit ( "void(f4[:], f4[:], f4[:,:], f4[:], f4[:], f4[:], f4)" , nopython = True )
1276+ @njit ( parralel = True , cache = True )
12091277def interp_numba (x_g , y_g , z , x , y , dest_z , fill_value ):
12101278 x_ref = x_g [0 ]
12111279 y_ref = y_g [0 ]
12121280 x_step = x_g [1 ] - x_ref
12131281 y_step = y_g [1 ] - y_ref
1214- for i in range (x .size ):
1282+ for i in prange (x .size ):
12151283 x_ = (x [i ] - x_ref ) / x_step
12161284 y_ = (y [i ] - y_ref ) / y_step
12171285 i0 = int (floor (x_ ))
0 commit comments