def crop(self, w=DEFAULT_CROP, h=DEFAULT_CROP): cropped_area = create_area_def("ci_crop", { "proj": "lcc", "ellps": "WGS84", "lat_0": self.eye_lat, "lat_1": self.eye_lat, "lon_0": self.eye_lon }, center=(self.eye_lon, self.eye_lat), radius=(w / 2, h / 2), units="degrees", resolution=DataArray( 400, attrs={"units": "meters"})) print( cropped_area.overlap_rate(self.bb_area()) * (self.bb_area().get_area() / cropped_area.get_area())) assert cropped_area.overlap_rate(self.bb_area()) * ( self.bb_area().get_area() / cropped_area.get_area()) > 0.8 self.scene = self.scene.resample(self.bb_area()) self.scene = self.scene.crop(area=cropped_area) self.raw_grid_I5 = self.scene["I05_mask"].values self.raw_grid_I4 = self.scene["I04_mask"].values self.zenith = self.scene["i_solar_zenith_angle"].values self.satz = np.cos(np.deg2rad( self.scene["i_satellite_zenith_angle"])).values self.raz = np.abs(self.scene["i_satellite_azimuth_angle"] - self.scene["i_solar_azimuth_angle"]).values
def test_get_bucket_indices(self): """Test calculation of array indices.""" # Ensure nothing is calculated with dask.config.set(scheduler=CustomScheduler(max_computes=0)): self.resampler._get_indices() x_idxs, y_idxs = da.compute(self.resampler.x_idxs, self.resampler.y_idxs) np.testing.assert_equal(x_idxs, np.array([1710, 1710, 1707, 1705])) np.testing.assert_equal(y_idxs, np.array([465, 465, 459, 455])) # Additional small test case adef = create_area_def(area_id='test', projection={'proj': 'latlong'}, width=2, height=2, center=(0, 0), resolution=10) lons = da.from_array(np.array( [-10.0, -9.9, -0.1, 0, 0.1, 9.9, 10.0, -10.1, 0]), chunks=2) lats = da.from_array(np.array( [-10.0, -9.9, -0.1, 0, 0.1, 9.9, 10.0, 0, 10.1]), chunks=2) resampler = bucket.BucketResampler(source_lats=lats, source_lons=lons, target_area=adef) resampler._get_indices() np.testing.assert_equal(resampler.x_idxs, np.array([-1, 0, 0, 1, 1, 1, -1, -1, -1])) np.testing.assert_equal(resampler.y_idxs, np.array([-1, 1, 1, 1, 0, 0, -1, -1, -1]))
def join_areadefs(*areas): """Join one or more areadefinitions. For a collection of areadefinitions sharing a projection and resolution, create the smallest area definition that encompasses all. """ # also at https://github.com/pytroll/pyresample/pull/306 first = None if len(areas) == 0: raise TypeError("Must pass at least one area, found zero.") for area in areas: if first is None: first = area largest_extent = list(area.area_extent) else: if not area.proj_dict == first.proj_dict: raise ValueError("Inconsistent projections between areas") if not numpy.isclose(area.resolution, first.resolution).all(): raise ValueError("Inconsistent resolution between areas") largest_extent[0] = min(largest_extent[0], area.area_extent[0]) largest_extent[1] = min(largest_extent[1], area.area_extent[1]) largest_extent[2] = max(largest_extent[2], area.area_extent[2]) largest_extent[3] = max(largest_extent[3], area.area_extent[3]) return pyresample.create_area_def(area_id="joint-area", projection=first.proj_dict, units=first.proj_dict["units"], area_extent=largest_extent, resolution=first.resolution)
def create_areadefinition_from_yaml(yamlfile, sector): '''Take a YAML with misc metadata and create a pyresample areadefinition Misc. metadata will be parsed from the YAML file and manually added to the areadefinition Args: yamlfile : string full path to YAML area definition file sector : string name of sector Returns: (obj) : pyresample areadefinition object ''' import pyresample import yaml with open(yamlfile, 'r') as f: sectorfile_yaml = yaml.load(f, Loader=yaml.FullLoader) sector_info = sectorfile_yaml[sector] area_id = sector description = sector_info.pop('description') projection = sector_info.pop('projection') resolution = sector_info.pop('resolution') shape = sector_info.pop('shape') area_extent = sector_info.pop('area_extent') # Create the pyresample area definition shape_list = [shape['height'],shape['width']] extent_list = [] extent_list.extend(area_extent['lower_left_xy']) extent_list.extend(area_extent['upper_right_xy']) area_def = pyresample.create_area_def(area_id=area_id, description=description, projection=projection, resolution=resolution, shape=shape_list, area_extent=extent_list) # Manually add the metadata to area_def for key in sector_info.keys(): area_def.__setattr__(key, sector_info[key]) return area_def
def test_area_epsg4326(): """Test with EPSG4326 (latlong) area, which has no CRS coordinate operation.""" from pyproj import CRS shp = (16, 8) euro4326 = create_area_def("epgs4326europa", CRS.from_epsg(4326), resolution=1 / 128, shape=shp, center=(0, 0)) return euro4326
def test_area_merc(): """Create a mercator area.""" from pyproj import CRS shp = (20, 10) test_area = create_area_def("test-area-merc", CRS("+proj=merc"), units="m", shape=shp, resolution=1000, center=(0.0, 0.0)) return test_area
def test_area_weird(): """Create a weird area (interrupted goode homolosine) to test error handling.""" from pyproj import CRS shp = (20, 10) test_area = create_area_def("test-area-north-stereo", CRS("+proj=igh"), units="m", shape=shp, resolution=1000, center=(0.0, 1500000.0)) return test_area
def test_area_small_eqc_wgs84(): """Create 50x100 test equirectangular area centered on (50, 90), wgs84.""" shp = (50, 100) test_area = create_area_def("test-area-eqc-wgs84", { "proj": "eqc", "lat_0": 2.5, "lon_0": 1., "ellps": "WGS84" }, units="m", shape=shp, resolution=1000, center=(10000000.0, 6000000.0)) return test_area
def test_area_northpole(): """Create a 20x10 test area centered exactly on the north pole. This has no well-defined central meridian so needs separate testing. """ shp = (20, 10) test_area = create_area_def("test-area-north-pole", { "proj": "stere", "lat_0": 90, "lat_ts": 60, "ellps": "WGS84" }, shape=shp, resolution=1000, center=(0.0, 15000000.0)) return test_area
def fake_multiscene4(): """Like fake_multiscene2, but with varying areas (none stacked).""" from satpy.dataset.dataid import WavelengthRange from satpy.tests.utils import make_dataid common_attrs = {} wl = { "C08": WavelengthRange(5.7, 6.2, 6.7), "C10": WavelengthRange(6.8, 7.3, 7.8), "C14": WavelengthRange(10, 11, 12) } content = { make_dataid(name=x, wavelength=wl.get(x)): numpy.arange(5 * 5).reshape(5, 5) for x in ("C08", "C10", "C14") } content[make_dataid( name="flash_extent_density")] = numpy.arange(5 * 5).reshape(5, 5) + 1 areas = [ pyresample.create_area_def("test-area", { "proj": "eqc", "lat_ts": 0, "lat_0": 0, "lon_0": 0, "x_0": 0, "y_0": 0, "ellps": "sphere", "units": "m", "no_defs": None, "type": "crs" }, units="m", shape=(5, 5), resolution=1000, center=(10 * i, 20 * i)) for i in range(3) ] aids = [0, 0, 0, 0, 0, 0, 1, 1, 1, 2] scenes = [ satpy.tests.utils.make_fake_scene(content.copy(), common_attrs=common_attrs, area=areas[i]) for i in aids ] for (i, sc) in enumerate(scenes): for da in sc.values(): da.attrs["start_time"] = datetime.datetime(1900, 1, 1, 0, i) da.attrs["end_time"] = datetime.datetime(1900, 1, 1, 0, i + 1) return satpy.MultiScene(scenes)
def test_area_tiny_stereographic_wgs84(): """Create a 20x10 test stereographic area centered near the north pole, wgs84.""" shp = (20, 10) test_area = create_area_def("test-area-north-stereo", { "proj": "stere", "lat_0": 75.0, "lon_0": 2.0, "lat_ts": 60.0, "ellps": "WGS84", "units": "m", "type": "crs" }, units="m", shape=shp, resolution=1000, center=(0.0, 1500000.0)) return test_area
def test_area_tiny_eqc_sphere(): """Create 10x00 test equirectangular area centered on (40, -30), spherical geoid, m.""" shp = (10, 20) test_area = create_area_def("test-area-eqc-sphere", { "proj": "eqc", "lat_ts": 0., "lat_0": 0., "lon_0": 0., "x_0": 0., "y_0": 0., "ellps": "sphere", "units": "m", "no_defs": None, "type": "crs" }, units="m", shape=shp, resolution=1000, center=(-3330000.0, 4440000.0)) return test_area
def resample(gem, variable, res, nx, ny, timestep): if not isinstance(variable, list): variable = [variable] # Open with xarray xref = gem # Load 2D lat and lon lat2d = xref.gridlat_0.values lon2d = xref.gridlon_0.values # Define the original swath required by pyresample orig_def = pyresample.geometry.SwathDefinition(lons=lon2d, lats=lat2d) #### # Definition of the target grid ### # Definition of the Canadian LCC projection (https://spatialreference.org/ref/esri/canada-lambert-conformal-conic/) proj_dict = { 'proj': 'lcc', 'lat_1': 50, 'lat_2': 70, 'lat_0': 40, 'lon_0': -96, 'x_0': 0, 'y_0': 0, 'ellps': 'GRS80', 'datum': 'NAD83', 'units': 'm' } #Name of the grid area_id = 'test_kan' # Coordinate of the upper left corner of the grid lat_upl = lat2d.max() lon_upl = lon2d.min() # Conversion from WGS84 lat/lon to coordinates in the Canadian LCC projection transformer = Transformer.from_crs( "EPSG:4326", "+proj=lcc +lat_1=50 +lat_2=70 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs", always_xy=True) xupl, yupl = transformer.transform(lon_upl, lat_upl) # Definition of the targert grid according to pyresample targ_def = pyresample.create_area_def(area_id, proj_dict, shape=(nx, ny), upper_left_extent=(xupl, yupl), resolution=(res, res), description='Test LCC') # Get the lat and lon corresponding to targ_def grid # Maybe needed in the wrf_out.nc file?? lons, lats = targ_def.get_lonlats() #different interp methods for the regrid # # Nearest neighbor interpolation # t_nearest = pyresample.kd_tree.resample_nearest(orig_def, tgem, \ # targ_def, radius_of_influence=500000, fill_value=None) # # Bilinear interpolation # t_bil = pyresample.bilinear.resample_bilinear(tgem, orig_def, targ_def) resampled_gem = {} for var in variable: # Load variable to be interpolated (temperature here) ingem = xref[var].values[timestep, :, :] # IDW interpolation wf = lambda r: 1 / r**2 resampled_gem[var] = pyresample.kd_tree.resample_custom( orig_def, ingem, targ_def, radius_of_influence=500000, neighbours=10, weight_funcs=wf, fill_value=None) resampled_gem[var] = np.flip(resampled_gem[var], axis=0) return targ_def, resampled_gem
def _bin_spatial(self, num_lat, lat_from, lat_step, num_lon, lon_from, lon_step, proj=None): # When loading file, keep list of indexes for each data file. Then bin in chunks, with each # chunk becoming a layer in the result data set. if 'SO2_column_number_density_validity' in self._file_data: # Validity is not valid for gridded data. del self._file_data['SO2_column_number_density_validity'] # Make sure everything is correctly typed num_lat = int(num_lat) - 1 lat_from = float(lat_from) lat_step = float(lat_step) lat_to = lat_from + (num_lat * lat_step) num_lon = int(num_lon) - 1 lon_from = float(lon_from) lon_step = float(lon_step) lon_to = lon_from + (num_lon * lon_step) if lon_to > 180: # Shift 360 degrees. With my changes, pyresample can cross the dateline to the # negitive, but not to the positive. lon_from -= 360 lon_to -= 360 # try gridding the data area_extent = (lon_from, lat_from, lon_to, lat_to) if isinstance(proj, str): proj = pickle.loads(bytes.fromhex(proj)) proj_dict = proj if proj else { 'proj': 'lonlat', 'over': True, 'preserve_units': False, } target_def = create_area_def("Binned", proj_dict, area_extent=area_extent, shape=(num_lat, num_lon)) target_lons, target_lats = target_def.get_lonlats() # Fix "out-of-bounds" lons if proj is None: target_lons[target_lons < -180] = 180 - ( -1 * (target_lons[target_lons < -180] + 180)) # get "bounds" left_bounds = target_lons - target_def.pixel_size_x / 2 right_bounds = target_lons + target_def.pixel_size_x / 2 top_bounds = target_lats + target_def.pixel_size_y / 2 bottom_bounds = target_lats - target_def.pixel_size_y / 2 lon_bounds = numpy.stack([left_bounds, right_bounds], axis=2) lat_bounds = numpy.stack([bottom_bounds, top_bounds], axis=2) lats = numpy.repeat(lat_bounds, 2, axis=2) lons = numpy.stack( [lon_bounds, numpy.flip(lon_bounds, axis=2)], axis=2) lons.shape = (lon_bounds.shape[0], lon_bounds.shape[1], 4) # Pre-allocate memory for final result binned_file_data = None results = [] for file_idx, stop in enumerate(self._file_idxs): try: kill = signaller.load_queue.get_nowait() except queue.Empty: pass # Nothng to get else: if kill: _TERM_FLAG.set() if _TERM_FLAG.is_set(): return if file_idx == 0: start = 0 else: start = self._file_idxs[file_idx - 1] results.append(self._bin_file((start, stop), target_def)) for idx, binned_data in enumerate(results): signaller.status.emit( f"Stacking Data ({idx}/{len(self._file_idxs)})...", idx, len(self._file_idxs)) binned_data.coords['latitude'] = (('x', 'y'), target_lats) binned_data.coords['longitude'] = (('x', 'y'), target_lons) binned_data.coords['latitude_bounds'] = (('x', 'y', 'corners'), lats) binned_data.coords['longitude_bounds'] = (('x', 'y', 'corners'), lons) if binned_file_data is None: binned_file_data = binned_data else: binned_file_data = xarray.concat( [binned_file_data, binned_data], 'file') self._file_data = binned_file_data
def colorplot_with_band(self, band, HSD_Dir, imgFile, *args, axLatRange=[20, 60], axLonRange=[90, 140], cmap=None, pixels=100, **kwargs): """ colorplot the variables together with radiance data. Parameters ---------- band: int band number [1-16]. See band specification in `../doc/2018_A_Yamashita.md` HSD_Dir: str path for hosting the HSD files. imgFile: str filename of the exported image Keywords -------- axLatRange: list latitude range of the plot (default: [20, 60]). [degree] axLonRange: list longitude range of the plot (default: [90, 140]). [degree] cmap: str colormap name. pixels: int resampled pixels of the band data (default: 100). Take care of time consumption when pixels > 1000! History ------- 2020-02-24 First version. """ files = find_files_and_readers( start_time=(self.mTime - dt.timedelta(seconds=300)), end_time=(self.mTime + dt.timedelta(seconds=300)), base_dir=HSD_Dir, reader='ahi_hsd') matched_files = [] for file in files['ahi_hsd']: if fnmatch.fnmatch( os.path.basename(file), 'HS_H08_*_B{0:02d}_FLDK_*_S0[1234]*DAT*'.format(band)): matched_files.append(file) h8_scene = Scene(filenames=matched_files, reader='ahi_hsd', sensor='ahi') band_label = 'B{0:02d}'.format(band) h8_scene.load([band_label]) roi = create_area_def('roi', { 'proj': 'eqc', 'ellps': 'WGS84' }, width=pixels, height=pixels, area_extent=[ axLonRange[0], axLatRange[0], axLonRange[1], axLatRange[1] ], units='degrees') roi_scene = h8_scene.resample(roi) # read China boundaries with open(os.path.join(PROJECTDIR, 'include', 'CN-border-La.dat'), 'r') as fd: context = fd.read() blocks = [cnt for cnt in context.split('>') if len(cnt) > 0] borders = [ np.fromstring(block, dtype=float, sep=' ') for block in blocks ] LON, LAT = np.meshgrid(self.lon, self.lat) fig = plt.figure(figsize=[8, 8]) plt.tight_layout(False) # Set projection and plot the main figure ax1 = plt.axes([0.1, 0.1, 0.8, 0.8], projection=ccrs.PlateCarree()) # Add ocean, land, rivers and lakes ax1.add_feature(cfeature.OCEAN.with_scale('50m')) ax1.add_feature(cfeature.LAND.with_scale('50m')) ax1.add_feature(cfeature.RIVERS.with_scale('50m')) ax1.add_feature(cfeature.LAKES.with_scale('50m')) # Plot border lines for line in borders: ax1.plot(line[0::2], line[1::2], '-', lw=1, color='k', transform=ccrs.Geodetic()) # loading colormap if cmap is None: cmap = chiljet_colormap() # Plot gridlines crs = roi.to_cartopy_crs() pcmesh_band = ax1.imshow(roi_scene[band_label], transform=crs, origin='upper', extent=crs.bounds, cmap='Greys') pcmesh = ax1.pcolormesh(LON, LAT, self.data, vmin=kwargs['vmin'], vmax=kwargs['vmax'], cmap=cmap, transform=ccrs.PlateCarree()) ax1.set_xticks( np.linspace(axLonRange[0], axLonRange[1], 5, endpoint=True)) ax1.set_yticks( np.linspace(axLatRange[0], axLatRange[1], 5, endpoint=True)) lon_formatter = LongitudeFormatter(number_format='.1f', degree_symbol='', dateline_direction_label=True) lat_formatter = LatitudeFormatter(number_format='.1f', degree_symbol='') ax1.xaxis.set_major_formatter(lon_formatter) ax1.yaxis.set_major_formatter(lat_formatter) ax1.set_ylim(axLatRange) ax1.set_xlim(axLonRange) ax1.set_title('{0} {1}'.format( self.mTime.strftime('%Y-%m-%d %H:%M (Himawari-8)'), self.long_name)) if 'cb_ticks' not in kwargs.keys(): kwargs['cb_ticks'] = np.linspace(kwargs['vmin'], kwargs['vmax'], 5, endpoint=True) cbar = fig.colorbar(pcmesh, fraction=0.03, ticks=kwargs['cb_ticks'], orientation='vertical') cbar.ax.tick_params(direction='out', labelsize=15, pad=5) cbar.ax.set_title(self.unit, fontsize=10) if 'cb_ticklabels' in kwargs.keys(): cbar.ax.set_yticklabels(kwargs['cb_ticklabels']) # Show figure # plt.show() plt.savefig(imgFile) plt.close()
#################### msg_area = geometry.AreaDefinition( 'msg_full', 'Full globe MSG1 image 41.5 degrees', 'msg_full', { 'a': '6378137.000000', 'b': '6356752.300000', 'h': '35785863.000000', 'lon_0': '41.500000', 'proj': 'geos' }, 3712, 3712, [ -5570248.477339261, -5567248.074173444, 5567248.074173444, 5570248.477339261 ]) area_def = create_area_def('my_area', { 'proj': 'latlong', 'lon_0': 0 }, area_extent=[-180, -90, 180, 90], resolution=0.1, units='degrees', description='Global 1x1 degree lat-lon grid') #area_def = load_area('/home/NCMRWFTEMP/vsprasad/EXP_HY2B/validation/crr/areas.yaml', 'IndianOcean_latlon_SC300') ########## ########## Basemap #area_def = pr.utils.load_area('areas.cfg', 'pc_world') #####bmap = pr.plot.area_def2basemap(area_def) ################### #area_def, cf_info = load_cf_area('/home/NCMRWFTEMP/vsprasad/EXP_HY2B/validation/crr/xxx.nc') #x = xr.open_dataset('/home/NCMRWFTEMP/vsprasad/EXP_HY2B/validation/crr/xxx.nc') #llon = x.lon.values #llat = x.lat.values #xgrid = x.lat.values.shape[0]
def make_fake_scene(content_dict, daskify=False, area=True, common_attrs=None): """Create a fake Scene. Create a fake Scene object from fake data. Data are provided in the ``content_dict`` argument. In ``content_dict``, keys should be strings or DatasetID/DataID, and values may be either numpy.ndarray or xarray.DataArray, in either case with exactly two dimensions. The function will convert each of the numpy.ndarray objects into an xarray.DataArray and assign those as datasets to a Scene object. A fake AreaDefinition will be assigned for each array, unless disabled by passing ``area=False``. When areas are automatically generated, arrays with the same shape will get the same area. This function is exclusively intended for testing purposes. If regular ndarrays are passed and the keyword argument daskify is True, DataArrays will be created as dask arrays. If False (default), regular DataArrays will be created. When the user passes xarray.DataArray objects then this flag has no effect. Args: content_dict (Mapping): Mapping where keys correspond to objects accepted by ``Scene.__setitem__``, i.e. strings or DatasetID, and values may be either ``numpy.ndarray`` or ``xarray.DataArray``. daskify (bool): optional, to use dask when converting ``numpy.ndarray`` to ``xarray.DataArray`. No effect when the values in ``content_dict`` are already ``xarray.DataArray`. area (bool or BaseDefinition): Can be ``True``, ``False``, or an instance of ``pyresample.geometry.BaseDefinition`` such as ``AreaDefinition`` or ``SwathDefinition``. If ``True``, which is the default, automatically generate areas. If ``False``, values will not have assigned areas. If an instance of ``pyresample.geometry.BaseDefinition``, those instances will be used for all generated fake datasets. Warning: Passing an area as a string (``area="germ"``) is not supported. common_attrs (Mapping): optional, additional attributes that will be added to every dataset in the scene. Returns: Scene object with datasets corresponding to content_dict. """ import pyresample import satpy import xarray as xr if common_attrs is None: common_attrs = {} if daskify: import dask.array sc = satpy.Scene() for (did, arr) in content_dict.items(): extra_attrs = common_attrs.copy() if isinstance(area, pyresample.geometry.BaseDefinition): extra_attrs["area"] = area elif area: extra_attrs["area"] = pyresample.create_area_def("test-area", { "proj": "eqc", "lat_ts": 0, "lat_0": 0, "lon_0": 0, "x_0": 0, "y_0": 0, "ellps": "sphere", "units": "m", "no_defs": None, "type": "crs" }, units="m", shape=arr.shape, resolution=1000, center=(0, 0)) if isinstance(arr, xr.DataArray): sc[did] = arr.copy() # don't change attributes of input sc[did].attrs.update(extra_attrs) else: if daskify: arr = dask.array.from_array(arr) sc[did] = xr.DataArray(arr, dims=("y", "x"), attrs=extra_attrs) return sc
def get_scene_obj(file_list, latlon_extent, width=750, height=750, tmp_cache=False, resample_method='native_bilinear'): """Get Scene object, apply the resample area, to a small box centered on the lat lon point. inputs: file_list: list of netCDF L1b ABI files, must contain bands 1,2,3 latlon_extent: extent of displayed region in latlon: [min_lon, min_lat, max_lon, max_lat] width: number of resampled image pixels in width (x-dimension) height: number of resampled image pixels in width (y-dimension) tmp_cache: optional keyword, set to True to copy the located files to a temporary dir (from tempfile) before loading. Note the temporary files are NOT cleaned up. Use this option if the data_home access is slow or limited in some way, which can be mitigated by copying to a temp file on the local filesystem resample_method: string keyword to specify the resampling method. valid options are: nearest: perform nearest neighbor resampling in one step bilinear: perform bilinear interpolation in one step native_nearest: perform a native interpolation first, to upsample lower resolution bands to the highest native resolution; then perform nearest neighbor interpolation to the output grid. native_nearest: perform a native interpolation first, to upsample lower resolution bands to the highest native resolution; then perform bilinear interpolation to the output grid. outputs: the satpy Scene object. """ valid_resample_methods = [ 'nearest', 'bilinear', 'native_nearest', 'native_bilinear' ] if resample_method not in valid_resample_methods: raise ValueError('resample_method ' + resample_method + ' is not valid') if tmp_cache: tdir = tempfile.mkdtemp() cached_file_list = [] for f in file_list: src_f = f dst_f = os.path.join(tdir, os.path.split(f)[-1]) shutil.copyfile(src_f, dst_f) cached_file_list.append(dst_f) scn = Scene(reader='abi_l1b', filenames=cached_file_list) else: scn = Scene(reader='abi_l1b', filenames=file_list) scn.load(['true_color']) my_area = pyresample.create_area_def('testC', {'proj': 'eqc'}, width=width, height=height, area_extent=latlon_extent, units='degrees') if resample_method.startswith('native'): tmp_scn = scn.resample(resampler='native') else: tmp_scn = scn # this would split the second string str1_str2, # or just return the str if there is no underscore. # thus, it should be the resample method after the # optional native resampling. method = resample_method.split('_')[-1] new_scn = tmp_scn.resample(my_area, resampler=method) return new_scn
def sentinel3_olci(inpath, extent, epsg, user_list=[], resolution=300,): """Read an S3 OLCI image. Open a Sentinel-3 OLCI image based on the path to the SEN3 folder. The image is cropped to the extent provided as an input and reprojected to the given EPSG code. The user can specify a list of bands to process and a resolution. :param inpath: Path to the Sentinel-3 OLCI image :type inpath: pathlib.PosixPath :param extent: Polygon setting the extent of the Scene to process :type extent: osgeo.ogr.Geometry :param epsg: EPSG code of the projection for the image :type epsg: int :param user_list: List of bandnames to process :type user_list: list, optional :param resolution: Resolution of the image to resample the image to :type resolution: int, optional :return: The satellite data stored in a class :rtype: redress.inputs.products.Sat """ # Open the image s3_prod = open_generic_product(inpath) # Check if the product overlaps the extent of the file s3_extents = gdal_ops.build_poly_from_coords(image_extents(s3_prod)) if not gdal_ops.geom_contains(s3_extents, extent): raise ValueError("The chosen bounding box is not entirely inside the" " provided Satellite image!") # If the user selects all bands, set a list containing all band names if not user_list: user_list = fetch_bandnames(s3_prod) else: # Check if bands are in the product if not set(user_list).issubset(fetch_bandnames(s3_prod)): raise ValueError("Selected bands are not in product!") # Load all bands for the resampling s3_prod.load(user_list) # Set parameters for the resampling stage image_extent = gdal_ops.corner_coords_from_poly(extent, out_epsg=2154) area_def = create_area_def("reprojection", "EPSG:%s" % epsg, area_extent=image_extent, units="metres", resolution=300, ) # Resample product s3_resampled = s3_prod.resample(area_def, resampler="nearest") # Instantiate class s3_data = Sat() # Feed the class with data s3_data.meta["path"] = inpath # Get radiance bands from product and import to the S3 class for band in user_list: # Get radiance bands if "Oa" in band: # Load radiance band s3_resampled.load([band]) # Fetch data from band s3_data.bands[band] = s3_resampled[band] # Get band name s3_data.meta["bandlist"].append(band) # Get band wavelength center s3_data.meta["wavelengths"].append( s3_resampled[band].wavelength[1] * 1000) # Get solar and viewing bands from the S3 product elif band in ["satellite_azimuth_angle", "satellite_zenith_angle", "solar_azimuth_angle", "solar_zenith_angle"]: # Load and import band s3_resampled.load([band]) s3_data.angles[band] = s3_resampled[band] # Correct for the particularity of the VAA band in S3 OLCI # (flipped on one side of nadir) negative_array = \ s3_data.angles["satellite_azimuth_angle"].where( s3_data.angles["satellite_azimuth_angle"] < 0) positive_array = \ s3_data.angles["satellite_azimuth_angle"].where( s3_data.angles["satellite_azimuth_angle"] > 0) # Replace negative values by substracting 180 by the positive value negative_array = negative_array + 180 # Merge arrays s3_data.angles["satellite_azimuth_angle"] = \ positive_array.fillna(negative_array) # Rename angle bands for consistency s3_data.angles = s3_data.angles.rename({"satellite_azimuth_angle": "VAA", "satellite_zenith_angle": "VZA", "solar_azimuth_angle": "SAA", "solar_zenith_angle": "SZA"}, ) # Convert to radians for band in ["SZA", "SAA", "VZA", "VAA"]: s3_data.angles[band].data = xr.ufuncs.deg2rad(s3_data.angles[band]) s3_data.angles[band].attrs["units"] = "radians" s3_data.meta["angles"].append(band) # Get/Set Geotransform ulxy = image_extents(s3_resampled, epsg=2154)[2] s3_data.geotransform = (ulxy[0], resolution, 0.0, ulxy[1], 0.0, -resolution) return s3_data
def get_eye(start_point, end_point): lat_0, lat_1 = start_point["USA_LAT"], end_point["USA_LAT"] lon_0, lon_1 = start_point["USA_LON"], end_point["USA_LON"] try: files, urls = get_data(DATA_DIRECTORY, start_point["ISO_TIME"].to_pydatetime(), end_point["ISO_TIME"].to_pydatetime(), north=max(lat_0, lat_1) + DEFAULT_MARGIN, south=min(lat_0, lat_1) - DEFAULT_MARGIN, east=wrap(max(lon_0, lon_1) + DEFAULT_MARGIN), west=wrap(min(lon_0, lon_1) - DEFAULT_MARGIN), dayOrNight="D") except FileNotFoundError: return None raw_scene = Scene(filenames=files, reader="viirs_l1b") raw_scene.load( ["I04", "I05", "i_lat", "i_lon", "i_satellite_azimuth_angle"]) t = raw_scene.start_time - start_point["ISO_TIME"].to_pydatetime() metadata = interpolate(start_point, end_point, t) eye_radius = metadata["USA_RMW"] / 60 # core_area = create_area_def("core_eye",{ # "proj":"lcc","ellps":"WGS84","lat_0":metadata["USA_LAT"],"lon_1":metadata["USA_LON"]},units="degrees", # # }) first_pass = create_area_def("first_pass", { "proj": "lcc", "ellps": "WGS84", "lat_0": metadata["USA_LAT"], "lon_0": metadata["USA_LON"], "lat_1": metadata["USA_LAT"] }, units="degrees", resolution=RESOLUTION_DEF, area_extent=[ metadata["USA_LON"] - 2 * eye_radius, metadata["USA_LAT"] - 2 * eye_radius, metadata["USA_LON"] + 2 * eye_radius, metadata["USA_LAT"] + 2 * eye_radius ]) cropped_scene = raw_scene.resample(first_pass) centered_lon, centered_lat = first_pass.get_lonlat(*np.unravel_index( cropped_scene["I05"].values.argmax(), cropped_scene["I05"].shape)) recentered_area = create_area_def("better_eye_area", { "proj": "lcc", "ellps": "WGS84", "lat_0": centered_lat, "lon_0": centered_lon, "lat_1": centered_lat }, units="degrees", resolution=RESOLUTION_DEF, area_extent=[ centered_lon - 2 * eye_radius, centered_lat - 2 * eye_radius, centered_lon + 2 * eye_radius, centered_lat + 2 * eye_radius ]) new_scene = raw_scene.resample(recentered_area) return CycloneSnapshot(new_scene["I04"].values, new_scene["I05"].values, recentered_area.pixel_size_x, recentered_area.pixel_size_y, new_scene["i_satellite_azimuth_angle"].values, metadata, b_lon=centered_lon - 2 * eye_radius, b_lat=centered_lat - 2 * eye_radius)