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