31
31
from scipy import spatial
32
32
from dateutil import parser
33
33
from numpy import meshgrid , zeros , array , where , ma , argmin , vstack , ones , \
34
- newaxis , sqrt , diff , r_
34
+ newaxis , sqrt , diff , r_ , arange
35
+ from scipy .interpolate import interp1d
35
36
import logging
36
37
from netCDF4 import Dataset
37
38
@@ -60,6 +61,8 @@ class AvisoGrid(BaseData):
60
61
'fillval' ,
61
62
'_angle' ,
62
63
'sla_coeffs' ,
64
+ 'xinterp' ,
65
+ 'yinterp' ,
63
66
'uspd_coeffs' ,
64
67
'__lon' ,
65
68
'__lat' ,
@@ -77,22 +80,37 @@ def __init__(self, aviso_file, the_domain,
77
80
super (AvisoGrid , self ).__init__ ()
78
81
logging .info ('Initialising the *AVISO_grid*' )
79
82
self .grid_filename = aviso_file
80
- self .domain = the_domain
81
- self .lonmin = float (lonmin )
82
- self .lonmax = float (lonmax )
83
- self .latmin = float (latmin )
84
- self .latmax = float (latmax )
85
- self .grid_filename = aviso_file
86
-
83
+
87
84
self .lon_name = lon_name
88
85
self .lat_name = lat_name
89
86
self .grid_name = grid_name
90
87
91
88
self ._lon = self .read_nc (self .lon_name )
92
89
self ._lat = self .read_nc (self .lat_name )
90
+ if the_domain is None :
91
+ self .domain = 'Automatic Domain'
92
+ dlon = abs (self ._lon [1 ] - self ._lon [0 ])
93
+ dlat = abs (self ._lat [1 ] - self ._lat [0 ])
94
+ self .lonmin = float (self ._lon .min ()) + dlon * 2
95
+ self .lonmax = float (self ._lon .max ()) - dlon * 2
96
+ self .latmin = float (self ._lat .min ()) + dlat * 2
97
+ self .latmax = float (self ._lat .max ()) - dlat * 2
98
+ if ((self ._lon [- 1 ] + dlon ) % 360 ) == self ._lon [0 ]:
99
+ self .domain = 'Global'
100
+ self .lonmin = - 100.
101
+ self .lonmax = 290.
102
+ self .latmin = - 80.
103
+ self .latmax = 80.
104
+ else :
105
+ self .domain = the_domain
106
+ self .lonmin = float (lonmin )
107
+ self .lonmax = float (lonmax )
108
+ self .latmin = float (latmin )
109
+ self .latmax = float (latmax )
110
+
93
111
self .fillval = self .read_nc_att (self .grid_name , '_FillValue' )
94
112
95
- if lonmin < 0 and lonmax <= 0 :
113
+ if self . lonmin < 0 and self . lonmax <= 0 :
96
114
self ._lon -= 360.
97
115
self ._lon , self ._lat = meshgrid (self ._lon , self ._lat )
98
116
self ._angle = zeros (self ._lon .shape )
@@ -102,7 +120,7 @@ def __init__(self, aviso_file, the_domain,
102
120
103
121
# zero_crossing, used for handling a longitude range that
104
122
# crosses zero degree meridian
105
- if lonmin < 0 and lonmax >= 0 and 'MedSea' not in self .domain :
123
+ if self . lonmin < 0 and self . lonmax >= 0 and 'MedSea' not in self .domain :
106
124
if ((self .lonmax < self ._lon .max ()) and (self .lonmax > self ._lon .min ()) and (self .lonmin < self ._lon .max ()) and (self .lonmin > self ._lon .min ())):
107
125
pass
108
126
else :
@@ -119,9 +137,15 @@ def __init__(self, aviso_file, the_domain,
119
137
self .get_aviso_f_pm_pn ()
120
138
self .set_u_v_eke ()
121
139
self .shape = self .lon .shape
122
- # pad2 = 2 * self.pad
123
- # self.shape = (self.f_coriolis.shape[0] - pad2,
124
- # self.f_coriolis.shape[1] - pad2)
140
+
141
+ # self.init_pos_interpolator()
142
+
143
+ def init_pos_interpolator (self ):
144
+ self .xinterp = interp1d (self .lon [0 ].copy (), arange (self .lon .shape [1 ]), assume_sorted = True , copy = False , fill_value = (0 , - 1 ), bounds_error = False , kind = 'nearest' )
145
+ self .yinterp = interp1d (self .lat [:, 0 ].copy (), arange (self .lon .shape [0 ]), assume_sorted = True , copy = False , fill_value = (0 , - 1 ), bounds_error = False , kind = 'nearest' )
146
+
147
+ def nearest_indice (self , lon , lat ):
148
+ return self .xinterp (lon ), self .yinterp (lat )
125
149
126
150
def set_filename (self , file_name ):
127
151
self .grid_filename = file_name
@@ -137,7 +161,7 @@ def get_aviso_data(self, aviso_file, dimensions=None):
137
161
if units not in self .KNOWN_UNITS :
138
162
raise Exception ('Unknown units : %s' % units )
139
163
140
- with Dataset (self .grid_filename ) as h_nc :
164
+ with Dataset (self .grid_filename . decode ( 'utf-8' ) ) as h_nc :
141
165
grid_dims = array (h_nc .variables [self .grid_name ].dimensions )
142
166
lat_dim = h_nc .variables [self .lat_name ].dimensions [0 ]
143
167
lon_dim = h_nc .variables [self .lon_name ].dimensions [0 ]
@@ -186,44 +210,6 @@ def set_mask(self, sla):
186
210
sea_label = self .labels [plus9 , plus200 ]
187
211
self .mask += self .labels != sea_label
188
212
189
- def fillmask (self , data , mask ):
190
- """
191
- Fill missing values in an array with an average of nearest
192
- neighbours
193
- From http://permalink.gmane.org/gmane.comp.python.scientific.user/19610
194
- """
195
- raise Exception ('Use convolution to fill data' )
196
- assert data .ndim == 2 , 'data must be a 2D array.'
197
- fill_value = 9999.99
198
- data [mask == 0 ] = fill_value
199
-
200
- # Create (i, j) point arrays for good and bad data.
201
- # Bad data are marked by the fill_value, good data elsewhere.
202
- igood = vstack (where (data != fill_value )).T
203
- ibad = vstack (where (data == fill_value )).T
204
-
205
- # Create a tree for the bad points, the points to be filled
206
- tree = spatial .cKDTree (igood )
207
-
208
- # Get the four closest points to the bad points
209
- # here, distance is squared
210
- dist , iquery = tree .query (ibad , k = 4 , p = 2 )
211
-
212
- # Create a normalised weight, the nearest points are weighted as 1.
213
- # Points greater than one are then set to zero
214
- weight = dist / (dist .min (axis = 1 )[:, newaxis ])
215
- weight *= ones (dist .shape )
216
- weight [weight > 1. ] = 0.
217
-
218
- # Multiply the queried good points by the weight, selecting only the
219
- # nearest points. Divide by the number of nearest points to get average
220
- xfill = weight * data [igood [:, 0 ][iquery ], igood [:, 1 ][iquery ]]
221
- xfill = (xfill / weight .sum (axis = 1 )[:, newaxis ]).sum (axis = 1 )
222
-
223
- # Place average of nearest good points, xfill, into bad point locations
224
- data [ibad [:, 0 ], ibad [:, 1 ]] = xfill
225
- return data
226
-
227
213
@property
228
214
def lon (self ):
229
215
if self .__lon is None :
0 commit comments