Exemplo n.º 1
0
def upscale_field(lons, lats, field, x_scale=2, y_scale=2, is_degrees=True):
    '''
    Takes a field defined on a sphere using lons/lats and returns an upscaled
    version, using cubic spline interpolation.
    '''
    if is_degrees:
        lons = lons * np.pi / 180.
        lats = (lats + 90) * np.pi / 180.

    d_lon = lons[1] - lons[0]
    d_lat = lats[1] - lats[0]

    new_lon = np.linspace(lons[0], lons[-1], len(lons) * x_scale)
    new_lat = np.linspace(lats[0], lats[-1], len(lats) * x_scale)

    mesh_new_lat, mesh_new_lon = np.meshgrid(new_lat, new_lon)

    if True:
        lut = RectSphereBivariateSpline(lats[1:-1], lons[1:-1], field[1:-1,
                                                                      1:-1])

        interp_field = lut.ev(mesh_new_lat[1:-1, 1:-1].ravel(),
                              mesh_new_lon[1:-1, 1:-1].ravel()).reshape(
                                  mesh_new_lon.shape[0] - 2,
                                  mesh_new_lon.shape[1] - 2).T
    else:
        pass
    if is_degrees:
        new_lon = new_lon * 180. / np.pi
        new_lat = (new_lat * 180. / np.pi) - 90

    return new_lon[1:-1], new_lat[1:-1], interp_field
def resize_interpolate(ary_in, new_size):
    if hasattr(ary_in, 'dtype'):
        lons = sorted(list(set(ary_in['x'])))
        lats = sorted(list(set(ary_in['y'])))
        zs = ary_in['z']
    else:
        lons, lats, zs = (numpy.array(sorted(list(set(x))))
                          for x in (zip(*ary_in)))
        #print('lls: ', lons, lats)
        zs = numpy.array([rw[2] for rw in ary_in])
    #
    new_lons = numpy.linspace(min(lons), max(lons),
                              new_size[0]) * numpy.pi / 180.
    new_lats = numpy.linspace(min(lats), max(lats),
                              new_size[1]) * numpy.pi / 180.
    #return new_lons, new_lats
    new_lats, new_lons = numpy.meshgrid(new_lats, new_lons)
    #
    data = numpy.array(zs)
    data.shape = (numpy.size(lats), numpy.size(lons)
                  )  # or is it len(lats), len(lons) (yes, i think it is)
    lut = RectSphereBivariateSpline(lats, lons, data)
    #data_interp = lut.ev(new_lats.ravel(), new_lons.ravel())
    data_interp = lut.ev(new_lats.ravel(),
                         new_lons.ravel()).reshape(new_size).T
    data_interp = data_interp.reshape((data_interp.size, ))
    #return data_interp
    #
    #
    return np.core.records.fromarrays(
        zip(*[[x * 180 / numpy.pi, y * 180 / numpy.pi, z] for (x, y), z in zip(
            itertools.product(new_lons.reshape((
                new_lons.size, )), new_lats.reshape((
                    new_lats.size, ))), data_interp)]),
        dtype=[('x', '>f8'), ('y', '>f8'), ('z', '>f8')])
Exemplo n.º 3
0
def upscale_field(lons, lats, field, x_scale=2, y_scale=2, is_degrees=True):
    '''
    Takes a field defined on a sphere using lons/lats and returns an upscaled
    version, using cubic spline interpolation.
    '''
    if is_degrees:
        lons = lons * np.pi / 180.
        lats = (lats + 90) * np.pi / 180.

    d_lon = lons[1] - lons[0]
    d_lat = lats[1] - lats[0]

    new_lon = np.linspace(lons[0], lons[-1], len(lons) * x_scale)
    new_lat = np.linspace(lats[0], lats[-1], len(lats) * x_scale)

    mesh_new_lat, mesh_new_lon = np.meshgrid(new_lat, new_lon)

    if True:
        lut = RectSphereBivariateSpline(lats[1:-1], lons[1:-1], field[1:-1, 1:-1])

        interp_field = lut.ev(mesh_new_lat[1:-1, 1:-1].ravel(),
                              mesh_new_lon[1:-1, 1:-1].ravel()).reshape(mesh_new_lon.shape[0] - 2,
                                                                        mesh_new_lon.shape[1] - 2).T
    else:
        pass
    if is_degrees:
        new_lon = new_lon * 180. / np.pi
        new_lat = (new_lat * 180. / np.pi) - 90

    return new_lon[1:-1], new_lat[1:-1], interp_field
Exemplo n.º 4
0
def ncepGFSmodel2swath(lats, lons, data, lats_2, lons_2):

    func = RectSphereBivariateSpline(lats, lons, data)
    data_2 = func.ev(lats_2.ravel(),\
                     lons_2.ravel())\
                     .reshape(lats_2.shape)
    return data_2
Exemplo n.º 5
0
def apply_gia(sites_of_retain4, dir_file_gia):

    # read the rate of radial displacement (UP) on a 0.2x0.2 grid from ICE-6G_D(VM5a)
    data_ICE_6G_D = dir_file_gia

    # Open the dataset and print out metadeta
    ds = xr.open_dataset(data_ICE_6G_D)

    # convert lons and lats of sites in [d,m,s] to lons and colats in radian

    sites_of_retain4_lons = sites_of_retain4['Lon. °E'] * u.deg.to(u.rad)
    sites_of_retain4_lats = sites_of_retain4['Lat. °N'] * u.deg.to(u.rad)
    sites_of_retain4_colats = np.pi / 2 - sites_of_retain4_lats

    # colats and lons in radians
    lats, lons, up_rate = ds['Lat'], ds['Lon'], ds['Drad_250']

    colats_rad = np.deg2rad(90 - lats)
    lons_rad = np.deg2rad(lons)

    lut = RectSphereBivariateSpline(colats_rad, lons_rad, up_rate)

    up_rate_sites = lut.ev(sites_of_retain4_colats, sites_of_retain4_lons)

    sites_of_retain5 = sites_of_retain4[up_rate_sites < 0.75]

    return sites_of_retain5
Exemplo n.º 6
0
def create_model(file_name=None, tag=None):
    '''Takes .ffe model, converts into healpix and smooths the response'''

    ##Make an empty array for healpix projection
    beam_response = zeros(len_empty_healpix) * nan

    ##Load ffe model data in, which is stored in real and imaginary components
    ##of a phi/theta polaristaion representation of the beam
    ##apparently this is normal to beam engineers
    data = loadtxt(file_name)
    theta = data[:, 0]
    phi = data[:, 1]
    re_theta = data[:, 2]
    im_theta = data[:, 3]
    re_phi = data[:, 4]
    im_phi = data[:, 5]

    ##Convert to complex numbers
    X_theta = re_theta.astype(complex)
    X_theta.imag = im_theta

    X_phi = re_phi.astype(complex)
    X_phi.imag = im_phi

    ##make a coord grid for the data in the .ffe model
    theta_range = linspace(epsilon, 90, 91)
    phi_range = linspace(epsilon, 359.0, 360)
    theta_mesh, phi_mesh = meshgrid(theta_range, phi_range)

    ##Convert reference model into power from the complex values
    ##make an inf values super small
    power = 10 * log10(abs(X_theta)**2 + abs(X_phi)**2)
    power[where(power == -inf)] = -80

    ##Had a problem with edge effects, leave off near horizon values
    power = power[:-91]

    ##Get things into correct shape and do an interpolation
    ##s is a paramater I had to play with to get by eye nice results
    power.shape = phi_mesh.shape

    lut = RectSphereBivariateSpline(theta_range * (pi / 180.0),
                                    phi_range * (pi / 180.0),
                                    power.T,
                                    s=0.1)

    ##Get the theta and phi of all healpixels
    ip = arange(len_empty_healpix)
    theta_rad, phi_rad = hp.pix2ang(nside, ip)

    ##Use spline to map beam into healpixels
    beam_response = lut.ev(theta_rad, phi_rad)

    return beam_response, theta_mesh, phi_mesh, power, theta
        def I_sc(u, phi):
            '''
            Given a calculated, discretized, scattered intensity (Ifull), evaluate it 
            at the given u, phi. Use linear interpolation on a sphere.
            Global variables: Ifull, u_bounds, phi_bounds
            '''
            ui = (u_bounds[1:] + u_bounds[:-1]) / 2
            phii = (phi_bounds[1:] + phi_bounds[:-1]) / 2
            thi = arccos(ui)[::-1]
            Ii = Ifull[-1, ::-1, :]
            # There is a discontinuity at u=0 (th=pi/2), so interpolation over either
            # the top half or bottom half plane. In practice, we only need the bottom.
            # Another detail is that we should specify a point at zenith, otherwise
            # it's extrapolating.
            zenith_val = np.mean(Ii[0, :])
            # Because this interpolator is not ideal, create a ghost data point to
            # enforce linear interpolation across 0-2pi jump in phi
            phii_new = concatenate(([0], phii))
            Ii_new = zeros((N, R + 1))
            Ii_new[:, 0] = (Ii[:, -1] + Ii[:, 0]) / 2
            Ii_new[:, 1:] = Ii
            Iint = RectSphereBivariateSpline(thi[:N / 2],
                                             phii_new,
                                             Ii_new[:N / 2, :],
                                             pole_values=(zenith_val, None))

            return Iint(arccos(u), phi).item()
def regrid(phi_old, lambda_old, nphi_new, nlambda_new, data):
    Drc = data[1:-1, 1:-1, 0].copy()
    lut = RectSphereBivariateSpline(phi_old + pi / 2, lambda_old + pi, Drc.T)

    dlambda1 = 2 * pi / nlambda_new
    dphi1 = pi / nphi_new

    phi1 = np.array(
        [-((pi / 2) - dphi1 / 2) + (j) * dphi1
         for j in range(nphi_new)]) + pi / 2
    lambd1 = (np.array([-(pi) + (i) * dlambda1
                        for i in range(nlambda_new)])) + pi

    glambd, gphi = np.meshgrid(lambd1, phi1)

    interp = (lut.ev(gphi.ravel(),
                     glambd.ravel())).reshape(nphi_new, nlambda_new).T
    return interp, phi1, lambd1, dphi1, dlambda1
Exemplo n.º 9
0
def geointerp(lats, lons, data, grid_size_deg, mesh=False):
    '''We want to interpolate it to a global x-degree grid'''
    deg2rad = np.pi / 180.
    new_lats = np.linspace(grid_size_deg, 180, 180 / grid_size_deg)
    new_lons = np.linspace(grid_size_deg, 360, 360 / grid_size_deg)
    new_lats_mesh, new_lons_mesh = np.meshgrid(new_lats * deg2rad,
                                               new_lons * deg2rad)
    '''We need to set up the interpolator object'''
    # lats = [float(lat) for lat in lats]
    print lats * 2  #*deg2rad
    lut = RectSphereBivariateSpline(lats * deg2rad, lons * deg2rad, data)
    '''Finally we interpolate the data. The RectSphereBivariateSpline
    object only takes 1-D arrays as input, therefore we need to do some reshaping.'''
    new_lats = new_lats_mesh.ravel()
    new_lons = new_lons_mesh.ravel()
    data_interp = lut.ev(new_lats, new_lons)

    if mesh == True:
        data_interp = data_interp.reshape(
            (360 / grid_size_deg, 180 / grid_size_deg)).T

    return new_lats / deg2rad, new_lons / deg2rad, data_interp
Exemplo n.º 10
0
def init_interpo_dec():
    """
    Generates an object of scipy.interpolate.RectSphereBivariateSpline 
    interpo_dec required by magdec() that interpolates
    magnetic declination (also called magnetic variation) based on the data
    table calculated from the NOAA webpage
    https://www.ngdc.noaa.gov/geomag/calculators/magcalc.shtml#igrfgrid
    with the following input:
        Southern most lat:  90 S
        Northern most lat:  90 N
        Lat Step Size:      1.0
        Western most long:  180 W
        Eastern most long:  179 E
        Lon Step Size:      1.0
        Elevation:          Mean sea level 0 Feet
        Magnetic component: Declination
        Model:              WMM (2019-2024)
        Start Date:         2020 09 20
        End Date:           2020 09 20
        Step size:          1.0
        Result format:      CSV
    The grid size can be adjusted but the (1 deg by 1 deg) size should suffice 
    for practical purpose, as long as the the grids cover the entire Earth
    surface. The interpolation is performed at sea-level, but no significant
    difference would be noticed up to FL600 or beyond.
    See docstring of geo.magdec() for more information.
    Created by  : Yaofu Zhou
    """

    declination = pd.read_csv('bluesky/tools/declination_sealevel.csv',\
        comment='#',usecols=[1,2,4],header=None, names=['lat','lon','dec'])
    index_last = len(declination.index)
    lat_1st = declination.iloc[0, 0]
    lon_1st = declination.iloc[0, 1]
    num_lon = (declination.lat == lat_1st).sum()
    num_lat = (declination.lon == lon_1st).sum()
    lat_last = declination.iloc[index_last - 1, 0]
    lon_last = declination.iloc[index_last - 1, 1]
    lat_x = np.linspace(lat_last, lat_1st, num_lat) * np.pi / 180.
    lon_y = np.linspace(lon_1st, lon_last, num_lon) * np.pi / 180.
    distinct_lat = np.unique(declination.lat)
    dec_xy = np.zeros([1, num_lon])
    for val in distinct_lat:
        dec = np.array(declination.loc[declination.lat == val, 'dec'].values)\
        .reshape(1,num_lon)
        dec_xy = np.vstack((dec_xy, dec))

    dec_xy = dec_xy[1:, :]
    interpo_dec = RectSphereBivariateSpline(lat_x+np.pi/2., lon_y+np.pi,\
     dec_xy)
    return interpo_dec
Exemplo n.º 11
0
def geointerp(lats,lons,data,grid_size_deg, mesh=False):
    '''We want to interpolate it to a global x-degree grid'''
    deg2rad = np.pi/180.
    new_lats = np.linspace(grid_size_deg, 180, 180/grid_size_deg)
    new_lons = np.linspace(grid_size_deg, 360, 360/grid_size_deg)
    new_lats_mesh, new_lons_mesh = np.meshgrid(new_lats*deg2rad, new_lons*deg2rad)

    '''We need to set up the interpolator object'''
   # lats = [float(lat) for lat in lats]
    print lats*2#*deg2rad
    lut = RectSphereBivariateSpline(lats*deg2rad, lons*deg2rad, data)

    '''Finally we interpolate the data. The RectSphereBivariateSpline
    object only takes 1-D arrays as input, therefore we need to do some reshaping.'''
    new_lats = new_lats_mesh.ravel()
    new_lons = new_lons_mesh.ravel()
    data_interp = lut.ev(new_lats,new_lons)

    if mesh == True:
        data_interp = data_interp.reshape((360/grid_size_deg,
                                           180/grid_size_deg)).T

    return new_lats/deg2rad, new_lons/deg2rad, data_interp
Exemplo n.º 12
0
def _loadEGM96():
    """load the EGM96 geoid model into a spline object"""

    #load the data resource file into a string
    flc = resource_string(__name__, "data/egm96.dac")

    #setup basic coordinates
    lon = sp.linspace(0, 2 * sp.pi, 1440, False)
    lat = sp.linspace(0, sp.pi, 721)

    #parse the raw data string
    data = sp.fromstring(flc,
                         sp.dtype(sp.int16).newbyteorder("B"),
                         1038240).reshape((lat.size, lon.size)) / 100.0

    #interpolate the bad boy
    lut = RectSphereBivariateSpline(lat[1:-1],
                                    lon,
                                    data[1:-1],
                                    pole_values=(sp.mean(data[1]),
                                                 sp.mean(data[-1])))

    return lut
Exemplo n.º 13
0
def interpolate2d_sphere(lat, lon, param, radians=True, **kwargs):
    """
  Interpolate on rectangular mesh on sphere
  
  Convenience function to call `RectSphereBivariateSpline 
  <http://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.RectSphereBivariateSpline.html>`_
  
  Parameters
  ----------
  lat_rad : array_like
    1-D array of latitude coordinates in strictly ascending order.
    Coordinates must be given in radians, and lie within ``(0, pi)``.
  lon_rad : array_like
    1-D array of longitude coordinates in strictly ascending order.
    Coordinates must be given in radians and lie within the interval
    ``(0, 2*pi)``.
  param : array_like
    2-D array of parameter with shape ``(lat_rad.size, lon_rad.size)``
  radians : bool, optional


  Returns
  -------
  `scipy.interpolate.RectSphereBivariateSpline`
    Spline function to be used for evaluation of interpolation

  Notes
  -----
  Keyword arguments passed on to `RectSphereBivariateSpline`_.
  """
    d2r = np.pi / 180
    if not radians:
        lat *= d2r
        lon *= d2r

    return RectSphereBivariateSpline(lat, lon, param, **kwargs)
Exemplo n.º 14
0
class Interpolator2D():
    """ Class for interpolating 2D (lat,lon) geospatial data.

        For irregular grids, the data values must be passed as a
        1d array and all three arrays (values, lats, lons) must have
        the same length.

        For regular grids, the data values must be passed as a
        2d array with shape (M,N) where M and N are the lengths
        of the latitude and longitude array, respectively.

        Attributes:
            values: 1d or 2d numpy array
                Values to be interpolated
            lats: 1d numpy array
                Latitude values
            lons: 1d numpy array
                Longitude values
            origin: tuple(float,float)
                Reference location (origo of XY coordinate system).
            method_irreg : {‘linear’, ‘nearest’, ‘cubic’, ‘regularize’}, optional
                Interpolation method used for irregular grids.
                Note that 'nearest' is usually significantly faster than
                the 'linear' and 'cubic'.
                If the 'regularize' is selected, the data is first mapped onto
                a regular grid by means of a linear interpolation (for points outside
                the area covered by the data, a nearest-point interpolation is used).
                The bin size of the regular grid is specified via the reg_bin argument.
            bins_irreg_max: int
                Maximum number of bins along either axis of the regular grid onto which
                the irregular data is mapped. Only relevant if method_irreg is set to
                'regularize'. Default is 2000.
    """
    def __init__(self,
                 values,
                 lats,
                 lons,
                 origin=None,
                 method_irreg='regularize',
                 bins_irreg_max=400):

        # compute coordinates of origin, if not provided
        if origin is None: origin = center_point(lats, lons)
        self.origin = origin

        # check if bathymetry data are on a regular or irregular grid
        reggrid = (np.ndim(values) == 2)

        # convert to radians
        lats_rad, lons_rad = torad(lats, lons)

        # necessary to resolve a mismatch between scipy and underlying Fortran code
        # https://github.com/scipy/scipy/issues/6556
        if np.min(lons_rad) < 0: self._lon_corr = np.pi
        else: self._lon_corr = 0
        lons_rad += self._lon_corr

        # initialize lat-lon interpolator
        if reggrid:  # regular grid
            if len(lats) > 2 and len(lons) > 2:
                self.interp_ll = RectSphereBivariateSpline(u=lats_rad,
                                                           v=lons_rad,
                                                           r=values)
            elif len(lats) > 1 and len(lons) > 1:
                z = np.swapaxes(values, 0, 1)
                self.interp_ll = interp2d(x=lats_rad,
                                          y=lons_rad,
                                          z=z,
                                          kind='linear')
            elif len(lats) == 1:
                self.interp_ll = interp1d(x=lons_rad,
                                          y=np.squeeze(values),
                                          kind='linear')
            elif len(lons) == 1:
                self.interp_ll = interp1d(x=lats_rad,
                                          y=np.squeeze(values),
                                          kind='linear')

        else:  # irregular grid
            if len(np.unique(lats)) <= 1 or len(np.unique(lons)) <= 1:
                self.interp_ll = GridData2D(u=lats_rad,
                                            v=lons_rad,
                                            r=values,
                                            method='nearest')

            elif method_irreg == 'regularize':

                # initialize interpolators on irregular grid
                if len(np.unique(lats)) >= 2 and len(np.unique(lons)) >= 2:
                    method = 'linear'
                else:
                    method = 'nearest'
                gd = GridData2D(u=lats_rad,
                                v=lons_rad,
                                r=values,
                                method=method)
                gd_near = GridData2D(u=lats_rad,
                                     v=lons_rad,
                                     r=values,
                                     method='nearest')

                # determine bin size for regular grid
                lat_diffs = np.diff(np.sort(np.unique(lats)))
                lat_diffs = lat_diffs[lat_diffs > 1e-4]
                lon_diffs = np.diff(np.sort(np.unique(lons)))
                lon_diffs = lon_diffs[lon_diffs > 1e-4]
                bin_size = (np.min(lat_diffs), np.min(lon_diffs))

                # regular grid that data will be mapped to
                lats_reg, lons_reg = self._create_grid(lats=lats,
                                                       lons=lons,
                                                       bin_size=bin_size,
                                                       max_bins=bins_irreg_max)

                # map to regular grid
                lats_reg_rad, lons_reg_rad = torad(lats_reg, lons_reg)
                lons_reg_rad += self._lon_corr
                vi = gd(theta=lats_reg_rad, phi=lons_reg_rad, grid=True)
                vi_near = gd_near(theta=lats_reg_rad,
                                  phi=lons_reg_rad,
                                  grid=True)
                indices_nan = np.where(np.isnan(vi))
                vi[indices_nan] = vi_near[indices_nan]

                # initialize interpolator on regular grid
                self.interp_ll = RectSphereBivariateSpline(u=lats_reg_rad,
                                                           v=lons_reg_rad,
                                                           r=vi)

            else:
                self.interp_ll = GridData2D(u=lats_rad,
                                            v=lons_rad,
                                            r=values,
                                            method=method_irreg)

        # store data used for interpolation
        self.lat_nodes = lats
        self.lon_nodes = lons
        self.values = values

    def get_nodes(self):
        return (self.values, self.lat_nodes, self.lon_nodes)

    def interp_xy(self, x, y, grid=False, x_deriv_order=0, y_deriv_order=0):
        """ Interpolate using planar coordinate system (xy).

            x and y can be floats or arrays.

            If grid is set to False, the interpolation will be evaluated at
            the positions (x_i, y_i), where x=(x_1,...,x_N) and
            y=(y_1,...,y_N). Note that in this case, x and y must have
            the same length.

            If grid is set to True, the interpolation will be evaluated at
            all combinations (x_i, y_j), where x=(x_1,...,x_N) and
            y=(y_1,...,y_M). Note that in this case, the lengths of x
            and y do not have to be the same.

            Args:
                x: float or array
                   x-coordinate of the positions(s) where the interpolation is to be evaluated
                y: float or array
                   y-coordinate of the positions(s) where the interpolation is to be evaluated
                grid: bool
                   Specify how to combine elements of x and y.
                x_deriv_order: int
                    Order of x-derivative
                y_deriv_order: int
                    Order of y-derivative

            Returns:
                zi: Interpolated interpolation values
        """
        lat, lon = XYtoLL(x=x,
                          y=y,
                          lat_ref=self.origin[0],
                          lon_ref=self.origin[1],
                          grid=grid)

        if grid:
            M = lat.shape[0]
            N = lat.shape[1]
            lat = np.reshape(lat, newshape=(M * N))
            lon = np.reshape(lon, newshape=(M * N))

        zi = self.interp(lat=lat,
                         lon=lon,
                         squeeze=False,
                         lat_deriv_order=y_deriv_order,
                         lon_deriv_order=x_deriv_order)

        if x_deriv_order + y_deriv_order > 0:
            r = DLDL_over_DXDY(lat=lat,
                               lat_deriv_order=y_deriv_order,
                               lon_deriv_order=x_deriv_order)
            zi *= r

        if grid:
            zi = np.reshape(zi, newshape=(M, N))

        if np.ndim(zi) == 2:
            zi = np.swapaxes(zi, 0, 1)

        zi = np.squeeze(zi)

        if np.ndim(zi) == 0 or (np.ndim(zi) == 1 and len(zi) == 1):
            zi = float(zi)

        return zi

    def interp(self,
               lat,
               lon,
               grid=False,
               squeeze=True,
               lat_deriv_order=0,
               lon_deriv_order=0):
        """ Interpolate using spherical coordinate system (latitude-longitude).

            lat and lot can be floats or arrays.

            If grid is set to False, the interpolation will be evaluated at
            the coordinates (lat_i, lon_i), where lat=(lat_1,...,lat_N)
            and lon=(lon_1,...,lon_N). Note that in this case, lat and
            lon must have the same length.

            If grid is set to True, the interpolation will be evaluated at
            all combinations (lat_i, lon_j), where lat=(lat_1,...,lat_N)
            and lon=(lon_1,...,lon_M). Note that in this case, the lengths
            of lat and lon do not have to be the same.

            Derivates are given per radians^n, where n is the overall
            derivative order.

            Args:
                lat: float or array
                    latitude of the positions(s) where the interpolation is to be evaluated
                lon: float or array
                    longitude of the positions(s) where the interpolation is to be evaluated
                grid: bool
                    Specify how to combine elements of lat and lon. If lat and lon have different
                    lengths, specifying grid has no effect as it is automatically set to True.
                lat_deriv_order: int
                    Order of latitude-derivative
                lon_deriv_order: int
                    Order of longitude-derivative

            Returns:
                zi: Interpolated values (or derivates)
        """
        lat = np.squeeze(np.array(lat))
        lon = np.squeeze(np.array(lon))
        lat_rad, lon_rad = torad(lat, lon)
        lon_rad += self._lon_corr

        if isinstance(self.interp_ll, interp2d):
            zi = self.interp_ll.__call__(x=lat_rad,
                                         y=lon_rad,
                                         dx=lat_deriv_order,
                                         dy=lon_deriv_order)
            if grid: zi = np.swapaxes(zi, 0, 1)
            if not grid and np.ndim(zi) == 2: zi = np.diagonal(zi)

        elif isinstance(self.interp_ll, interp1d):
            if len(self.lat_nodes) > 1:
                zi = self.interp_ll(x=lat_rad)
            elif len(self.lon_nodes) > 1:
                zi = self.interp_ll(x=lon_rad)

        else:
            zi = self.interp_ll.__call__(theta=lat_rad,
                                         phi=lon_rad,
                                         grid=grid,
                                         dtheta=lat_deriv_order,
                                         dphi=lon_deriv_order)

        if squeeze:
            zi = np.squeeze(zi)

        if np.ndim(zi) == 0 or (np.ndim(zi) == 1 and len(zi) == 1):
            zi = float(zi)

        return zi

    def _create_grid(self, lats, lons, bin_size, max_bins):
        """ Created regular lat-lon grid with uniform spacing that covers
            a set of (lat,lon) coordinates.

            Args:
                lats: numpy.array
                    Latitude values in degrees
                lons: numpy.array
                    Longitude values in degrees
                bin_size: float or tuple(float,float)
                    Lat and long bin size
                max_bins: int
                    Maximum number of bins along either axis

            Returns:
                : numpy.array, numpy.array
                    Latitude and longitude values of the regular grid
        """
        if isinstance(bin_size, (int, float)): bin_size = (bin_size, bin_size)
        res = []
        for v, dv in zip([lats, lons], bin_size):
            v_min = np.min(v) - dv
            v_max = np.max(v) + dv
            num = max(3, int((v_max - v_min) / dv) + 1)
            num = min(max_bins, num)
            v_reg = np.linspace(v_min, v_max, num=num)
            res.append(v_reg)

        return tuple(res)
	def interpol(latitude,longitude,variable):
		''' This thing interpolates
		'''
		lut=RSBS(latitude,longitude,variable)
		interpolated_vairable=lut.ev(latai.ravel(),lonai.ravel()).reshape((361, 576))
		return interpolated_vairable
Exemplo n.º 16
0
"""
This is an example test for scipy RectSphereBivariateSpline interpolator.
It is meant to be used for approximation of a rectangular grid on a sphere,

e.g., for lat/lon interpolation.
"""
import numpy as np
from scipy.interpolate import RectSphereBivariateSpline
import matplotlib.pyplot as plt

lats = np.linspace(10, 170, 9) * np.pi / 180.
lons = np.linspace(0, 350, 18) * np.pi / 180.
data = np.dot(np.atleast_2d(90. - np.linspace(-80., 80., 18)).T,
               np.atleast_2d(180. - np.abs(np.linspace(0., 350., 9)))).T

new_lats = np.linspace(1, 180, 180) * np.pi / 180
new_lons = np.linspace(1, 360, 360) * np.pi / 180
new_lats, new_lons = np.meshgrid(new_lats, new_lons)

lut = RectSphereBivariateSpline(lats, lons, data)
data_interp = lut.ev(new_lats.ravel(),
                     new_lons.ravel()).reshape((360, 180)).T

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax1.imshow(data, interpolation='nearest')
ax2 = fig.add_subplot(212)
ax2.imshow(data_interp, interpolation='nearest')
plt.show()
lons = np.linspace(0, 350, 18) * np.pi / 180.
data = np.dot(
    np.atleast_2d(90. - np.linspace(-80., 80., 18)).T,
    np.atleast_2d(180. - np.abs(np.linspace(0., 350., 9)))).T

# We want to interpolate it to a global one-degree grid

new_lats = np.linspace(1, 180, 180) * np.pi / 180
new_lons = np.linspace(1, 360, 360) * np.pi / 180
new_lats, new_lons = np.meshgrid(new_lats, new_lons)

# We need to set up the interpolator object

from scipy.interpolate import RectSphereBivariateSpline

lut = RectSphereBivariateSpline(lats, lons, data)

# Finally we interpolate the data.  The `RectSphereBivariateSpline` object
# only takes 1-D arrays as input, therefore we need to do some reshaping.

data_interp = lut.ev(new_lats.ravel(), new_lons.ravel()).reshape((360, 180)).T

# Looking at the original and the interpolated data, one can see that the
# interpolant reproduces the original data very well:

import matplotlib.pyplot as plt

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax1.imshow(data, interpolation='nearest')
ax2 = fig.add_subplot(212)
Exemplo n.º 18
0
def create_model(nside, file_name=None):
    """Takes feko .ffe reference model, converts into healpix and smooths the response

    :param nside: Healpix nside
    :param file_name: Path to :samp:`.ffe` feko model of reference tiles

    :returns:
        - :class:`tuple` of (beam_response, theta_mesh, phi_mesh, power, theta)

    """

    # Make an empty array for healpix projection
    len_empty_healpix = hp.nside2npix(nside)
    beam_response = np.zeros(len_empty_healpix) * np.nan

    # Had problems with having coords = 0 when interpolating, so make a small number
    # and call it epsilon for some reason
    epsilon = 1.0e-12

    # Load ffe model data in, which is stored in real and imaginary components
    # of a phi/theta polaristaion representation of the beam
    # apparently this is normal to beam engineers

    data = np.loadtxt(file_name)
    theta = data[:, 0]
    re_theta = data[:, 2]
    im_theta = data[:, 3]
    re_phi = data[:, 4]
    im_phi = data[:, 5]

    # Convert to complex numbers
    X_theta = re_theta.astype(complex)
    X_theta.imag = im_theta

    X_phi = re_phi.astype(complex)
    X_phi.imag = im_phi

    # make a coord grid for the data in the .ffe model
    theta_range = np.linspace(epsilon, 90, 91)
    phi_range = np.linspace(epsilon, 359.0, 360)
    theta_mesh, phi_mesh = np.meshgrid(theta_range, phi_range)

    # Convert reference model into power from the complex values
    power = 10 * np.log10(abs(X_theta)**2 + abs(X_phi)**2)

    # Make an inf values super small
    power[np.where(power == -np.inf)] = -80

    # Had a problem with edge effects, leave off near horizon values
    # Basically remove the last 90 values of power list, where θ == 90
    power = power[:-91]

    # Get things into correct shape and do an interpolation
    power.shape = phi_mesh.shape

    # Bivariate spline approximation over a rectangular mesh on a sphere
    # s is a paramater I had to play with to get by eye nice results
    # s: positive smoothing factor
    lut = RectSphereBivariateSpline(theta_range * (np.pi / 180.0),
                                    phi_range * (np.pi / 180.0),
                                    power.T,
                                    s=0.1)

    # Get the theta and phi of all healpixels
    i_pix = np.arange(hp.nside2npix(nside))
    theta_rad, phi_rad = hp.pix2ang(nside, i_pix)

    # Evaluate the interpolated function at healpix gridpoints
    # Use spline to map beam into healpixels
    beam_response = lut.ev(theta_rad, phi_rad)

    # rescale beam response to have peak value of 0 dB
    beam_response = beam_response - np.nanmax(beam_response)

    return beam_response, theta_mesh, phi_mesh, power, theta
	PM1  = fn.variables['DUSMASS25_avg'][:]*1e9
	PM2  = fn.variables['SSSMASS25_avg'][:]*1e9
	PM3  = fn.variables['SO4SMASS_avg' ][:]*1e9*1.375
	PM4  = fn.variables['OCSMASS_avg'  ][:]*1e9
	PM5  = fn.variables['BCSMASS_avg'  ][:]*1e9
	PM25 = PM1+PM2+PM3+PM4+PM5   # By Definition from MERRAero
	fn.close(); del fn

	clon=-98.5795 # central lat/lon for imaging. Dead-center of US.
	clat= 39.8282

	# ----------------------------------------------------------------
	# Interpolates coarse (144x288) 500 hPa data into finer (361x540)
	# surface grid.

	lut=RSBS(latp5,lonp5,u5)
	u5i=lut.ev(lat2.ravel(),lon2.ravel()).reshape((361, 540))
	del lut
	lut=RSBS(latp5,lonp5,v5)
	v5i=lut.ev(lat2.ravel(),lon2.ravel()).reshape((361, 540))
	del lut
	lut=RSBS(latp5,lonp5,hgt)
	hgti=lut.ev(lat2.ravel(),lon2.ravel()).reshape((361, 540));

	del hgt, u5, v5, lonp5, latp5, lonp2, latp2, lon2, lat2, lon5, lat5

	#fig = plt.figure()
	#ax1 = fig.add_subplot(211)
	#ax1.imshow(hgt, interpolation='nearest')
	#ax2 = fig.add_subplot(212)
	#ax2.imshow(hgti, interpolation='nearest')
Exemplo n.º 20
0
def apply_gsrm(sites_of_retain3_pv, ITRF_ID, dir_file_gsrm):

    # read the lons, lats, and heights
    width = (5, 3, 10, 25, 4, 3, 5, 4, 3, 5, 8)
    data_lonlat = np.genfromtxt(ITRF_ID,
                                delimiter=width,
                                dtype=np.str,
                                skip_header=2,
                                skip_footer=1,
                                autostrip=True)
    n = len(data_lonlat)
    code_pt = np.core.defchararray.add(data_lonlat[:, 0], data_lonlat[:, 1])

    CODE_PT = sites_of_retain3_pv['CODE'] + sites_of_retain3_pv['PT']
    _, __, _index = np.intersect1d(CODE_PT, code_pt, return_indices=True)
    sites_of_retain3_lonlat = data_lonlat[_index]

    # convert lons and lats of sites in [d,m,s] to lons and colats in radian
    sites_of_retain3_lons = np.array(sites_of_retain3_lonlat[:, 4:7],
                                     dtype=np.float)
    sites_of_retain3_geod_lats = np.array(sites_of_retain3_lonlat[:, 7:10],
                                          dtype=np.float)

    sites_of_retain3_lons = [tuple(x) for x in sites_of_retain3_lons]
    sites_of_retain3_geod_lats = [tuple(x) for x in sites_of_retain3_geod_lats]

    sites_of_retain3_lons_deg = Angle(sites_of_retain3_lons, unit=u.deg)
    sites_of_retain3_lats_geod_deg = Angle(sites_of_retain3_geod_lats,
                                           unit=u.deg)
    sites_of_retain3_lats_deg = geode2geocen(sites_of_retain3_lats_geod_deg)

    sites_of_retain3_lons = sites_of_retain3_lons_deg.rad
    sites_of_retain3_lats = sites_of_retain3_lats_deg.to(u.rad).value

    df = pd.DataFrame(sites_of_retain3_lonlat[:, :4],
                      columns=['CODE', 'PT', 'DOMES', 'STATION DESCRIPTION'])
    df['Geod. Lat. °N'] = sites_of_retain3_lats_geod_deg
    df['Lat. °N'] = sites_of_retain3_lats_deg
    df['Lon. °E'] = sites_of_retain3_lons_deg
    df['H'] = sites_of_retain3_lonlat[:, -1]
    sites_of_retain3_lonlat = df

    sites_of_retain3_colats = np.pi / 2 - sites_of_retain3_lats

    # read the GSRMv2.1
    data_gsrmv21 = np.loadtxt(dir_file_gsrm)

    # calculate second invariant strain rate
    sisr = np.sqrt(data_gsrmv21[:, 8]**2 + data_gsrmv21[:, 9]**2).reshape(
        1750, 3600)

    # flip the lons and lats
    sisr = np.flip(sisr, 0)
    sisr[:, :1800], sisr[:, 1800:] = sisr[:,
                                          1800:].copy(), sisr[:, :1800].copy()

    # lons and lats after flipping
    lons = np.linspace(0.05, 359.95, 3600)
    lats = np.linspace(87.45, -87.45, 1750)

    # colats and lons in radians
    colats_rad = np.deg2rad(90 - lats)
    lons_rad = np.deg2rad(lons)

    lut = RectSphereBivariateSpline(colats_rad, lons_rad, sisr)

    sisr_sites = lut.ev(sites_of_retain3_colats, sites_of_retain3_lons)

    sites_of_retain4_lonlat = sites_of_retain3_lonlat[
        sisr_sites < 0.1].reset_index(drop=True)

    CODE = sites_of_retain4_lonlat['CODE']
    CODE_pv = sites_of_retain3_pv['CODE']

    _, _index, __ = np.intersect1d(CODE_pv, CODE, return_indices=True)
    sites_of_retain4_pv = sites_of_retain3_pv.loc[_index].reset_index(
        drop=True)
    sites_of_retain4 = pd.merge(sites_of_retain4_lonlat,
                                sites_of_retain4_pv,
                                on=['CODE', 'PT'],
                                validate="one_to_one")

    return sites_of_retain4
Exemplo n.º 21
0
def interpolate_RSBS(data,
                     sz,
                     lon1=None,
                     lon2=None,
                     lat1=None,
                     lat2=None,
                     fignum=None):
    # interpolate using scipy.interpolate.RectSphereBivariateSpline
    #
    # this needs some tuning, but it appears to be working and semi-functional
    # ... but tends to break for complex array. let's try scipy.interp2d():
    #http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.interpolate.interp2d.html
    #
    print('data: ', data[0:5])
    #
    lons = sorted(list(set([x for x, y, z in data])))
    lats = sorted(list(set([y for x, y, z in data])))
    #print('lls: ', len(lats), len(lons))
    data = numpy.reshape([rw[2] for rw in data], (len(lats), len(lons)))
    #print('sh: ', numpy.shape(data))
    #####
    plt.figure(fignum + 2)
    plt.clf()
    ax1 = plt.gca()
    ax1.imshow(data, interpolation='nearest')
    #####
    #
    lon1 = (lon1 or min(lons))
    lon2 = (lon2 or max(lons))
    lat1 = (lat1 or min(lats))
    lat2 = (lat2 or max(lats))
    #
    #new_lats = np.linspace(1, 180, 180) * np.pi / 180
    #new_lons = np.linspace(1, 360, 360) * np.pi / 180
    new_lats = np.linspace(lat1, lat2, sz[0]) * np.pi / 180
    new_lons = np.linspace(lon1, lon2, sz[1]) * np.pi / 180
    new_lats, new_lons = np.meshgrid(new_lats, new_lons)

    # We need to set up the interpolator object

    #from scipy.interpolate import RectSphereBivariateSpline
    lut = RectSphereBivariateSpline(lats, lons, data)
    #
    #lut = RectBivariateSpline(lats, lons, data)
    print(len(new_lats), len(new_lons[0]), len(data), len(data[0]),
          new_lats.shape)

    # Finally we interpolate the data.  The `RectSphereBivariateSpline` object
    # only takes 1-D arrays as input, therefore we need to do some reshaping.

    data_interp = lut.ev(new_lats.ravel(),
                         new_lons.ravel()).reshape(new_lats.shape).T

    # Looking at the original and the interpolated data, one can see that the
    # interpolant reproduces the original data very well:
    #
    if fignum != None:
        fig = plt.figure(fignum + 0)
        ax1 = fig.add_subplot(211)
        ax1.imshow(data, interpolation='nearest')
        ax2 = fig.add_subplot(212)
        ax2.imshow(data_interp, interpolation='nearest')
        plt.show()
        #
        # Chosing the optimal value of ``s`` can be a delicate task. Recommended
        # values for ``s`` depend on the accuracy of the data values.  If the user
        # has an idea of the statistical errors on the data, she can also find a
        # proper estimate for ``s``. By assuming that, if she specifies the
        # right ``s``, the interpolator will use a spline ``f(u,v)`` which exactly
        # reproduces the function underlying the data, she can evaluate
        # ``sum((r(i,j)-s(u(i),v(j)))**2)`` to find a good estimate for this ``s``.
        # For example, if she knows that the statistical errors on her
        # ``r(i,j)``-values are not greater than 0.1, she may expect that a good
        # ``s`` should have a value not larger than ``u.size * v.size * (0.1)**2``.

        # If nothing is known about the statistical error in ``r(i,j)``, ``s`` must
        # be determined by trial and error.  The best is then to start with a very
        # large value of ``s`` (to determine the least-squares polynomial and the
        # corresponding upper bound ``fp0`` for ``s``) and then to progressively
        # decrease the value of ``s`` (say by a factor 10 in the beginning, i.e.
        # ``s = fp0 / 10, fp0 / 100, ...``  and more carefully as the approximation
        # shows more detail) to obtain closer fits.

        # The interpolation results for different values of ``s`` give some insight
        # into this process:

        fig2 = plt.figure(fignum + 1)
        s = [3e9, 2e9, 1e9, 1e8]
        for ii in range(len(s)):
            #lut = RectSphereBivariateSpline(lats, lons, data, s=s[ii])
            RectBivariateSpline(lats, lons, data, s=s[ii])
            data_interp = lut.ev(new_lats.ravel(),
                                 new_lons.ravel()).reshape(new_lons.shape).T
            ax = fig2.add_subplot(2, 2, ii + 1)
            ax.imshow(data_interp, interpolation='nearest')
            ax.set_title("s = %g" % s[ii])
    plt.show()
Exemplo n.º 22
0
def main():
    # Suppose we have global data on a coarse grid
    import numpy as np

    lats = np.linspace(10, 170, 9) * np.pi / 180.
    lons = np.linspace(0, 350, 18) * np.pi / 180.
    data = np.dot(
        np.atleast_2d(90. - np.linspace(-80., 80., 18)).T,
        np.atleast_2d(180. - np.abs(np.linspace(0., 350., 9)))).T

    # We want to interpolate it to a global one-degree grid

    new_lats = np.linspace(1, 180, 180) * np.pi / 180
    new_lons = np.linspace(1, 360, 360) * np.pi / 180
    new_lats, new_lons = np.meshgrid(new_lats, new_lons)

    # We need to set up the interpolator object

    from scipy.interpolate import RectSphereBivariateSpline
    lut = RectSphereBivariateSpline(lats, lons, data)

    # Finally we interpolate the data.  The `RectSphereBivariateSpline` object
    # only takes 1-D arrays as input, therefore we need to do some reshaping.

    data_interp = lut.ev(new_lats.ravel(), new_lons.ravel()).reshape(
        (360, 180)).T

    # Looking at the original and the interpolated data, one can see that the
    # interpolant reproduces the original data very well:

    import matplotlib.pyplot as plt
    fig = plt.figure()
    ax1 = fig.add_subplot(211)
    ax1.imshow(data, interpolation='nearest')
    ax2 = fig.add_subplot(212)
    ax2.imshow(data_interp, interpolation='nearest')
    plt.show()

    # Chosing the optimal value of ``s`` can be a delicate task. Recommended
    # values for ``s`` depend on the accuracy of the data values.  If the user
    # has an idea of the statistical errors on the data, she can also find a
    # proper estimate for ``s``. By assuming that, if she specifies the
    # right ``s``, the interpolator will use a spline ``f(u,v)`` which exactly
    # reproduces the function underlying the data, she can evaluate
    # ``sum((r(i,j)-s(u(i),v(j)))**2)`` to find a good estimate for this ``s``.
    # For example, if she knows that the statistical errors on her
    # ``r(i,j)``-values are not greater than 0.1, she may expect that a good
    # ``s`` should have a value not larger than ``u.size * v.size * (0.1)**2``.

    # If nothing is known about the statistical error in ``r(i,j)``, ``s`` must
    # be determined by trial and error.  The best is then to start with a very
    # large value of ``s`` (to determine the least-squares polynomial and the
    # corresponding upper bound ``fp0`` for ``s``) and then to progressively
    # decrease the value of ``s`` (say by a factor 10 in the beginning, i.e.
    # ``s = fp0 / 10, fp0 / 100, ...``  and more carefully as the approximation
    # shows more detail) to obtain closer fits.

    # The interpolation results for different values of ``s`` give some insight
    # into this process:

    fig2 = plt.figure()
    s = [3e9, 2e9, 1e9, 1e8]
    for ii in range(len(s)):
        lut = RectSphereBivariateSpline(lats, lons, data, s=s[ii])
        data_interp = lut.ev(new_lats.ravel(), new_lons.ravel()).reshape(
            (360, 180)).T
        ax = fig2.add_subplot(2, 2, ii + 1)
        ax.imshow(data_interp, interpolation='nearest')
        ax.set_title("s = %g" % s[ii])
    plt.show()
Exemplo n.º 23
0
    def __init__(self,
                 values,
                 lats,
                 lons,
                 origin=None,
                 method_irreg='regularize',
                 bins_irreg_max=400):

        # compute coordinates of origin, if not provided
        if origin is None: origin = center_point(lats, lons)
        self.origin = origin

        # check if bathymetry data are on a regular or irregular grid
        reggrid = (np.ndim(values) == 2)

        # convert to radians
        lats_rad, lons_rad = torad(lats, lons)

        # necessary to resolve a mismatch between scipy and underlying Fortran code
        # https://github.com/scipy/scipy/issues/6556
        if np.min(lons_rad) < 0: self._lon_corr = np.pi
        else: self._lon_corr = 0
        lons_rad += self._lon_corr

        # initialize lat-lon interpolator
        if reggrid:  # regular grid
            if len(lats) > 2 and len(lons) > 2:
                self.interp_ll = RectSphereBivariateSpline(u=lats_rad,
                                                           v=lons_rad,
                                                           r=values)
            elif len(lats) > 1 and len(lons) > 1:
                z = np.swapaxes(values, 0, 1)
                self.interp_ll = interp2d(x=lats_rad,
                                          y=lons_rad,
                                          z=z,
                                          kind='linear')
            elif len(lats) == 1:
                self.interp_ll = interp1d(x=lons_rad,
                                          y=np.squeeze(values),
                                          kind='linear')
            elif len(lons) == 1:
                self.interp_ll = interp1d(x=lats_rad,
                                          y=np.squeeze(values),
                                          kind='linear')

        else:  # irregular grid
            if len(np.unique(lats)) <= 1 or len(np.unique(lons)) <= 1:
                self.interp_ll = GridData2D(u=lats_rad,
                                            v=lons_rad,
                                            r=values,
                                            method='nearest')

            elif method_irreg == 'regularize':

                # initialize interpolators on irregular grid
                if len(np.unique(lats)) >= 2 and len(np.unique(lons)) >= 2:
                    method = 'linear'
                else:
                    method = 'nearest'
                gd = GridData2D(u=lats_rad,
                                v=lons_rad,
                                r=values,
                                method=method)
                gd_near = GridData2D(u=lats_rad,
                                     v=lons_rad,
                                     r=values,
                                     method='nearest')

                # determine bin size for regular grid
                lat_diffs = np.diff(np.sort(np.unique(lats)))
                lat_diffs = lat_diffs[lat_diffs > 1e-4]
                lon_diffs = np.diff(np.sort(np.unique(lons)))
                lon_diffs = lon_diffs[lon_diffs > 1e-4]
                bin_size = (np.min(lat_diffs), np.min(lon_diffs))

                # regular grid that data will be mapped to
                lats_reg, lons_reg = self._create_grid(lats=lats,
                                                       lons=lons,
                                                       bin_size=bin_size,
                                                       max_bins=bins_irreg_max)

                # map to regular grid
                lats_reg_rad, lons_reg_rad = torad(lats_reg, lons_reg)
                lons_reg_rad += self._lon_corr
                vi = gd(theta=lats_reg_rad, phi=lons_reg_rad, grid=True)
                vi_near = gd_near(theta=lats_reg_rad,
                                  phi=lons_reg_rad,
                                  grid=True)
                indices_nan = np.where(np.isnan(vi))
                vi[indices_nan] = vi_near[indices_nan]

                # initialize interpolator on regular grid
                self.interp_ll = RectSphereBivariateSpline(u=lats_reg_rad,
                                                           v=lons_reg_rad,
                                                           r=vi)

            else:
                self.interp_ll = GridData2D(u=lats_rad,
                                            v=lons_rad,
                                            r=values,
                                            method=method_irreg)

        # store data used for interpolation
        self.lat_nodes = lats
        self.lon_nodes = lons
        self.values = values
def scatter_along_los(dhf,
                      tau0,
                      P,
                      h,
                      th_look,
                      phi_look,
                      om=1.,
                      q=None,
                      full_fov_deg=None,
                      M=20,
                      N=20,
                      R=20,
                      N_int=30,
                      R_int=30,
                      Q_int=30,
                      tol=1e-4,
                      K=20,
                      verbose=True):
    '''
    For given lines of sight, calculate the direct and scattered brightness measurements, for both
    the in-FoV and out-of-FoV (i.e., stray light) components.
    
    dhf: function that takes x,y and returns the column brightness
    tau0: optical thickness of atmosphere
    P: scattering phase function P(u0,u1,phi0,phi1)
    h: height of airglow layer [m]
    th_look:  (array) zenith angle of observation (deg, geophysical convention)
    phi_look: (array) azimuth angle of observation (deg, geophysical convention)
    om: single-scattering albedo
    q: stray light function (None = ignore stray light)
    full_fov_deg: the field of view in degrees (only used if q is specified)
    M: number of tau grid points
    N: number of u grid points
    R: number of phi grid points
    N_int: number of u grid points to use in sky integration
    R_int: number of phi grid points to use in sky integration
    Q_int: number of u and phi grid points to use in stray light calculation
    tol: stop iterating when the relative change in the solution is less than this
    K: maximum iterations
    verbose: whether to print progress
    
    Returns:
    g_sc:  (array) measured brightness from atmospheric scattering
    g_dir: (array) measured brightness from direct ray
    s_sc:  (array) measured brightness from stray light of scattered signal
    s_dir: (array) measured brightness from stray light of direct signal
    '''

    Ifull, tau, u_bounds, phi_bounds = white_light_scatter(dhf,
                                                           tau0,
                                                           P,
                                                           h,
                                                           om=om,
                                                           M=M,
                                                           N=N,
                                                           R=R,
                                                           N_int=N_int,
                                                           R_int=R_int,
                                                           tol=tol,
                                                           K=K,
                                                           verbose=verbose)

    # Precalculate interpolation function
    ui = (u_bounds[1:] + u_bounds[:-1]) / 2
    phii = (phi_bounds[1:] + phi_bounds[:-1]) / 2
    thi = arccos(ui)[::-1]

    ######## VERSION USING ROTATED COORDINATES #############
    Ii = Ifull[-1, ::-1, :]

    # There is a discontinuity at u=0 (th=pi/2), so interpolate over either
    # the top half or bottom half plane. In practice, we only need the bottom.
    # Another detail is that we should specify a point at zenith, otherwise
    # it's extrapolating.
    zenith_val = np.mean(Ii[0, :])
    # Define interpolation for phi in 90 to 270
    Iint0 = RectSphereBivariateSpline(thi[:N / 2],
                                      phii,
                                      Ii[:N / 2, :],
                                      pole_values=(zenith_val, None))
    # Define interpolation for phi in 270 to 90, using a rotated coordinate system to avoid problems at phi=0
    r0 = sum(phii < pi / 2) + 1  # index just after 90 deg
    r1 = sum(phii < 3 * pi / 2) - 1  # index just before 270 deg
    phii_rot = np.concatenate((phii[r1:] - 2 * pi, phii[:r0 + 1])) + pi
    Ii_rot = np.concatenate((Ii[:, r1:], Ii[:, :r0 + 1]), axis=1)
    Iint1 = RectSphereBivariateSpline(thi[:N / 2],
                                      phii_rot,
                                      Ii_rot[:N / 2, :],
                                      pole_values=(zenith_val, None))

    def I_sc(u, phi):
        '''
        Given a calculated, discretized, scattered intensity (Ifull), evaluate it 
        at the given u, phi. Use linear interpolation on a sphere.
        Global variables: Iint0, Iint1
        '''
        if phi > np.pi / 2 and phi < 3 * np.pi / 2:
            return Iint0(arccos(u), phi).item()
        else:
            phi_rot = np.mod(phi + pi, 2 * pi)
            return Iint1(arccos(u), phi_rot).item()

    def I_dir(dhf, tau0, u, phi):
        '''
        Evaluate the direct intensity.
        Global variables: RE,h
        '''
        if u <= 0.0:
            return 0.0  # no incident light looking downwards
        th = arccos(u)
        gamma = arcsin(RE / (RE + h) * sqrt(1 - u**2))
        rho = (th - gamma) * (RE + h)
        x = -rho * cos(phi)
        y = -rho * sin(phi)
        return dhf(x, y) * sec(gamma) * exp(-tau0 / u)

    # Determine correct u,phi (in math coordinates, incoming ray convention) to use
    # for direct signal
    g_sc = []
    g_dir = []
    for i in range(len(th_look)):
        u_dir = cos(th_look[i] * pi / 180)
        phi_dir = mod(pi / 2 - phi_look[i] * pi / 180 + pi, 2 * pi)
        g_sc.append(I_sc(u_dir, phi_dir))
        g_dir.append(I_dir(dhf, tau0, u_dir, phi_dir))

    g_sc = array(g_sc)
    g_dir = array(g_dir)

    # Stray light calculation, if desired:
    s_sc = zeros(len(g_sc))
    s_dir = zeros(len(g_dir))
    if q:  # Grid points for stray light integral:
        if full_fov_deg is None:
            raise Exception(
                'If "q" is specified, "full_fov_deg" needs to be specified')
        dS = 2 * pi * (1 - cos(full_fov_deg / 2 * pi / 180))  # solid angle

        th_bound_vec = linspace(pi / 2, full_fov_deg / 2 * pi / 180,
                                Q_int + 1)  # don't include FoV
        u_bound_vec = cos(th_bound_vec)
        u_vec = (u_bound_vec[1:] + u_bound_vec[:-1]) / 2
        du_vec = u_bound_vec[1:] - u_bound_vec[:-1]

        phi_bound_vec = linspace(0, 2 * pi, Q_int + 1)
        phi_vec = (phi_bound_vec[1:] + phi_bound_vec[:-1]) / 2
        dphi_vec = phi_bound_vec[1:] - phi_bound_vec[:-1]

        for looki in range(len(th_look)):
            # Collect integral term at each grid point
            d_gsc_stray = zeros(
                (Q_int, Q_int)
            )  # terms of integral at each grid point (see notes 2016-03-28)
            d_gdir_stray = zeros(
                (Q_int, Q_int)
            )  # terms of integral at each grid point (see notes 2016-03-28)
            for i in range(Q_int):
                for j in range(Q_int):
                    th = arccos(u_vec[i])
                    ph = phi_vec[j]
                    # th (rad) is the angle of the incoming ray relative to -z
                    # ph (rad) is the (math-convention) azimuth angle of the incoming ray
                    # th_look (deg) is the angle of the look direction relative to +z
                    # phi_look (deg) is the (geophysical-convention) azimuth angle of the look direction
                    th_look_rad = th_look[looki] * pi / 180
                    phi_look_rad = phi_look[looki] * pi / 180
                    # unit vector (x,y,z)=(E,N,U) of look direction
                    look = [
                        sin(th_look_rad) * sin(phi_look_rad),
                        sin(th_look_rad) * cos(phi_look_rad),
                        cos(th_look_rad)
                    ]
                    # unit vector (x,y,z)=(E,N,U) of direction to source
                    src = [-sin(th) * cos(ph), -sin(th) * sin(ph), cos(th)]
                    angle_between = arccos(np.dot(look, src))
                    d_gsc_stray[i,j] = u_vec[i] * I_sc(u_vec[i],phi_vec[j]) * q(angle_between) * \
                                       du_vec[i] * dphi_vec[j]
                    d_gdir_stray[i,j] = u_vec[i] * I_dir(dhf,tau0, u_vec[i],phi_vec[j]) * q(angle_between) * \
                                       du_vec[i] * dphi_vec[j]

            # Add these stray components to the previously-calculated in-FoV component, of both
            # the direct and atmosphere-scattered signal.
            # Determine correct u,phi (in math coordinates, incoming ray convention) to use
            # for direct signal.
            # Technically I should scale the in-FoV component by dS, but that's the same as
            # scaling the stray component by 1/dS. (For backwards compatibility).
            u_dir = cos(th_look[looki] * pi / 180)
            phi_dir = mod(pi / 2 - phi_look[looki] * pi / 180 + pi, 360)
            s_sc[looki] = 1 / dS * sum(d_gsc_stray)
            s_dir[looki] = 1 / dS * sum(d_gdir_stray)

    return g_sc, g_dir, s_sc, s_dir
Exemplo n.º 25
0
    def _calculate_spatial(self):
        """
        Pre-calculate the relative Zodiacal Light brightness variation with sky position
        """
        # Normalise scaling factor to a value of 1.0 at the NEP
        zl_scale = ZodiacalLight.zl_scale / 77

        # Expand range of angles to cover the full sphere by using symmetry
        beta = np.array(
            np.concatenate((-np.flipud(ZodiacalLight.beta)[:-1],
                            ZodiacalLight.beta))) * u.degree
        llsun = np.array(
            np.concatenate(
                (ZodiacalLight.llsun,
                 360 - np.flipud(ZodiacalLight.llsun)[1:-1]))) * u.degree
        zl_scale = np.concatenate((np.flipud(zl_scale)[:-1], zl_scale))
        zl_scale = np.concatenate((zl_scale, np.fliplr(zl_scale)[:, 1:-1]),
                                  axis=1)

        # Convert angles to radians within the required ranges.
        beta = beta.to(u.radian).value + np.pi / 2
        llsun = llsun.to(u.radian).value
        # For initial cartesian interpolation want the hole in the middle of the data,
        # i.e. want to remap longitudes onto -180 to 180, not 0 to 360 degrees.
        # Only want the region of closely spaced data point near to the Sun.
        beta_c = beta[3:-3]
        nl = len(llsun)
        llsun_c = np.concatenate(
            (llsun[nl // 2 + 9:] - 2 * np.pi, llsun[:nl // 2 - 8]))
        zl_scale_c = np.concatenate(
            (zl_scale[3:-3, nl // 2 + 9:], zl_scale[3:-3, :nl // 2 - 8]),
            axis=1)

        # Convert everthing to 1D arrays (lists) of x, y and z coordinates.
        llsuns, betas = np.meshgrid(llsun_c, beta_c)
        llsuns_c = llsuns.ravel()
        betas_c = betas.ravel()
        zl_scale_cflat = zl_scale_c.ravel()

        # Indices of the non-NaN points
        good = np.where(np.isfinite(zl_scale_cflat))

        # 2D cartesian interpolation function
        zl_scale_c_interp = SmoothBivariateSpline(betas_c[good],
                                                  llsuns_c[good],
                                                  zl_scale_cflat[good])

        # Calculate interpolated values
        zl_scale_fill = zl_scale_c_interp(beta_c, llsun_c)

        # Remap the interpolated values back to original ranges of coordinates
        zl_patch = np.zeros(zl_scale.shape)
        zl_patch[3:16, 0:10] = zl_scale_fill[:, 9:]
        zl_patch[3:16, -9:] = zl_scale_fill[:, :9]

        # Fill the hole in the original data with values from the cartesian interpolation
        zl_patched = np.where(np.isfinite(zl_scale), zl_scale, zl_patch)

        # Spherical interpolation function from the full, filled data set
        self._spatial = RectSphereBivariateSpline(beta, llsun, zl_patched, \
                                                  pole_continuity=(False,False), pole_values=(1.0, 1.0), \
                                                  pole_exact=True, pole_flat=False)
Exemplo n.º 26
0
def regular_gldas(lats,lons,grids):
    '''
    Normalize the GLDAS grid data to meet the requirements of spherical harmonic expansion with pyshtools based on the sampling theorem of Driscoll and Healy (1994).
    The normalized grid data has the following characteristics: 
    (1) the first latitudinal band corresponds to 90 N, and the latitudinal band for 90 S is not included, and the latitudinal sampling interval is 180/n degrees. 
    (2) the first longitudinal band is 0 E, and the longitude band for 360 E is not included, and the longitudinal sampling interval is 360/n for an equally spaced grid.

    Usage:
    gldas_new = regular_gldas(lats,lons,grids)

    Inputs:
    lats -> [float array] latitudes of gldas grid data
    lons -> [float array] longitudes of gldas grid data
    grids -> [float 2d array] gldas grids data

    Parameters:
    
    Outputs:
    gldas_new -> float 2d array] normalized grids data
    '''
    # Extend the spatial extent of the GLDAS grid to a grid with a shape of n x 2n
    n = int(180/(lats[1] - lats[0]))
    lats_new = np.linspace(lats.max(),-lats.max(),n)
    lons_new = np.linspace(180-lons.max(),180+lons.max(),2*n)

    nlats,nlons = len(lats),len(lons)
    nlats_new,nlons_new = len(lats_new),len(lons_new)

    grids_new = []

    for grid in grids:
        grid_new = np.zeros((nlats_new,nlons_new))
        # Flip the grid data along latitude
        grid_new[:nlats,:] = np.flip(grid,0)
        # Swap the grid data along the longitude direction to make the longitude range from [-180W ~ 180E] to [0E ~ 360E]
        grid_new[:,:nlats_new],grid_new[:,nlats_new:] = grid_new[:,nlats_new:].copy(),grid_new[:,:nlats_new].copy()
        grids_new.append(grid_new)
    grids_new = np.array(grids_new) 
    grids_new[np.isnan(grids_new)] = 0
    
    trunc = np.abs(grids_new[grids_new != 0]).min()/2
    
    lats_interp = lats_new + lons_new.min()
    lons_interp = lons_new - lons_new.min()
    
    grids_interp = []
 
    # colatitude and longitude before interpolation
    colats_rad = np.deg2rad(90 - lats_new)
    lons_rad = np.deg2rad(lons_new)
    
    # colatitude and longitude after interpolation
    colats_rad_interp = np.deg2rad(90 - lats_interp)
    lons_rad_interp = np.deg2rad(lons_interp)
    lons_rad_interp, colats_rad_interp = np.meshgrid(lons_rad_interp, colats_rad_interp)
    
    # grid data after interpolation
    for grid_new in grids_new:
        lut = RectSphereBivariateSpline(colats_rad,lons_rad,grid_new) 
        grid_interp = lut.ev(colats_rad_interp,lons_rad_interp).reshape(nlats_new,nlons_new)
        grids_interp.append(grid_interp)
    grids_interp = np.array(grids_interp) 
    grids_interp[np.abs(grids_interp) < trunc] = 0

    return lats_interp,lons_interp,grids_interp