Example #1
0
    def test_get_time(self):
        n1 = Nansat(self.test_file_gcps, logLevel=40)
        t = n1.get_time()

        self.assertEqual(len(t), len(n1.bands()))
        self.assertEqual(type(t[0]), datetime.datetime)
Example #2
0
    def test_get_time(self):
        n1 = Nansat(self.test_file_gcps, logLevel=40)
        t = n1.get_time()

        self.assertEqual(len(t), len(n1.bands()))
        self.assertEqual(type(t[0]), datetime.datetime)
Example #3
0
class SARWind(Nansat, object):
    '''
    A class for calculating wind speed from SAR images using CMOD
    '''

    def __init__(self, sar_image, winddir=None, pixelsize=500):
        '''
            Parameters
            -----------
            sar_image : string or Nansat object
                SAR image filename (original, raw file)
            winddir : int, string, Nansat, None
                Auxiliary wind field information needed to calculate
                SAR wind (must be or have wind direction)
        '''
        if isinstance(sar_image, str) or isinstance(sar_image, unicode):
            super(SARWind, self).__init__(sar_image)
        elif isinstance(sar_image, Nansat):
            super(SARWind, self).__init__(domain=sar_image)
            self.vrt = sar_image.vrt

        # Check that this is a SAR image with VV pol NRCS
        try:
            self.sigma0_bandNo = self._get_band_number(
                            {'standard_name': 
            'surface_backwards_scattering_coefficient_of_radar_wave', 
                            'polarization': 'VV'})
        except:
            raise TypeError(self.fileName + 
                ' does not have SAR NRCS in VV polarization')

        self.SAR_image_time = self.get_time(
                self.sigma0_bandNo).replace(tzinfo=None)

        if pixelsize != 'fullres':
            print 'Resizing SAR image to ' + str(pixelsize) + ' m pixel size'
            self.resize(pixelsize=pixelsize)

        self.winddir = winddir
        if winddir is not None:
            self.calculate_wind()


    def calculate_wind(self, winddir=None, storeModelSpeed=True):
        # Calculate wind speed from SAR sigma0 in VV polarization

        if winddir:
            self.winddir = winddir
        if self.winddir is None or self.winddir == 'online':
            self.winddir = 'ncep_wind_online' # default source

        if isinstance(self.winddir, int):
            # Constant wind direction is input
            print 'Using constant wind (from) direction: ' + str(self.winddir) + \
                    ' degrees clockwise from North'
            winddirArray = np.ones(self.shape())*self.winddir
            winddir_time = None
            storeModelSpeed = False # Not relevant if direction given as number
        else:
            # Nansat readable file
            if isinstance(self.winddir, str):
                try:
                    self.winddir = Nansat(self.winddir)
                except:
                    try:
                        self.winddir = Nansat(self.winddir + 
                                            datetime.strftime(
                                            self.SAR_image_time, ':%Y%m%d%H%M'))
                    except:
                        pass

            if not isinstance(self.winddir, Nansat):
                raise ValueError('Wind direction not available')

            winddir_time = self.winddir.get_time()[0]

            # Bi-linear interpolation onto SAR image
            self.winddir.reproject(self, eResampleAlg=1)

            # Check time difference between SAR image and wind direction object
            timediff = self.SAR_image_time - winddir_time
            hoursDiff = np.abs(timediff.total_seconds()/3600.)
            print 'Time difference between SAR image and wind direction: ' \
                    + '%.2f' % hoursDiff + ' hours'
            print 'SAR image time: ' + str(self.SAR_image_time)
            print 'Wind dir time: ' + str(winddir_time)
            if hoursDiff > 3:
                print '#########################################'
                print 'WARNING: time difference exceeds 3 hours!'
                print '#########################################'

            wind_u_bandNo = self.winddir._get_band_number({
                                'standard_name': 'eastward_wind',
                            })
            wind_v_bandNo = self.winddir._get_band_number({
                                'standard_name': 'northward_wind',
                            })
            # Get wind direction
            u_array = self.winddir[wind_u_bandNo]
            v_array = self.winddir[wind_v_bandNo]
            winddirArray = np.degrees(
                    np.arctan2(-u_array, -v_array)) # 0 from North, 90 from East


        # Calculate SAR wind with CMOD
        # TODO: 
        # - add other CMOD versions than CMOD5
        print 'Calculating SAR wind with CMOD...'
        startTime = datetime.now()

        windspeed = cmod5n_inverse(self[self.sigma0_bandNo], 
                        np.mod(winddirArray - self['SAR_look_direction'], 360), 
                        self['incidence_angle'])
        print 'Calculation time: ' + str(datetime.now() - startTime)

        windspeed[np.where(np.isnan(windspeed))] = np.nan
        windspeed[np.where(np.isinf(windspeed))] = np.nan

        # Add wind speed and direction as bands
        # TODO: make it possible to update existing bands... See
        # https://github.com/nansencenter/nansat/issues/58
        self.add_band(array=windspeed, parameters={
                        'wkv': 'wind_speed',
                        'name': 'windspeed',
                        'time': self.get_time(self.sigma0_bandNo),
                        'winddir_time': winddir_time
                })
        self.add_band(array=winddirArray, parameters={
                            'wkv': 'wind_from_direction',
                            'name': 'winddirection',
                            'time': winddir_time
                })

        if storeModelSpeed:
            self.add_band(array=self.winddir['windspeed'], parameters={
                            'wkv': 'wind_speed',
                            'name': 'model_windspeed',
                            'time': winddir_time,
            })

        # TODO: Replace U and V bands with pixelfunctions
        u = -windspeed*np.sin((180.0 - winddirArray)*np.pi/180.0)
        v = windspeed*np.cos((180.0 - winddirArray)*np.pi/180.0)
        self.add_band(array=u, parameters={
                            'wkv': 'eastward_wind',
        })
        self.add_band(array=v, parameters={
                            'wkv': 'northward_wind',
        })


    def _get_masked_windspeed(self, landmask=True, icemask=True):
        try:
            sar_windspeed = self['windspeed']
        except:
            raise ValueError('SAR wind has not been calculated, ' \
                'execute calculate_wind(winddir) first.')

        sar_windspeed[sar_windspeed<0] = 0
        palette = jet

        if landmask:
            try: # Land mask
                sar_windspeed = np.ma.masked_where(
                                    self.watermask()[1]==2, sar_windspeed)
                palette.set_bad([.3, .3, .3], 1.0) # Land is masked (bad)
            except:
                print 'Land mask not available'
        
        if icemask:
            try: # Ice mask
                try: # first try local file 
                    ice = Nansat('metno_local_hires_seaice_' + 
                            self.SAR_image_time.strftime('%Y%m%d'), 
                            mapperName='metno_local_hires_seaice')
                except: # otherwise Thredds
                    ice = Nansat('metno_hires_seaice:' + 
                            self.SAR_image_time.strftime('%Y%m%d'))
                ice.reproject(self)
                iceBandNo = ice._get_band_number(
                    {'standard_name': 'sea_ice_area_fraction'})
                sar_windspeed[ice[iceBandNo]>0] = -1
                palette.set_under('w', 1.0) # Ice is 'under' (-1)
            except:
                print 'Ice mask not available'

        return sar_windspeed, palette

    def write_geotiff(self, filename, landmask=True, icemask=True):

        sar_windspeed, palette = self._get_masked_windspeed(landmask, icemask)

        nansat_geotiff = Nansat(array=sar_windspeed, domain=self,
                                parameters = {'name': 'masked_windspeed',
                                              'minmax': '0 20'})
                        
        nansat_geotiff.write_geotiffimage(filename)


    def plot(self, filename=None, numVectorsX = 16, show=True,
                landmask=True, icemask=True, flip=True, maskWindAbove=35):
        ''' Basic plotting function showing CMOD wind speed
        overlaid vectors in SAR image projection'''

        try:
            sar_windspeed, palette = self._get_masked_windspeed(landmask, icemask)
        except:
            raise ValueError('SAR wind has not been calculated, ' \
                'execute calculate_wind(winddir) before plotting.')
        sar_windspeed[sar_windspeed>maskWindAbove] = np.nan

        winddirReductionFactor = np.round(
                self.vrt.dataset.RasterXSize/numVectorsX)
        # model_winddir is direction from which wind is blowing
        winddir_relative_up = 360 - self['winddirection'] + \
                                    self.azimuth_up()
        indX = range(0, self.vrt.dataset.RasterXSize, winddirReductionFactor)
        indY = range(0, self.vrt.dataset.RasterYSize, winddirReductionFactor)
        X, Y = np.meshgrid(indX, indY)
        try: # scaling of wind vector length, if model wind is available
            model_windspeed = self['model_windspeed']
            model_windspeed = model_windspeed[Y, X]
        except:
            model_windspeed = 8*np.ones(X.shape)

        Ux = np.sin(np.radians(winddir_relative_up[Y, X]))*model_windspeed
        Vx = np.cos(np.radians(winddir_relative_up[Y, X]))*model_windspeed

        # Make sure North is up, and east is right
        if flip == True:
            lon, lat = self.get_corners()
            if lat[0] < lat[1]:
                sar_windspeed = np.flipud(sar_windspeed)
                Ux = -np.flipud(Ux)
                Vx = -np.flipud(Vx)

            if lon[0] > lon[2]:
                sar_windspeed = np.fliplr(sar_windspeed)
                Ux = np.fliplr(Ux)
                Vx = np.fliplr(Vx)

        # Plotting
        figSize = sar_windspeed.shape
        legendPixels = 60.0
        legendPadPixels = 5.0
        legendFraction = legendPixels/figSize[0]
        legendPadFraction = legendPadPixels/figSize[0]
        dpi=100.0

        fig = plt.figure()
        fig.set_size_inches((figSize[1]/dpi, (figSize[0]/dpi)*
                                (1+legendFraction+legendPadFraction)))
        ax = fig.add_axes([0,0,1,1+legendFraction])
        ax.set_axis_off()
        plt.imshow(sar_windspeed, cmap=palette, interpolation='nearest')
        plt.clim([0, 20])
        cbar = plt.colorbar(orientation='horizontal', shrink=.80,
                     aspect=40,
                     fraction=legendFraction, pad=legendPadFraction)
        cbar.ax.set_ylabel('[m/s]', rotation=0)
        cbar.ax.yaxis.set_label_position('right')
        ax.quiver(X, Y, Ux, Vx, angles='xy', width=0.004,
                    scale=200, scale_units='width',
                    color=[.0, .0, .0], headaxislength=4)
        if filename is not None:
            fig.savefig(filename, pad_inches=0, dpi=dpi)
        if show:
            plt.show()
        return fig
Example #4
0
# Open an input file
# Create a Nansat object <n> for futher high-level operations
n = Nansat(iFileName)

# Open an input file, specify which Mapper to use, set logging level
n = Nansat(iFileName, mapperName='generic', logLevel=10)

# list bands and georeference of the object
print 'Raw Nansat:', n, '\n'

# get dictionary with metadata from all bands
print 'Bands:', n.bands(), '\n'

# get time of the image aquisition
print 'Time:', n.get_time()[0], '\n'

# set GlobalMetadata
n.set_metadata(key='GlobalKey', value='GlobalVal')
# get Global Metadata
print 'Global Metadata:', n.get_metadata(), '\n'

# set BandMetadata to the 1st band
n.set_metadata(key='BandKey', value='BandVal', bandID=1)
# get 1st Band Metadata
print '1st Band Metadata:', n.get_metadata(bandID=1), '\n'

# add a band from file (copy the 2nd band to the end (4th band)
n.add_band(fileName=n.fileName, bandID=2)
# add a band from numpy array (copy the 1st band to the end (5th band))
n.add_band(array=n[1], parameters={'name': 'Name1',
Example #5
0
print 'Raw Nansat:', n

# get dictionary with metadata from all bands
print 'Bands:', n.bands()

# get size of the object (Y and X dimensions, to follow Numpy style)
print 'Shape:', n.shape()

# get list with coordinates of the object corners
print 'Corners:', n.get_corners()

# get lists with coordinates of the object borders
print 'Border:', n.get_border()

# get time of the image aquisition
print 'Time:', n.get_time()[0]

# Get band data and do some operations
# 1. Get data from 1st band as numpy array
# 2. Plot the array (pyplot image is save to a PNG file)
# 3. Save as Matlab file
a = n[1]
plt.imshow(a);plt.colorbar();plt.savefig(oFileName + '_imshow.png');plt.close()
savemat(oFileName + '.mat', {'band_1': a})

# make simple indexed image from 1st band with default colormap
n.write_figure(oFileName + '.png')

# make RGB image from bands 1,2,3 with brightness correction
n.write_figure(oFileName + '_rgb.png', bands=[1,2,3], clim='hist', ratio=0.9)
Example #6
0
class SARWind(Nansat, object):
    '''
    A class for calculating wind speed from SAR images using CMOD
    '''
    def __init__(self, sar_image, winddir=None, pixelsize=500):
        '''
            Parameters
            -----------
            sar_image : string or Nansat object
                SAR image filename (original, raw file)
            winddir : int, string, Nansat, None
                Auxiliary wind field information needed to calculate
                SAR wind (must be or have wind direction)
        '''
        if isinstance(sar_image, str) or isinstance(sar_image, unicode):
            super(SARWind, self).__init__(sar_image)
        elif isinstance(sar_image, Nansat):
            super(SARWind, self).__init__(domain=sar_image)
            self.vrt = sar_image.vrt

        # Check that this is a SAR image with VV pol NRCS
        try:
            self.sigma0_bandNo = self._get_band_number({
                'standard_name':
                'surface_backwards_scattering_coefficient_of_radar_wave',
                'polarization': 'VV'
            })
        except:
            raise TypeError(self.fileName +
                            ' does not have SAR NRCS in VV polarization')

        self.SAR_image_time = self.get_time(
            self.sigma0_bandNo).replace(tzinfo=None)

        if pixelsize != 'fullres':
            print 'Resizing SAR image to ' + str(pixelsize) + ' m pixel size'
            self.resize(pixelsize=pixelsize)

        self.winddir = winddir
        if winddir is not None:
            self.calculate_wind()

    def calculate_wind(self, winddir=None, storeModelSpeed=True):
        # Calculate wind speed from SAR sigma0 in VV polarization

        if winddir:
            self.winddir = winddir
        if self.winddir is None or self.winddir == 'online':
            self.winddir = 'ncep_wind_online'  # default source

        if isinstance(self.winddir, int):
            # Constant wind direction is input
            print 'Using constant wind (from) direction: ' + str(self.winddir) + \
                    ' degrees clockwise from North'
            winddirArray = np.ones(self.shape()) * self.winddir
            winddir_time = None
            storeModelSpeed = False  # Not relevant if direction given as number
        else:
            # Nansat readable file
            if isinstance(self.winddir, str):
                try:
                    self.winddir = Nansat(self.winddir)
                except:
                    try:
                        self.winddir = Nansat(self.winddir + datetime.strftime(
                            self.SAR_image_time, ':%Y%m%d%H%M'))
                    except:
                        pass

            if not isinstance(self.winddir, Nansat):
                raise ValueError('Wind direction not available')

            winddir_time = self.winddir.get_time()[0]

            # Bi-linear interpolation onto SAR image
            self.winddir.reproject(self, eResampleAlg=1)

            # Check time difference between SAR image and wind direction object
            timediff = self.SAR_image_time - winddir_time
            hoursDiff = np.abs(timediff.total_seconds() / 3600.)
            print 'Time difference between SAR image and wind direction: ' \
                    + '%.2f' % hoursDiff + ' hours'
            print 'SAR image time: ' + str(self.SAR_image_time)
            print 'Wind dir time: ' + str(winddir_time)
            if hoursDiff > 3:
                print '#########################################'
                print 'WARNING: time difference exceeds 3 hours!'
                print '#########################################'

            wind_u_bandNo = self.winddir._get_band_number({
                'standard_name':
                'eastward_wind',
            })
            wind_v_bandNo = self.winddir._get_band_number({
                'standard_name':
                'northward_wind',
            })
            # Get wind direction
            u_array = self.winddir[wind_u_bandNo]
            v_array = self.winddir[wind_v_bandNo]
            winddirArray = np.degrees(np.arctan2(
                -u_array, -v_array))  # 0 from North, 90 from East

        # Calculate SAR wind with CMOD
        # TODO:
        # - add other CMOD versions than CMOD5
        print 'Calculating SAR wind with CMOD...'
        startTime = datetime.now()

        windspeed = cmod5n_inverse(
            self[self.sigma0_bandNo],
            np.mod(winddirArray - self['SAR_look_direction'], 360),
            self['incidence_angle'])
        print 'Calculation time: ' + str(datetime.now() - startTime)

        windspeed[np.where(np.isnan(windspeed))] = np.nan
        windspeed[np.where(np.isinf(windspeed))] = np.nan

        # Add wind speed and direction as bands
        # TODO: make it possible to update existing bands... See
        # https://github.com/nansencenter/nansat/issues/58
        self.add_band(array=windspeed,
                      parameters={
                          'wkv': 'wind_speed',
                          'name': 'windspeed',
                          'time': self.get_time(self.sigma0_bandNo),
                          'winddir_time': winddir_time
                      })
        self.add_band(array=winddirArray,
                      parameters={
                          'wkv': 'wind_from_direction',
                          'name': 'winddirection',
                          'time': winddir_time
                      })

        if storeModelSpeed:
            self.add_band(array=self.winddir['windspeed'],
                          parameters={
                              'wkv': 'wind_speed',
                              'name': 'model_windspeed',
                              'time': winddir_time,
                          })

        # TODO: Replace U and V bands with pixelfunctions
        u = -windspeed * np.sin((180.0 - winddirArray) * np.pi / 180.0)
        v = windspeed * np.cos((180.0 - winddirArray) * np.pi / 180.0)
        self.add_band(array=u, parameters={
            'wkv': 'eastward_wind',
        })
        self.add_band(array=v, parameters={
            'wkv': 'northward_wind',
        })

    def _get_masked_windspeed(self, landmask=True, icemask=True):
        try:
            sar_windspeed = self['windspeed']
        except:
            raise ValueError('SAR wind has not been calculated, ' \
                'execute calculate_wind(winddir) first.')

        sar_windspeed[sar_windspeed < 0] = 0
        palette = jet

        if landmask:
            try:  # Land mask
                sar_windspeed = np.ma.masked_where(self.watermask()[1] == 2,
                                                   sar_windspeed)
                palette.set_bad([.3, .3, .3], 1.0)  # Land is masked (bad)
            except:
                print 'Land mask not available'

        if icemask:
            try:  # Ice mask
                try:  # first try local file
                    ice = Nansat('metno_local_hires_seaice_' +
                                 self.SAR_image_time.strftime('%Y%m%d'),
                                 mapperName='metno_local_hires_seaice')
                except:  # otherwise Thredds
                    ice = Nansat('metno_hires_seaice:' +
                                 self.SAR_image_time.strftime('%Y%m%d'))
                ice.reproject(self)
                iceBandNo = ice._get_band_number(
                    {'standard_name': 'sea_ice_area_fraction'})
                sar_windspeed[ice[iceBandNo] > 0] = -1
                palette.set_under('w', 1.0)  # Ice is 'under' (-1)
            except:
                print 'Ice mask not available'

        return sar_windspeed, palette

    def write_geotiff(self, filename, landmask=True, icemask=True):

        sar_windspeed, palette = self._get_masked_windspeed(landmask, icemask)

        nansat_geotiff = Nansat(array=sar_windspeed,
                                domain=self,
                                parameters={
                                    'name': 'masked_windspeed',
                                    'minmax': '0 20'
                                })

        nansat_geotiff.write_geotiffimage(filename)

    def plot(self,
             filename=None,
             numVectorsX=16,
             show=True,
             landmask=True,
             icemask=True,
             flip=True,
             maskWindAbove=35):
        ''' Basic plotting function showing CMOD wind speed
        overlaid vectors in SAR image projection'''

        try:
            sar_windspeed, palette = self._get_masked_windspeed(
                landmask, icemask)
        except:
            raise ValueError('SAR wind has not been calculated, ' \
                'execute calculate_wind(winddir) before plotting.')
        sar_windspeed[sar_windspeed > maskWindAbove] = np.nan

        winddirReductionFactor = np.round(self.vrt.dataset.RasterXSize /
                                          numVectorsX)
        # model_winddir is direction from which wind is blowing
        winddir_relative_up = 360 - self['winddirection'] + \
                                    self.azimuth_up()
        indX = range(0, self.vrt.dataset.RasterXSize, winddirReductionFactor)
        indY = range(0, self.vrt.dataset.RasterYSize, winddirReductionFactor)
        X, Y = np.meshgrid(indX, indY)
        try:  # scaling of wind vector length, if model wind is available
            model_windspeed = self['model_windspeed']
            model_windspeed = model_windspeed[Y, X]
        except:
            model_windspeed = 8 * np.ones(X.shape)

        Ux = np.sin(np.radians(winddir_relative_up[Y, X])) * model_windspeed
        Vx = np.cos(np.radians(winddir_relative_up[Y, X])) * model_windspeed

        # Make sure North is up, and east is right
        if flip == True:
            lon, lat = self.get_corners()
            if lat[0] < lat[1]:
                sar_windspeed = np.flipud(sar_windspeed)
                Ux = -np.flipud(Ux)
                Vx = -np.flipud(Vx)

            if lon[0] > lon[2]:
                sar_windspeed = np.fliplr(sar_windspeed)
                Ux = np.fliplr(Ux)
                Vx = np.fliplr(Vx)

        # Plotting
        figSize = sar_windspeed.shape
        legendPixels = 60.0
        legendPadPixels = 5.0
        legendFraction = legendPixels / figSize[0]
        legendPadFraction = legendPadPixels / figSize[0]
        dpi = 100.0

        fig = plt.figure()
        fig.set_size_inches(
            (figSize[1] / dpi,
             (figSize[0] / dpi) * (1 + legendFraction + legendPadFraction)))
        ax = fig.add_axes([0, 0, 1, 1 + legendFraction])
        ax.set_axis_off()
        plt.imshow(sar_windspeed, cmap=palette, interpolation='nearest')
        plt.clim([0, 20])
        cbar = plt.colorbar(orientation='horizontal',
                            shrink=.80,
                            aspect=40,
                            fraction=legendFraction,
                            pad=legendPadFraction)
        cbar.ax.set_ylabel('[m/s]', rotation=0)
        cbar.ax.yaxis.set_label_position('right')
        ax.quiver(X,
                  Y,
                  Ux,
                  Vx,
                  angles='xy',
                  width=0.004,
                  scale=200,
                  scale_units='width',
                  color=[.0, .0, .0],
                  headaxislength=4)
        if filename is not None:
            fig.savefig(filename, pad_inches=0, dpi=dpi)
        if show:
            plt.show()
        return fig