Example #1
0
def __interp3_vel_thread(rx, ry, rz, ra, u, v, zx, zy, zz, za, pmap,
                         weight, nx, ny, mask):
    """
    internal routine: 3D velocity interpolation thread for parallel interpolation
    """
    # Put on the same grid
    if u.shape != v.shape:
        u = seapy.model.u2rho(u, fill=True)
        v = seapy.model.v2rho(v, fill=True)

    # Rotate the fields (NOTE: ROMS angle is negative relative to "true")
    if ra is not None:
        u, v = seapy.rotate(u, v, ra)

    # Interpolate
    u = __interp3_thread(rx, ry, rz, u, zx, zy, zz, pmap,
                         weight, nx, ny, mask, _up_scaling["u"],
                         _down_scaling["u"])
    v = __interp3_thread(rx, ry, rz, v, zx, zy, zz, pmap,
                         weight, nx, ny, mask, _up_scaling["v"],
                         _down_scaling["v"])

    # Rotate to destination (NOTE: ROMS angle is negative relative to "true")
    if za is not None:
        u, v = seapy.rotate(u, v, -za)

    # Return the masked data
    return u, v
Example #2
0
def __interp3_vel_thread(rx, ry, rz, ra, u, v, zx, zy, zz, za, pmap,
                         weight, nx, ny, mask):
    """
    internal routine: 3D velocity interpolation thread for parallel interpolation
    """
    # Put on the same grid
    if u.shape != v.shape:
        u = seapy.model.u2rho(u, fill=True)
        v = seapy.model.v2rho(v, fill=True)

    # Rotate the fields (NOTE: ROMS angle is negative relative to "true")
    if ra is not None:
        u, v = seapy.rotate(u, v, ra)

    # Interpolate
    u = __interp3_thread(rx, ry, rz, u, zx, zy, zz, pmap,
                         weight, nx, ny, mask, _up_scaling["u"],
                         _down_scaling["u"])
    v = __interp3_thread(rx, ry, rz, v, zx, zy, zz, pmap,
                         weight, nx, ny, mask, _up_scaling["v"],
                         _down_scaling["v"])

    # Rotate to destination (NOTE: ROMS angle is negative relative to "true")
    if za is not None:
        u, v = seapy.rotate(u, v, -za)

    # Return the masked data
    return u, v
Example #3
0
def detide(grid, bryfile, tidefile, tides=None, tide_start=None):
    """
    Given a boundary file, detide the barotropic components and create tidal
    forcing file for the grid. This method will update the given boundary file.

    Parameters
    ----------
    grid : seapy.model.grid or string,
       The grid that defines the boundaries shape and mask
    bryfile : string,
       The boundary file to detide
    tidefile : string,
       The output tidal forcing file with the tide spectral forcing
    tides : string array, optional
       Array of strings defining which tides to extract. Defaults to the
       standard 11 constituents.
    tide_start : datetime, optional
       The reference date to use for the tide forcing. If None, the
       center of the time period is used.

    Returns
    -------
    None

    Examples
    --------
    Make a long time-series boundary conditions from a group of boundary files,
    skipping the last record of each file to prevent overlap (if there are 100 records
    in each file). Afterwards, detide the resulting file.

    >>> !ncrcat -dbry_time,0,,100,99 bry_out_*nc bry_detide.nc
    >>> seapy.roms.boundary.detide("mygrid.nc", "bry_detide.nc", "tide_out.nc")

    """
    import datetime

    if not tides:
        tides = seapy.tide.default_tides
    else:
        tides = np.atleast_1d(tides)

    # Load Files
    grid = seapy.model.asgrid(grid)
    bry = netCDF4.Dataset(bryfile, "a")

    # Get the definitions of the boundary file
    epoch, timevar = seapy.roms.get_reftime(bry)
    time = seapy.roms.num2date(bry, timevar)

    # Pick the time for the tide file reference
    if not tide_start:
        tide_start = time[0] + (time[-1] - time[0]) / 2
        tide_start = datetime.datetime(
            tide_start.year, tide_start.month, tide_start.day)

    try:
        s_rho = len(bry.dimensions['s_rho'])
    except:
        s_rho = grid.n

    # Set variables to detide
    detide_vars = ['zeta', 'ubar', 'vbar']

    # Create the tide forcing file
    bry.detide = "Detided to generate tide forcing: {:s}".format(tidefile)

    # Detide the free-surface
    eamp = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))
    epha = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))
    cmin = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))
    cmax = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))
    cang = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))
    cpha = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))

    for side in sides:
        lvar = "zeta_" + side
        idx = sides[side].indices
        lat = grid.lat_rho[idx[0], idx[1]]
        size = grid.xi_rho if sides[side].xi else grid.eta_rho
        if lvar in bry.variables:
            print(lvar)
            zeta = np.ma.array(bry.variables[lvar][:])
            mask = np.ma.getmaskarray(zeta)
            # Detide
            for i in seapy.progressbar.progress(range(size)):
                if np.any(mask[:, i]):
                    continue
                out = seapy.tide.fit(time, zeta[:, i], tides=tides, lat=lat[i],
                                     tide_start=tide_start)
                zeta[:, i] -= out['fit'].data

                # Save the amp/phase in the tide file
                for n, t in enumerate(tides):
                    if sides[side].xi:
                        eamp[n, idx[0], i] = out['major'][t].amp
                        epha[n, idx[0], i] = np.mod(
                            out['major'][t].phase, 2 * np.pi)
                    else:
                        eamp[n, i, idx[1]] = out['major'][t].amp
                        epha[n, i, idx[1]] = np.mod(
                            out['major'][t].phase, 2 * np.pi)

            # Save out the detided information
            bry.variables[lvar][:] = zeta
            zeta = [0]
            bry.sync()

        # Detide the barotropic velocity
        uvar = "ubar_" + side
        vvar = "vbar_" + side
        if uvar in bry.variables and vvar in bry.variables:
            print(uvar, vvar)
            ubar = np.zeros((len(time), size))
            vbar = np.zeros((len(time), size))

            # Load data, put onto rho-grid, and rotate
            bubar = np.ma.array(bry.variables[uvar][:]).filled(0)
            bvbar = np.ma.array(bry.variables[vvar][:]).filled(0)
            if sides[side].xi:
                ubar[:, 1:-1] = 0.5 * (bubar[:, 1:] + bubar[:, :-1])
                ubar[:, 0] = bubar[:, 1]
                ubar[:, -1] = bubar[:, -2]
                vbar = bvbar.copy()
            else:
                vbar[:, 1:-1] = 0.5 * (bvbar[:, 1:] + bvbar[:, :-1])
                vbar[:, 0] = bvbar[:, 1]
                vbar[:, -1] = bvbar[:, -2]
                ubar = bubar.copy()
            ubar, vbar = seapy.rotate(ubar, vbar, grid.angle[idx[0], idx[1]])
            bubar = bvbar = []

            # Detide
            for i in seapy.progressbar.progress(range(size)):
                if np.any(mask[:, i]):
                    continue
                out = seapy.tide.fit(
                    time, ubar[:, i] + 1j * vbar[:, i], tides=tides, lat=lat[i],
                    tide_start=tide_start)
                ubar[:, i] -= np.real(out['fit'])
                vbar[:, i] -= np.imag(out['fit'])

                # Save the amp/phase in the tide file
                for n, t in enumerate(tides):
                    if sides[side].xi:
                        cmax[n, idx[0], i] = out['major'][t].amp
                        cmin[n, idx[0], i] = out['minor'][t].amp
                        cpha[n, idx[0], i] = out['major'][t].phase
                        cang[n, idx[0], i] = out['minor'][t].phase
                    else:
                        cmax[n, i, idx[1]] = out['major'][t].amp
                        cmin[n, i, idx[1]] = out['minor'][t].amp
                        cpha[n, i, idx[1]] = out['major'][t].phase
                        cang[n, i, idx[1]] = out['minor'][t].phase

            ubar, vbar = seapy.rotate(ubar, vbar, -grid.angle[idx[0], idx[1]])
            if sides[side].xi:
                bry.variables[uvar][:] = 0.5 * (ubar[:, 1:] + ubar[:, :-1])
                bry.variables[vvar][:] = vbar
            else:
                bry.variables[vvar][:] = 0.5 * (vbar[:, 1:] + vbar[:, :-1])
                bry.variables[uvar][:] = ubar
            bry.sync()
            ubar = vbar = []

    # Have to duplicate the boundary tide info into the inner row/column
    eamp[:, 1:-1, 1] = eamp[:, 1:-1, 0]
    eamp[:, 1:-1, -2] = eamp[:, 1:-1, -1]
    eamp[:, 1, 1:-1] = eamp[:, 0, 1:-1]
    eamp[:, -2, 1:-1] = eamp[:, -1, 1:-1]
    epha[:, 1:-1, 1] = epha[:, 1:-1, 0]
    epha[:, 1:-1, -2] = epha[:, 1:-1, -1]
    epha[:, 1, 1:-1] = epha[:, 0, 1:-1]
    epha[:, -2, 1:-1] = epha[:, -1, 1:-1]
    cmax[:, 1:-1, 1] = cmax[:, 1:-1, 0]
    cmax[:, 1:-1, -2] = cmax[:, 1:-1, -1]
    cmax[:, 1, 1:-1] = cmax[:, 0, 1:-1]
    cmax[:, -2, 1:-1] = cmax[:, -1, 1:-1]
    cmin[:, 1:-1, 1] = cmin[:, 1:-1, 0]
    cmin[:, 1:-1, -2] = cmin[:, 1:-1, -1]
    cmin[:, 1, 1:-1] = cmin[:, 0, 1:-1]
    cmin[:, -2, 1:-1] = cmin[:, -1, 1:-1]
    cpha[:, 1:-1, 1] = cpha[:, 1:-1, 0]
    cpha[:, 1:-1, -2] = cpha[:, 1:-1, -1]
    cpha[:, 1, 1:-1] = cpha[:, 0, 1:-1]
    cpha[:, -2, 1:-1] = cpha[:, -1, 1:-1]
    cang[:, 1:-1, 1] = cang[:, 1:-1, 0]
    cang[:, 1:-1, -2] = cang[:, 1:-1, -1]
    cang[:, 1, 1:-1] = cang[:, 0, 1:-1]
    cang[:, -2, 1:-1] = cang[:, -1, 1:-1]

    # Set the tide reference
    tideout = {}
    tideout['tides'] = tides
    tideout['tide_start'] = tide_start
    tideout['Eamp'] = eamp
    tideout['Ephase'] = epha
    tideout['Cmajor'] = cmax
    tideout['Cminor'] = cmin
    tideout['Cphase'] = cpha
    tideout['Cangle'] = cang

    seapy.roms.tide.create_forcing(tidefile, tideout,
                                   title="Tides from " + bryfile, epoch=epoch)
    bry.close()

    pass
Example #4
0
def from_stations(station_file, bry_file, grid=None):
    """
    Construct a boundary forcing file from a stations file generated by a parent-grid.
    The stations.in file must have been generated by the seapy.roms.gen_stations method;
    otherwise, the order will be incorrect.

    Parameters
    ==========
    station_file : string
        Filename of the stations file that is the source for the boundary data
    bry_file : string
        Filename of the boundary conditions file to generate
    grid : string or seapy.model.grid
        Grid that the boundary conditions are created for

    Returns
    -------
    None

    """
    grid = seapy.model.asgrid(grid)
    ncstation = netCDF4.Dataset(station_file)
    src_ref, time = seapy.roms.get_reftime(ncstation)

    # Create the boundary file and fill up the descriptive data
    ncbry = seapy.roms.ncgen.create_bry(bry_file,
                                        eta_rho=grid.eta_rho, xi_rho=grid.xi_rho,
                                        s_rho=grid.n, reftime=src_ref, clobber=False,
                                        title="generated from " + station_file)
    grid.to_netcdf(ncbry)

    # Load the times: we need to see if the times are duplicated
    # because if using assimilation, they may be duplicated for every
    # outer-loop. Currently, it overwrites the first one each time (this
    # will need to be fixed if ROMS is fixed).
    statime = ncstation.variables[time][:]
    dup = np.where(statime[1:] == statime[0])[0]
    rng = np.s_[:]
    if dup.size > 0:
        rng = np.s_[0:np.min(dup)]
        statime = statime[rng]
    brytime = seapy.roms.get_timevar(ncbry)
    ncbry.variables[brytime][:] = seapy.roms.date2num(
        seapy.roms.num2date(ncstation, time, rng), ncbry, brytime)

    # Set up the indices
    bry = {
        "south": range(0, grid.lm),
        "north": range(grid.lm, 2 * grid.lm),
        "west": range(2 * grid.lm, 2 * grid.lm + grid.ln),
        "east": range(2 * grid.lm + grid.ln, 2 * (grid.lm + grid.ln))
    }

    # Get the information to construct the depths of the station data
    sta_vt = ncstation.variables["Vtransform"][:]
    sta_hc = ncstation.variables["hc"][:]
    sta_s_rho = ncstation.variables["s_rho"][:]
    sta_cs_r = ncstation.variables["Cs_r"][:]
    sta_h = ncstation.variables["h"][:]
    sta_angle = ncstation.variables["angle"][:]
    sta_lon = ncstation.variables["lon_rho"][:]
    sta_lat = ncstation.variables["lat_rho"][:]
    sta_mask = np.ones(sta_lat.shape)
    sta_mask[sta_lon * sta_lat > 1e10] = 0

    # Load the station data as we need to manipulate it
    sta_zeta = np.ma.masked_greater(ncstation.variables["zeta"][rng], 100)
    sta_ubar = np.ma.masked_greater(ncstation.variables["ubar"][rng], 100)
    sta_vbar = np.ma.masked_greater(ncstation.variables["vbar"][rng], 100)
    sta_temp = np.ma.masked_greater(ncstation.variables["temp"][rng], 100)
    sta_salt = np.ma.masked_greater(ncstation.variables["salt"][rng], 100)
    sta_u = np.ma.masked_greater(ncstation.variables["u"][rng], 100)
    sta_v = np.ma.masked_greater(ncstation.variables["v"][rng], 100)
    ncstation.close()

    # Create the true positions and mask
    grid_h = np.concatenate([grid.h[0, :], grid.h[-1, :],
                             grid.h[:, 0], grid.h[:, -1]])
    grid_lon = np.concatenate([grid.lon_rho[0, :], grid.lon_rho[-1, :],
                               grid.lon_rho[:, 0], grid.lon_rho[:, -1]])
    grid_lat = np.concatenate([grid.lat_rho[0, :], grid.lat_rho[-1, :],
                               grid.lat_rho[:, 0], grid.lat_rho[:, -1]])
    grid_mask = np.concatenate([grid.mask_rho[0, :], grid.mask_rho[-1, :],
                                grid.mask_rho[:, 0], grid.mask_rho[:, -1]])
    grid_angle = np.concatenate([grid.angle[0, :], grid.angle[-1, :],
                                 grid.angle[:, 0], grid.angle[:, -1]])

    # Search for bad stations due to child grid overlaying parent mask.
    # Unfortunately, ROMS will give points that are not at the locations
    # you specify if those points conflict with the mask. So, these points
    # are simply replaced with the nearest.
    dist = np.sqrt((sta_lon - grid_lon)**2 + (sta_lat - grid_lat)**2)
    bad_pts = np.where(np.logical_and(dist > 0.001, grid_mask == 1))[0]
    good_pts = np.where(np.logical_and(dist < 0.001, grid_mask == 1))[0]
    for i in bad_pts:
        didx = np.sqrt((sta_lon[i] - sta_lon[good_pts])**2 +
                       (sta_lat[i] - sta_lat[good_pts])**2).argmin()
        index = good_pts[didx]
        sta_h[i] = sta_h[index]
        sta_angle[i] = sta_angle[index]
        sta_lon[i] = sta_lon[index]
        sta_lat[i] = sta_lat[index]
        sta_zeta[:, i] = sta_zeta[:, index]
        sta_ubar[:, i] = sta_ubar[:, index]
        sta_vbar[:, i] = sta_vbar[:, index]
        sta_temp[:, i, :] = sta_temp[:, index, :]
        sta_salt[:, i, :] = sta_salt[:, index, :]
        sta_u[:, i, :] = sta_u[:, index, :]
        sta_v[:, i, :] = sta_v[:, index, :]

    # Construct the boundaries: a dictionary of boundary side and two element
    # array whether the u[0] or v[1] dimensions need to be averaged
    sides = {"north": [True, False], "south": [True, False],
             "east": [False, True], "west": [False, True]}
    delta_angle = sta_angle - grid_angle
    sta_ubar, sta_vbar = seapy.rotate(sta_ubar, sta_vbar, delta_angle)
    sta_u, sta_v = seapy.rotate(sta_u, sta_v, np.tile(delta_angle,
                                                      (sta_u.shape[-1], 1)).T)

    # Set up the parameters for depth-interpolated
    wght = 5
    nx = 3
    ny = 9

    # Build a non-extrapolating field to interpolate. Generate the
    # position and depth
    def __expand_field(x):
        shp = x.shape
        y = np.zeros((shp[0] + 2, shp[1] + 2))
        y[1:-1, 1:-1] = x
        y[1:-1, 0] = x[:, 0]
        y[1:-1, -1] = x[:, -1]
        y[0, :] = y[1, :]
        y[-1, :] = y[-2, :]
        return y

    for side in sides:
        print(side)

        # Masks
        sta_ocean = np.where(sta_mask[bry[side]] == 1)[0]
        ocean = np.where(grid_mask[bry[side]] == 1)[0]

        # If we have a masked boundary, skip it
        if not np.any(ocean):
            continue

        # 1) Zeta
        ncbry.variables["zeta_" + side][:,
                                        ocean] = sta_zeta[:, bry[side]][:, ocean]

        # 2) Ubar
        if sides[side][0]:
            ncbry.variables["ubar_" + side][:] = 0.5 * (
                sta_ubar[:, bry[side][0:-1]] + sta_ubar[:, bry[side][1:]])
        else:
            ncbry.variables["ubar_" + side][:] = sta_ubar[:, bry[side]]

        # 3) Vbar
        if sides[side][1]:
            ncbry.variables["vbar_" + side][:] = 0.5 * (
                sta_vbar[:, bry[side][0:-1]] + sta_vbar[:, bry[side][1:]])
        else:
            ncbry.variables["vbar_" + side][:] = sta_vbar[:, bry[side]]

        # For 3D variables, we need to loop through time and interpolate
        # onto the child grid. Construct the distances
        x = np.zeros(len(bry[side]))
        x[1:] = np.cumsum(seapy.earth_distance(grid_lon[bry[side][0:-1]],
                                               grid_lat[bry[side][0:-1]],
                                               grid_lon[bry[side][1:]],
                                               grid_lat[bry[side][1:]]))
        sta_x = seapy.adddim(x, len(sta_s_rho))
        x = seapy.adddim(x, len(grid.s_rho))

        for n, t in seapy.progressbar.progress(enumerate(statime), statime.size):
            sta_depth = seapy.roms.depth(sta_vt, sta_h[bry[side]], sta_hc,
                                         sta_s_rho, sta_cs_r, sta_zeta[n, bry[side]])
            depth = seapy.roms.depth(grid.vtransform, grid_h[bry[side]],
                                     grid.hc, grid.s_rho, grid.cs_r, sta_zeta[n, bry[side]])

            in_x = __expand_field(sta_x[:, sta_ocean])
            in_x[:, 0] = in_x[:, 0] - 3600
            in_x[:, -1] = in_x[:, -1] + 3600
            in_depth = __expand_field(sta_depth[:, sta_ocean])
            in_depth[0, :] = in_depth[0, :] - 1000
            in_depth[-1, :] = in_depth[-1, :] + 10

            # 4) Temp
            in_data = __expand_field(np.transpose(
                sta_temp[n, bry[side], :][sta_ocean, :]))
            ncbry.variables["temp_" + side][n, :] = 0.0
            ncbry.variables["temp_" + side][n, :, ocean], pmap = seapy.oa.oasurf(
                in_x, in_depth, in_data,
                x[:, ocean], depth[:, ocean], nx=nx, ny=ny, weight=wght)

            # 5) Salt
            in_data = __expand_field(np.transpose(
                sta_salt[n, bry[side], :][sta_ocean, :]))
            ncbry.variables["salt_" + side][n, :] = 0.0
            ncbry.variables["salt_" + side][n, :, ocean], pmap = seapy.oa.oasurf(
                in_x, in_depth, in_data,
                x[:, ocean], depth[:, ocean], pmap=pmap, nx=nx, ny=ny, weight=wght)

            # 6) U
            in_data = __expand_field(np.transpose(
                sta_u[n, bry[side], :][sta_ocean, :]))
            data = np.zeros(x.shape)
            data[:, ocean], pmap = seapy.oa.oasurf(in_x, in_depth, in_data,
                                                   x[:, ocean],
                                                   depth[:, ocean],
                                                   pmap=pmap, nx=nx, ny=ny, weight=wght)
            if sides[side][0]:
                ncbry.variables["u_" + side][n, :] = 0.5 * (
                    data[:, 0:-1] + data[:, 1:])
            else:
                ncbry.variables["u_" + side][n, :] = data

            # 7) V
            in_data = __expand_field(np.transpose(
                sta_v[n, bry[side], :][sta_ocean, :]))
            data = data * 0
            data[:, ocean], pmap = seapy.oa.oasurf(in_x, in_depth, in_data,
                                                   x[:, ocean],
                                                   depth[:, ocean],
                                                   pmap=pmap, nx=nx, ny=ny,
                                                   weight=wght)
            if sides[side][1]:
                ncbry.variables["v_" + side][n, :] = 0.5 * (
                    data[:, 0:-1] + data[:, 1:])
            else:
                ncbry.variables["v_" + side][n, :] = data
            ncbry.sync()
    ncbry.close()
    pass
Example #5
0
def mean_plot_2Dvec(u, v, g="hiomsag-grid.nc"):
    grid = sp.model.grid(g)
    m = 1 / grid.pm
    n = 1 / grid.pn
    T = len(u)
    x1 = np.array([
        180, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, 167,
        166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 153,
        152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139,
        138, 137, 136, 135
    ])

    y1 = np.array([[68, 69], [68, 69], [68, 69], [68, 69], [68, 69], [68, 69],
                   [68, 69], [68, 69], [68, 69], [68, 69], [68, 69], [68, 69],
                   [68, 69], [68, 69], [68, 69], [68, 69], [68, 69], [68, 69],
                   [68, 69], [68, 69], [68, 69], [68, 69], [68, 69], [68, 69],
                   [68, 69], [68, 69], [68, 69], [68, 69], [68, 69], [68, 69],
                   [68, 69], [68, 69], [68, 69], [68, 69], [68, 69], [68, 69],
                   [68, 69], [68, 69], [68, 69], [68, 69], [68, 69], [68, 69],
                   [68, 69], [68, 69], [68, 69], [69]])

    x2 = np.array([[135, 134, 133], [132, 133, 134], [131, 132, 133],
                   [131, 132, 133], [130, 131, 132], [129, 130, 131],
                   [129, 130, 131], [128, 129, 130], [128, 129, 130],
                   [127, 128, 129], [127, 128, 129], [126, 127]])

    y2 = np.array([67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56])

    x3 = np.array([[125, 126, 127], [125, 126, 127], [125, 126, 127],
                   [125, 126, 127], [125, 126, 127], [125, 126, 127],
                   [125, 126, 127], [125, 126, 127], [125, 126, 127],
                   [125, 126, 127]])

    y3 = np.array([54, 53, 52, 51, 50, 49, 48, 47, 46, 45])

    u1 = np.zeros((T, len(x1)))
    v1 = np.zeros((T, len(x1)))
    dist1 = np.zeros(len(x1))
    for i in range(0, len(x1)):
        u1[:, i] = np.nanmean(u[:, y1[i], x1[i] - 1], axis=-1)
        v1[:, i] = np.nanmean(v[:, np.asarray(y1[i]) - 1, x1[i]], axis=-1)
        dist1[i] = np.nanmean(m[y1[i], x1[i]])

    u2 = np.zeros((T, len(x2)))
    v2 = np.zeros((T, len(x2)))
    dist2 = np.zeros(len(x2))
    for i in range(0, len(x2)):
        #u2[:, :, i] = np.sqrt((np.mean(u[:, :, y2[i], x2[i]], axis=-1))**2 + (np.mean(v[:, :, y2[i], x2[i]], axis=-1))**2) * np.sign(np.mean(v[:, :, y2[i], x2[i]], axis=-1))
        u2[:, i], v2[:, i] = sp.rotate(np.nanmean(u[:, y2[i],
                                                    np.asarray(x2[i]) - 1],
                                                  axis=-1),
                                       np.nanmean(v[:, y2[i] - 1, x2[i]],
                                                  axis=-1),
                                       angle=np.pi / 3.0)
        dist2[i] = np.nanmean(m[y2[i], x2[i]])

    u3 = np.zeros((T, len(x3)))
    v3 = np.zeros((T, len(x3)))
    dist3 = np.zeros(len(x3))
    for i in range(0, len(x3)):
        u3[:, i] = np.nanmean(v[:, y3[i], np.asarray(x3[i]) - 1], axis=-1)
        v3[:, i] = np.nanmean(u[:, y3[i] - 1, x3[i]], axis=-1)
        dist3[i] = np.nanmean(m[y3[i], x3[i]])

    N = len(x1) + len(x2) + len(x3)
    U = np.zeros((T, N))
    V = np.zeros((T, N))
    dist = np.zeros(N)
    U[:, 0:len(x1)] = u1
    U[:, len(x1):len(x1) + len(x2)] = v2
    U[:, len(x1) + len(x2):N] = u3

    V[:, 0:len(x1)] = v1
    V[:, len(x1):len(x1) + len(x2)] = -u2
    V[:, len(x1) + len(x2):N] = v3

    dist[0:len(x1)] = dist1
    dist[len(x1):len(x1) + len(x2)] = dist2
    dist[len(x1) + len(x2):N] = dist3

    # calculate total distance along the canal
    total_dist = np.zeros(N)
    for i in range(0, N):
        total_dist[i] = np.sum(dist[0:i])

    # making distance vector to 2d array for plotting purposes
    distance_array = np.zeros((N))
    for i in range(0, N):
        distance_array[N - 1 - i] = total_dist[i]

    return U, V, distance_array
Example #6
0
def detide(grid, bryfile, tidefile, tides=None, tide_start=None):
    """
    Given a boundary file, detide the barotropic components and create tidal
    forcing file for the grid. This method will update the given boundary file.

    Parameters
    ----------
    grid : seapy.model.grid or string,
       The grid that defines the boundaries shape and mask
    bryfile : string,
       The boundary file to detide
    tidefile : string,
       The output tidal forcing file with the tide spectral forcing
    tides : string array, optional
       Array of strings defining which tides to extract. Defaults to the
       standard 11 constituents.
    tide_start : datetime, optional
       The reference date to use for the tide forcing. If None, the
       center of the time period is used.

    Returns
    -------
    None

    Examples
    --------
    Make a long time-series boundary conditions from a group of boundary files,
    skipping the last record of each file to prevent overlap (if there are 100 records
    in each file). Afterwards, detide the resulting file.

    >>> !ncrcat -dbry_time,0,,100,99 bry_out_*nc bry_detide.nc
    >>> seapy.roms.boundary.detide("mygrid.nc", "bry_detide.nc", "tide_out.nc")

    """
    import datetime

    if not tides:
        tides = seapy.tide.default_tides
    else:
        tides = np.atleast_1d(tides)

    # Load Files
    grid = seapy.model.asgrid(grid)
    bry = netCDF4.Dataset(bryfile, "a")

    # Get the definitions of the boundary file
    epoch, timevar = seapy.roms.get_reftime(bry)
    time = seapy.roms.num2date(bry, timevar)

    # Pick the time for the tide file reference
    if not tide_start:
        tide_start = time[0] + (time[-1] - time[0]) / 2
        tide_start = datetime.datetime(tide_start.year, tide_start.month,
                                       tide_start.day)

    try:
        s_rho = len(bry.dimensions['s_rho'])
    except:
        s_rho = grid.n

    # Set variables to detide
    detide_vars = ['zeta', 'ubar', 'vbar']

    # Create the tide forcing file
    bry.detide = "Detided to generate tide forcing: {:s}".format(tidefile)

    # Detide the free-surface
    eamp = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))
    epha = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))
    cmin = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))
    cmax = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))
    cang = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))
    cpha = np.zeros((len(tides), grid.eta_rho, grid.xi_rho))

    for side in sides:
        lvar = "zeta_" + side
        idx = sides[side].indices
        lat = grid.lat_rho[idx[0], idx[1]]
        size = grid.xi_rho if sides[side].xi else grid.eta_rho
        if lvar in bry.variables:
            print(lvar)
            zeta = np.ma.array(bry.variables[lvar][:])
            mask = np.ma.getmaskarray(zeta)
            # Detide
            for i in seapy.progressbar.progress(range(size)):
                if np.any(mask[:, i]):
                    continue
                out = seapy.tide.fit(time,
                                     zeta[:, i],
                                     tides=tides,
                                     lat=lat[i],
                                     tide_start=tide_start)
                zeta[:, i] -= out['fit'].data

                # Save the amp/phase in the tide file
                for n, t in enumerate(tides):
                    if sides[side].xi:
                        eamp[n, idx[0], i] = out['major'][t].amp
                        epha[n, idx[0], i] = np.mod(out['major'][t].phase,
                                                    2 * np.pi)
                    else:
                        eamp[n, i, idx[1]] = out['major'][t].amp
                        epha[n, i, idx[1]] = np.mod(out['major'][t].phase,
                                                    2 * np.pi)

            # Save out the detided information
            bry.variables[lvar][:] = zeta
            zeta = [0]
            bry.sync()

        # Detide the barotropic velocity
        uvar = "ubar_" + side
        vvar = "vbar_" + side
        if uvar in bry.variables and vvar in bry.variables:
            print(uvar, vvar)
            ubar = np.zeros((len(time), size))
            vbar = np.zeros((len(time), size))

            # Load data, put onto rho-grid, and rotate
            bubar = np.ma.array(bry.variables[uvar][:]).filled(0)
            bvbar = np.ma.array(bry.variables[vvar][:]).filled(0)
            if sides[side].xi:
                ubar[:, 1:-1] = 0.5 * (bubar[:, 1:] + bubar[:, :-1])
                ubar[:, 0] = bubar[:, 1]
                ubar[:, -1] = bubar[:, -2]
                vbar = bvbar.copy()
            else:
                vbar[:, 1:-1] = 0.5 * (bvbar[:, 1:] + bvbar[:, :-1])
                vbar[:, 0] = bvbar[:, 1]
                vbar[:, -1] = bvbar[:, -2]
                ubar = bubar.copy()
            ubar, vbar = seapy.rotate(ubar, vbar, grid.angle[idx[0], idx[1]])
            bubar = bvbar = []

            # Detide
            for i in seapy.progressbar.progress(range(size)):
                if np.any(mask[:, i]):
                    continue
                out = seapy.tide.fit(time,
                                     ubar[:, i] + 1j * vbar[:, i],
                                     tides=tides,
                                     lat=lat[i],
                                     tide_start=tide_start)
                ubar[:, i] -= np.real(out['fit'])
                vbar[:, i] -= np.imag(out['fit'])

                # Save the amp/phase in the tide file
                for n, t in enumerate(tides):
                    if sides[side].xi:
                        cmax[n, idx[0], i] = out['major'][t].amp
                        cmin[n, idx[0], i] = out['minor'][t].amp
                        cpha[n, idx[0], i] = out['major'][t].phase
                        cang[n, idx[0], i] = out['minor'][t].phase
                    else:
                        cmax[n, i, idx[1]] = out['major'][t].amp
                        cmin[n, i, idx[1]] = out['minor'][t].amp
                        cpha[n, i, idx[1]] = out['major'][t].phase
                        cang[n, i, idx[1]] = out['minor'][t].phase

            ubar, vbar = seapy.rotate(ubar, vbar, -grid.angle[idx[0], idx[1]])
            if sides[side].xi:
                bry.variables[uvar][:] = 0.5 * (ubar[:, 1:] + ubar[:, :-1])
                bry.variables[vvar][:] = vbar
            else:
                bry.variables[vvar][:] = 0.5 * (vbar[:, 1:] + vbar[:, :-1])
                bry.variables[uvar][:] = ubar
            bry.sync()
            ubar = vbar = []

    # Have to duplicate the boundary tide info into the inner row/column
    eamp[:, 1:-1, 1] = eamp[:, 1:-1, 0]
    eamp[:, 1:-1, -2] = eamp[:, 1:-1, -1]
    eamp[:, 1, 1:-1] = eamp[:, 0, 1:-1]
    eamp[:, -2, 1:-1] = eamp[:, -1, 1:-1]
    epha[:, 1:-1, 1] = epha[:, 1:-1, 0]
    epha[:, 1:-1, -2] = epha[:, 1:-1, -1]
    epha[:, 1, 1:-1] = epha[:, 0, 1:-1]
    epha[:, -2, 1:-1] = epha[:, -1, 1:-1]
    cmax[:, 1:-1, 1] = cmax[:, 1:-1, 0]
    cmax[:, 1:-1, -2] = cmax[:, 1:-1, -1]
    cmax[:, 1, 1:-1] = cmax[:, 0, 1:-1]
    cmax[:, -2, 1:-1] = cmax[:, -1, 1:-1]
    cmin[:, 1:-1, 1] = cmin[:, 1:-1, 0]
    cmin[:, 1:-1, -2] = cmin[:, 1:-1, -1]
    cmin[:, 1, 1:-1] = cmin[:, 0, 1:-1]
    cmin[:, -2, 1:-1] = cmin[:, -1, 1:-1]
    cpha[:, 1:-1, 1] = cpha[:, 1:-1, 0]
    cpha[:, 1:-1, -2] = cpha[:, 1:-1, -1]
    cpha[:, 1, 1:-1] = cpha[:, 0, 1:-1]
    cpha[:, -2, 1:-1] = cpha[:, -1, 1:-1]
    cang[:, 1:-1, 1] = cang[:, 1:-1, 0]
    cang[:, 1:-1, -2] = cang[:, 1:-1, -1]
    cang[:, 1, 1:-1] = cang[:, 0, 1:-1]
    cang[:, -2, 1:-1] = cang[:, -1, 1:-1]

    # Set the tide reference
    tideout = {}
    tideout['tides'] = tides
    tideout['tide_start'] = tide_start
    tideout['Eamp'] = eamp
    tideout['Ephase'] = epha
    tideout['Cmajor'] = cmax
    tideout['Cminor'] = cmin
    tideout['Cphase'] = cpha
    tideout['Cangle'] = cang

    seapy.roms.tide.create_forcing(tidefile,
                                   tideout,
                                   title="Tides from " + bryfile,
                                   epoch=epoch)
    bry.close()

    pass
Example #7
0
def from_stations(station_file, bry_file, grid=None):
    """
    Construct a boundary forcing file from a stations file generated by a parent-grid.
    The stations.in file must have been generated by the seapy.roms.gen_stations method;
    otherwise, the order will be incorrect.

    Parameters
    ==========
    station_file : string
        Filename of the stations file that is the source for the boundary data
    bry_file : string
        Filename of the boundary conditions file to generate
    grid : string or seapy.model.grid
        Grid that the boundary conditions are created for

    Returns
    -------
    None

    """
    grid = seapy.model.asgrid(grid)
    ncstation = netCDF4.Dataset(station_file)
    src_ref, time = seapy.roms.get_reftime(ncstation)

    # Create the boundary file and fill up the descriptive data
    ncbry = seapy.roms.ncgen.create_bry(bry_file,
                                        eta_rho=grid.eta_rho,
                                        xi_rho=grid.xi_rho,
                                        s_rho=grid.n,
                                        reftime=src_ref,
                                        clobber=False,
                                        title="generated from " + station_file)
    grid.to_netcdf(ncbry)

    # Load the times: we need to see if the times are duplicated
    # because if using assimilation, they may be duplicated for every
    # outer-loop. Currently, it overwrites the first one each time (this
    # will need to be fixed if ROMS is fixed).
    statime = ncstation.variables[time][:]
    dup = np.where(statime[1:] == statime[0])[0]
    rng = np.s_[:]
    if dup.size > 0:
        rng = np.s_[0:np.min(dup)]
        statime = statime[rng]
    brytime = seapy.roms.get_timevar(ncbry)
    ncbry.variables[brytime][:] = seapy.roms.date2num(
        seapy.roms.num2date(ncstation, time, rng), ncbry, brytime)

    # Set up the indices
    bry = {
        "south": range(0, grid.lm),
        "north": range(grid.lm, 2 * grid.lm),
        "west": range(2 * grid.lm, 2 * grid.lm + grid.ln),
        "east": range(2 * grid.lm + grid.ln, 2 * (grid.lm + grid.ln))
    }

    # Get the information to construct the depths of the station data
    sta_vt = ncstation.variables["Vtransform"][:]
    sta_hc = ncstation.variables["hc"][:]
    sta_s_rho = ncstation.variables["s_rho"][:]
    sta_cs_r = ncstation.variables["Cs_r"][:]
    sta_h = ncstation.variables["h"][:]
    sta_angle = ncstation.variables["angle"][:]
    sta_lon = ncstation.variables["lon_rho"][:]
    sta_lat = ncstation.variables["lat_rho"][:]
    sta_mask = np.ones(sta_lat.shape)
    sta_mask[sta_lon * sta_lat > 1e10] = 0

    # Load the station data as we need to manipulate it
    sta_zeta = np.ma.masked_greater(ncstation.variables["zeta"][rng], 100)
    sta_ubar = np.ma.masked_greater(ncstation.variables["ubar"][rng], 100)
    sta_vbar = np.ma.masked_greater(ncstation.variables["vbar"][rng], 100)
    sta_temp = np.ma.masked_greater(ncstation.variables["temp"][rng], 100)
    sta_salt = np.ma.masked_greater(ncstation.variables["salt"][rng], 100)
    sta_u = np.ma.masked_greater(ncstation.variables["u"][rng], 100)
    sta_v = np.ma.masked_greater(ncstation.variables["v"][rng], 100)
    ncstation.close()

    # Create the true positions and mask
    grid_h = np.concatenate(
        [grid.h[0, :], grid.h[-1, :], grid.h[:, 0], grid.h[:, -1]])
    grid_lon = np.concatenate([
        grid.lon_rho[0, :], grid.lon_rho[-1, :], grid.lon_rho[:, 0],
        grid.lon_rho[:, -1]
    ])
    grid_lat = np.concatenate([
        grid.lat_rho[0, :], grid.lat_rho[-1, :], grid.lat_rho[:, 0],
        grid.lat_rho[:, -1]
    ])
    grid_mask = np.concatenate([
        grid.mask_rho[0, :], grid.mask_rho[-1, :], grid.mask_rho[:, 0],
        grid.mask_rho[:, -1]
    ])
    grid_angle = np.concatenate([
        grid.angle[0, :], grid.angle[-1, :], grid.angle[:, 0], grid.angle[:,
                                                                          -1]
    ])

    # Search for bad stations due to child grid overlaying parent mask.
    # Unfortunately, ROMS will give points that are not at the locations
    # you specify if those points conflict with the mask. So, these points
    # are simply replaced with the nearest.
    dist = np.sqrt((sta_lon - grid_lon)**2 + (sta_lat - grid_lat)**2)
    bad_pts = np.where(np.logical_and(dist > 0.001, grid_mask == 1))[0]
    good_pts = np.where(np.logical_and(dist < 0.001, grid_mask == 1))[0]
    for i in bad_pts:
        didx = np.sqrt((sta_lon[i] - sta_lon[good_pts])**2 +
                       (sta_lat[i] - sta_lat[good_pts])**2).argmin()
        index = good_pts[didx]
        sta_h[i] = sta_h[index]
        sta_angle[i] = sta_angle[index]
        sta_lon[i] = sta_lon[index]
        sta_lat[i] = sta_lat[index]
        sta_zeta[:, i] = sta_zeta[:, index]
        sta_ubar[:, i] = sta_ubar[:, index]
        sta_vbar[:, i] = sta_vbar[:, index]
        sta_temp[:, i, :] = sta_temp[:, index, :]
        sta_salt[:, i, :] = sta_salt[:, index, :]
        sta_u[:, i, :] = sta_u[:, index, :]
        sta_v[:, i, :] = sta_v[:, index, :]

    # Construct the boundaries: a dictionary of boundary side and two element
    # array whether the u[0] or v[1] dimensions need to be averaged
    sides = {
        "north": [True, False],
        "south": [True, False],
        "east": [False, True],
        "west": [False, True]
    }
    delta_angle = sta_angle - grid_angle
    sta_ubar, sta_vbar = seapy.rotate(sta_ubar, sta_vbar, delta_angle)
    sta_u, sta_v = seapy.rotate(sta_u, sta_v,
                                np.tile(delta_angle, (sta_u.shape[-1], 1)).T)

    # Set up the parameters for depth-interpolated
    wght = 5
    nx = 3
    ny = 9

    # Build a non-extrapolating field to interpolate. Generate the
    # position and depth
    def __expand_field(x):
        shp = x.shape
        y = np.zeros((shp[0] + 2, shp[1] + 2))
        y[1:-1, 1:-1] = x
        y[1:-1, 0] = x[:, 0]
        y[1:-1, -1] = x[:, -1]
        y[0, :] = y[1, :]
        y[-1, :] = y[-2, :]
        return y

    for side in sides:
        print(side)

        # Masks
        sta_ocean = np.where(sta_mask[bry[side]] == 1)[0]
        ocean = np.where(grid_mask[bry[side]] == 1)[0]

        # If we have a masked boundary, skip it
        if not np.any(ocean):
            continue

        # 1) Zeta
        ncbry.variables["zeta_" + side][:, ocean] = sta_zeta[:,
                                                             bry[side]][:,
                                                                        ocean]

        # 2) Ubar
        if sides[side][0]:
            ncbry.variables["ubar_" +
                            side][:] = 0.5 * (sta_ubar[:, bry[side][0:-1]] +
                                              sta_ubar[:, bry[side][1:]])
        else:
            ncbry.variables["ubar_" + side][:] = sta_ubar[:, bry[side]]

        # 3) Vbar
        if sides[side][1]:
            ncbry.variables["vbar_" +
                            side][:] = 0.5 * (sta_vbar[:, bry[side][0:-1]] +
                                              sta_vbar[:, bry[side][1:]])
        else:
            ncbry.variables["vbar_" + side][:] = sta_vbar[:, bry[side]]

        # For 3D variables, we need to loop through time and interpolate
        # onto the child grid. Construct the distances
        x = np.zeros(len(bry[side]))
        x[1:] = np.cumsum(
            seapy.earth_distance(grid_lon[bry[side][0:-1]],
                                 grid_lat[bry[side][0:-1]],
                                 grid_lon[bry[side][1:]],
                                 grid_lat[bry[side][1:]]))
        sta_x = seapy.adddim(x, len(sta_s_rho))
        x = seapy.adddim(x, len(grid.s_rho))

        for n, t in seapy.progressbar.progress(enumerate(statime),
                                               statime.size):
            sta_depth = seapy.roms.depth(sta_vt, sta_h[bry[side]], sta_hc,
                                         sta_s_rho, sta_cs_r,
                                         sta_zeta[n, bry[side]])
            depth = seapy.roms.depth(grid.vtransform, grid_h[bry[side]],
                                     grid.hc, grid.s_rho, grid.cs_r,
                                     sta_zeta[n, bry[side]])

            in_x = __expand_field(sta_x[:, sta_ocean])
            in_x[:, 0] = in_x[:, 0] - 3600
            in_x[:, -1] = in_x[:, -1] + 3600
            in_depth = __expand_field(sta_depth[:, sta_ocean])
            in_depth[0, :] = in_depth[0, :] - 1000
            in_depth[-1, :] = in_depth[-1, :] + 10

            # 4) Temp
            in_data = __expand_field(
                np.transpose(sta_temp[n, bry[side], :][sta_ocean, :]))
            ncbry.variables["temp_" + side][n, :] = 0.0
            ncbry.variables["temp_" + side][n, :,
                                            ocean], pmap = seapy.oa.oasurf(
                                                in_x,
                                                in_depth,
                                                in_data,
                                                x[:, ocean],
                                                depth[:, ocean],
                                                nx=nx,
                                                ny=ny,
                                                weight=wght)

            # 5) Salt
            in_data = __expand_field(
                np.transpose(sta_salt[n, bry[side], :][sta_ocean, :]))
            ncbry.variables["salt_" + side][n, :] = 0.0
            ncbry.variables["salt_" + side][n, :,
                                            ocean], pmap = seapy.oa.oasurf(
                                                in_x,
                                                in_depth,
                                                in_data,
                                                x[:, ocean],
                                                depth[:, ocean],
                                                pmap=pmap,
                                                nx=nx,
                                                ny=ny,
                                                weight=wght)

            # 6) U
            in_data = __expand_field(
                np.transpose(sta_u[n, bry[side], :][sta_ocean, :]))
            data = np.zeros(x.shape)
            data[:, ocean], pmap = seapy.oa.oasurf(in_x,
                                                   in_depth,
                                                   in_data,
                                                   x[:, ocean],
                                                   depth[:, ocean],
                                                   pmap=pmap,
                                                   nx=nx,
                                                   ny=ny,
                                                   weight=wght)
            if sides[side][0]:
                ncbry.variables["u_" + side][n, :] = 0.5 * (data[:, 0:-1] +
                                                            data[:, 1:])
            else:
                ncbry.variables["u_" + side][n, :] = data

            # 7) V
            in_data = __expand_field(
                np.transpose(sta_v[n, bry[side], :][sta_ocean, :]))
            data = data * 0
            data[:, ocean], pmap = seapy.oa.oasurf(in_x,
                                                   in_depth,
                                                   in_data,
                                                   x[:, ocean],
                                                   depth[:, ocean],
                                                   pmap=pmap,
                                                   nx=nx,
                                                   ny=ny,
                                                   weight=wght)
            if sides[side][1]:
                ncbry.variables["v_" + side][n, :] = 0.5 * (data[:, 0:-1] +
                                                            data[:, 1:])
            else:
                ncbry.variables["v_" + side][n, :] = data
            ncbry.sync()
    ncbry.close()
    pass