Esempio n. 1
0
    def ijk(self, points, depth_adjust=False):
        """
        Compute the fractional i, j, k indices of the grid from a
        set of lon, lat, depth points.

        Parameters
        ----------
        points : list of tuples,
            longitude, latitude, depth points to compute i, j, k indicies.
            NOTE: depth is in meters (defaults to negative)
        depth_adjust : bool,
            If True, depths that are deeper than the grid are set to the
            bottom layer, 0. If False, a nan value is used for values
            beyond the grid depth. Default is False.

        Returns
        -------
        out : tuple of numpy.maskedarray (with netcdf-type indexing),
            list of k, j, i indices for the given lon, lat, depth points

        Examples
        --------
        >>> a = ([-158, -160.5, -155.5], [20, 22.443, 19.5], [-10 -200 0])
        >>> idx = g.ijk(a)
        """
        # NOTE: Attempted to use a 3D griddata, but it took over 2 minutes
        # for each call, resulting in a 6minute runtime for this method
        # Reverted to 2D i,j indices, then looping a 1-D interpolation
        # to get depths for increased-speed (though this method is still slow)

        # Get the i,j points
        (j, i) = self.ij((points[0], points[1]))
        k = j * np.ma.masked
        grid_k = np.arange(0, self.n)
        depth = np.asanyarray(points[2])
        depth[depth > 0] *= -1

        # Determine the unique points
        good = np.where(~np.logical_or(i.mask, j.mask))[0]
        ii = np.floor(i[good])
        jj = np.floor(j[good])
        idx = seapy.unique_rows((jj, ii))
        fill_value = 0 if depth_adjust else np.nan
        for n in idx:
            pts = np.where(np.logical_and(jj == jj[n], ii == ii[n]))
            fi = interp1d(self.depth_rho[:, jj[n], ii[n]], grid_k,
                          bounds_error=False, fill_value=fill_value)
            k[good[pts]] = fi(depth[good][pts])

        # Mask bad points
        l = np.isnan(k.data)
        i[l] = np.ma.masked
        j[l] = np.ma.masked
        k[l] = np.ma.masked

        return (k, j, i)
Esempio n. 2
0
def add_ssh_tides(obs, tide_file, tide_error, tide_start=None, provenance=None,
                  reftime=seapy.default_epoch):
    """
    Apply predicted barotropic tides to the SSH values of given observations
    using the tide_file given.

    Parameters
    ----------
    obs : seapy.roms.obs.obs or string,
      The observations to enforce the error profile upon.
    tide_file : string,
      The name of the ROMS tidal forcing file to use for predicting the
      barotropic tides.
    tide_error : np.masked_array
      A two dimensional array of the tidal fit errors to apply to
      the ssh errors when adding the tides. This should be the same size
      as the rho-grid. The units of the error must be in meters. If it is
      masked, the mask will be honored and obs that are in the mask will
      be removed. This allows you to filter on regions of high error.
    tide_start : bool, optional,
      If given, the tide_start of the tide file. If not specified,
      will read the attribute of the tidal forcing file
    provenance : list of int or string, optional,
      The provenance to apply the tides to (ignore other observations
      of the same type, but different instrument)
    reftime: datetime,
      Reference time for the observation times

    Returns
    -------
    None:
      The obs structure is mutable is changed in place

    Examples
    --------
    >>> obs = obs('observation_file.nc')
    >>> add_ssh_tides(obs, 'tide_frc.nc', errmap)

    The resulting 'obs' variable will have modified data. To save it:

    >>> obs.to_netcdf()
    """

    # Load tidal file data
    frc = seapy.roms.tide.load_forcing(tide_file)
    if not tide_start:
        tide_start = frc['tide_start']

    # Make sure that the sizes are the same
    if frc['Eamp'].shape[1:] != tide_error.shape:
        raise ValueError(
            "The error array is not the same size as the tidal grid")

    # Gather the observations that need tidal information
    obs = seapy.roms.obs.asobs(obs)
    pro = seapy.roms.obs.asprovenance(provenance) if provenance else None
    if pro:
        l = np.where(np.logical_and(obs.type == 1,
                                    np.in1d(obs.provenance, pro)))
    else:
        l = np.where(obs.type == 1)

    # If we have any, then do tidal predictions and add the signal
    # and error to the observations
    bad = []
    if l[0].any():
        ox = np.rint(obs.x[l]).astype(int)
        oy = np.rint(obs.y[l]).astype(int)
        idx = seapy.unique_rows((ox, oy))
        for cur in seapy.progressbar.progress(idx):
            pts = np.where(np.logical_and(ox == ox[cur], oy == oy[cur]))
            # If this point is masked, remove from the observations
            if not tide_error[oy[cur], ox[cur]]:
                bad.append(l[0][pts].tolist())
            else:
                time = [reftime + datetime.timedelta(t) for t in
                        obs.time[l][pts]]
                amppha = seapy.tide.pack_amp_phase(
                    frc['tides'], frc['Eamp'][:, oy[cur], ox[cur]],
                    frc['Ephase'][:, oy[cur], ox[cur]])
                zpred = seapy.tide.predict(time, amppha,
                                           lat=obs.lat[l][cur],
                                           tide_start=tide_start)
                # Add the information to the observations
                obs.value[l[0][pts]] += zpred
                obs.error[l[0][pts]] = np.maximum(
                    obs.error[l[0][pts]], tide_error[oy[cur], ox[cur]]**2)

    # If any were bad, then remove them
    if bad:
        obs.delete(seapy.flatten(bad))
    pass
Esempio n. 3
0
    def ijk(self, points, depth_adjust=False):
        """
        Compute the fractional i, j, k indices of the grid from a
        set of lon, lat, depth points.

        Parameters
        ----------
        points : list of tuples,
            longitude, latitude, depth points to compute i, j, k indicies.
            NOTE: depth is in meters (defaults to negative)
        depth_adjust : bool,
            If True, depths that are deeper (shallower) than the grid are set
            to the bottom (top) layer, 0 (N). If False, a nan value is used for
            values beyond the grid depth. Default is False.

        Returns
        -------
        out : tuple of numpy.maskedarray (with netcdf-type indexing),
            list of k, j, i indices for the given lon, lat, depth points

        Examples
        --------
        >>> a = ([-158, -160.5, -155.5], [20, 22.443, 19.5], [-10 -200 0])
        >>> idx = g.ijk(a)

        """
        # NOTE: Attempted to use a 3D griddata, but it took over 2 minutes
        # for each call, resulting in a 6minute runtime for this method
        # Reverted to 2D i,j indices, then looping a 1-D interpolation
        # to get depths for increased-speed (though this method is still slow)

        from scipy.interpolate import interp1d

        # Get the i,j points
        (j, i) = self.ij((points[0], points[1]))
        k = j * np.ma.masked
        grid_k = np.arange(0, self.n)
        depth = np.asanyarray(points[2])
        depth[depth > 0] *= -1

        # Determine the unique points
        good = np.where(~np.logical_or(i.mask, j.mask))[0]
        ii = np.floor(i[good]).astype(int)
        jj = np.floor(j[good]).astype(int)
        idx = seapy.unique_rows((jj, ii))
        fill_value = 0 if depth_adjust else np.nan
        for n in idx:
            pts = np.where(np.logical_and(jj == jj[n], ii == ii[n]))
            griddep = self.depth_rho[:, jj[n], ii[n]]
            if griddep[0] < griddep[-1]:
                griddep[-1] = 0.0
            else:
                griddep[0] = 0.0

            fi = interp1d(griddep,
                          grid_k,
                          bounds_error=False,
                          fill_value=fill_value)
            k[good[pts]] = fi(depth[good][pts])

        # Mask bad points
        l = np.isnan(k.data)
        i[l] = np.ma.masked
        j[l] = np.ma.masked
        k[l] = np.ma.masked

        return (k, j, i)
Esempio n. 4
0
def add_ssh_tides(obs, tide_file, tide_error, tide_start=None, provenance=None,
                  reftime=seapy.default_epoch):
    """
    Apply predicted barotropic tides to the SSH values of given observations
    using the tide_file given. 

    Parameters
    ----------
    obs : seapy.roms.obs.obs or string,
      The observations to enforce the error profile upon.
    tide_file : string,
      The name of the ROMS tidal forcing file to use for predicting the
      barotropic tides.
    tide_error : np.masked_array
      A two dimensional array of the tidal fit errors to apply to
      the ssh errors when adding the tides. This should be the same size
      as the rho-grid. The units of the error must be in meters. If it is
      masked, the mask will be honored and obs that are in the mask will
      be removed. This allows you to filter on regions of high error.
    tide_start : bool, optional,
      If given, the tide_start of the tide file. If not specified,
      will read the attribute of the tidal forcing file
    provenance : list of int or string, optional,
      The provenance to apply the tides to (ignore other observations
      of the same type, but different instrument)
    reftime: datetime,
      Reference time for the observation times

    Returns
    -------
    None:
      The obs structure is mutable is changed in place

    Examples
    --------
    >>> obs = obs('observation_file.nc')
    >>> add_ssh_tides(obs, 'tide_frc.nc', errmap)

    The resulting 'obs' variable will have modified data. To save it:

    >>> obs.to_netcdf()
    """

    # Load tidal file data
    frc = seapy.roms.tide.load_forcing(tide_file)
    if not tide_start:
        tide_start = frc['tide_start']

    # Make sure that the sizes are the same
    if frc['Eamp'].shape[1:] != tide_error.shape:
        raise ValueError(
            "The error array is not the same size as the tidal grid")

    # Gather the observations that need tidal information
    obs = seapy.roms.obs.asobs(obs)
    pro = seapy.roms.obs.asprovenance(provenance) if provenance else None
    if pro:
        l = np.where(np.logical_and(obs.type == 1,
                                    np.in1d(obs.provenance, pro)))
    else:
        l = np.where(obs.type == 1)

    # If we have any, then do tidal predictions and add the signal
    # and error to the observations
    bad = []
    if l[0].any():
        ox = np.rint(obs.x[l]).astype(int)
        oy = np.rint(obs.y[l]).astype(int)
        idx = seapy.unique_rows((ox, oy))
        for cur in seapy.progressbar.progress(idx):
            pts = np.where(np.logical_and(ox == ox[cur], oy == oy[cur]))
            # If this point is masked, remove from the observations
            if not tide_error[oy[cur], ox[cur]]:
                bad.append(l[0][pts].tolist())
            else:
                time = [reftime + datetime.timedelta(t) for t in
                        obs.time[l][pts]]
                amppha = seapy.tide.pack_amp_phase(
                    frc['tides'], frc['Eamp'][:, oy[cur], ox[cur]],
                    frc['Ephase'][:, oy[cur], ox[cur]])
                zpred = seapy.tide.predict(time, amppha,
                                           lat=obs.lat[l][cur],
                                           tide_start=tide_start)
                # Add the information to the observations
                obs.value[l[0][pts]] += zpred
                obs.error[l[0][pts]] = np.maximum(
                    obs.error[l[0][pts]], tide_error[oy[cur], ox[cur]]**2)

    # If any were bad, then remove them
    if bad:
        obs.delete(seapy.flatten(bad))
    pass