Beispiel #1
0
def sep_battjes(eta, ot, h, x, sten, vd=True, verbose=False):
    """    
    PARAMETERS:
    -----------
    eta     : long wave water surface elevation matrix (time,points)
    ot      : time vector [s]
    h       : water depth [m]
    x       : point location [m]
    sten    : Point averaging stencil
    vd      : Use the extension proposed by van Dongeren et al. (2007). 
              Defaults to True.
    verbose : (optional) True for some printed info
    
    RETURNS:
    --------
    etaInc  : incident wave time series [m]
    etaRef  : reflected wave time series [m]
    
    NOTES:
    ------
    1. eta has to be sampled at the same rate for all points
    2. numpy arrays are assumed
    3. x axis should point landward (i.e. eta_inc travel with increasing x)
    4. van Dongeren et al. (2007) extended the separation method of 
       Battjes et al. (2004) by considering wave shoaling and phase speed
       effects.
    
    REFERENCES:
    -----------
    Battjes, J. A., H. J. Bakkenes, T. T. Janssen, and A. R. van Dongeren, 2004:
        Shoaling of subharmonic gravity waves. Journal of Geophysical Research,
        109, C02009, doi:10.1029/2003JC001863.
    van Dongeren, A., J. Battjes, T. Janssen, J. van Noorloos, K. Steenhauer, 
        G. Steenbergen, and A. Reniers, 2007: Shoaling and shoreline 
        dissipation of low-frequency waves. Journal of Geophysical Research,
        112, C02011, doi:10.1029/2006JC003701.
    """

    # Compute general Fourier parameters
    N = ot.shape[0]
    dt = np.mean(ot[1:] - ot[:-1])
    fN = 1.0 / (2 * dt)

    # Compute group velocities for incoming waves and shallow water propagation
    # velocities for reflected waves.
    freq = np.fft.fftfreq(N, dt)
    k = np.zeros_like(eta)
    c = np.zeros_like(eta)
    cg = np.zeros_like(eta)
    clin = np.zeros_like(eta)

    # Loop over frequencies (may take advantage of the symmetry properties)
    if verbose:
        print('Long wave incident and reflected wave separation')
        if vd:
            print('  Using the van Dongeren et al. (2007) methodology')
        else:
            print('  Using the Battjes et al. (2004) methodology')
        print('Computing phase and group velocities based on linear theory')
        print('  Be patient ...')

    # Time loop
    for aa in range(k.shape[0]):

        # Loop over points in the array
        for bb in range(k.shape[1]):

            # Compute wave number
            if np.isclose(freq[aa], 0):
                k[aa, bb] = 0.0
                c[aa, bb] = 0.0
                cg[aa, bb] = 0.0
                clin[aa, bb] = 0.0
            else:
                k[aa, bb] = _gwaves.dispersion(np.abs(1.0 / freq[aa]), h[bb])
                # Compute the wave celerity and group velocity
                c[aa,
                  bb], n, cg[aa,
                             bb] = _gwaves.celerity(np.abs(1.0 / freq[aa]),
                                                    h[bb])
                # Compute celerity based on shallow water equations
                clin[aa, bb] = np.sqrt(9.81 * h[bb])

    # Equation numbers based on van Dongeren et al 2007
    # First working on equation A1 ---------------------------------------------

    # Compute the Fourier transform and arrange the frequencies
    z_mp = np.fft.fft(eta, axis=0)
    freq = np.fft.fftfreq(N, dt)

    # The reflected waves will be found by looking at finite stencils.
    eta_i_b = np.zeros_like(eta) * np.NAN
    eta_r_b = np.zeros_like(eta) * np.NAN

    # Compute where to start the counter based on the stencil and the dx
    half_sten = int((sten - 1) / 2)
    ind_min = half_sten
    ind_max = eta.shape[1] - ind_min

    # Loop over array
    for ii in range(ind_min, ind_max):

        # Progress update
        if verbose:
            print('  Point ' + np.str(ii - ind_min + 1) + ' of ' +
                  np.str(ind_max - ind_min))

        # Work on a subset of eta now
        subset_ind = np.arange(ii - half_sten, ii + half_sten + 1, 1)
        cg_work = cg[:, subset_ind].copy()
        clin_work = clin[:, subset_ind].copy()
        h_work = h[subset_ind].copy()
        x_work = x[subset_ind].copy()
        z_mp_work = z_mp[:, subset_ind].copy()

        # Equation A2 ----------------------------------------------------------
        # z_mp = q_i_mpn z_i_mRn + Q_r_mpn Z_r_mRn + e_mpn
        # The Fourier transform is considered as the sum of an incoming wave
        # component and a reflected wave component with an error term.
        # The next step is to assume that the amplitude and phase factors are
        # close to the values produced by linear wave theory.

        # Estimate the factors Q (Equations A4,A5,A6)
        freq_mat = np.repeat(np.expand_dims(freq, axis=-1),
                             h_work.shape[0],
                             axis=-1)
        q_i_mp = np.zeros_like(freq_mat) * 1j
        q_r_mp = np.zeros_like(freq_mat) * 1j
        for aa in range(x_work.shape[0]):
            q_i_mp[:, aa] = np.exp(-1j * np.trapz(
                2.0 * np.pi * freq_mat[:, 0:aa + 1] / cg_work[:, 0:aa + 1],
                x_work[0:aa + 1],
                axis=-1))
            q_r_mp[:, aa] = np.exp(1j * np.trapz(
                2.0 * np.pi * freq_mat[:, 0:aa + 1] / clin_work[:, 0:aa + 1],
                x_work[0:aa + 1],
                axis=-1))

        # Solve equation A3 to estimate z_i_mR and z_r_mR by using the least
        # squares method since the system is overdetermined --------------------
        z_i_mR = np.zeros((ot.shape[0], )) * 1j
        z_r_mR = np.zeros_like(z_i_mR)

        for aa in range(ot.shape[0]):
            # Put system of equations in the form Ax = B
            q_mat = np.vstack((q_i_mp[aa, :], q_r_mp[aa, :])).T
            if np.sum(np.isnan(q_mat)) > 0:
                continue
                z_i_mR[aa] = 0.0
                z_r_mR[aa] = 0.0
            else:
                # Use least squares method to find solution
                z_i_mR[aa], z_r_mR[aa] = np.linalg.lstsq(
                    q_mat, z_mp_work[aa, :])[0]

        # So far the methodology applied is the one described in Battjes (2004).
        # If the user selected true then the modifications of
        # van Dongeren et al. (2007) will be implemented.
        if vd:

            # Correction for incident waves ------------------------------------
            # Phase correction equation (A7)
            q_i_mp *= z_mp_work / np.repeat(np.expand_dims(np.abs(z_i_mR),
                                                           axis=-1),
                                            z_mp_work.shape[1],
                                            axis=-1)

            # Solve equation (A3)
            z_i_mR, z_r_mR = _vanDongeren2007A3(q_i_mp, q_r_mp, z_mp_work)

            # Correction for amplitude (A8)
            q_i_mp *= (np.abs(z_mp_work) /
                       np.repeat(np.expand_dims(np.abs(z_i_mR), axis=-1),
                                 z_mp_work.shape[1],
                                 axis=-1))

            # Solve equation (A3)
            z_i_mR, z_r_mR = _vanDongeren2007A3(q_i_mp, q_r_mp, z_mp_work)

            # Correction for reflected waves -----------------------------------
            # Phase correction equation (A7)
            q_r_mp *= (z_mp_work /
                       np.repeat(np.expand_dims(np.abs(z_r_mR), axis=-1),
                                 z_mp_work.shape[1],
                                 axis=-1))

            # Solve equation (A3)
            z_i_mR, z_r_mR = _vanDongeren2007A3(q_i_mp, q_r_mp, z_mp_work)

            # Correction for amplitude (A8)
            q_r_mp *= (np.abs(z_mp_work) /
                       np.repeat(np.expand_dims(np.abs(z_r_mR), axis=-1),
                                 z_mp_work.shape[1],
                                 axis=-1))

            # Solve equation (A3)
            z_i_mR, z_r_mR = _vanDongeren2007A3(q_i_mp, q_r_mp, z_mp_work)

        # Compute the inverse Fourier transform to get the time series of the
        # reflected and incident waves.
        eta_i_b[:, ii] = np.fft.ifft(z_i_mR).real
        eta_r_b[:, ii] = np.fft.ifft(z_r_mR).real

    # End of function
    return eta_i_b, eta_r_b
Beispiel #2
0
def sep_battjes(eta,ot,h,x,sten,vd=True,verbose=False):
    """    
    PARAMETERS:
    -----------
    eta     : long wave water surface elevation matrix (time,points)
    ot      : time vector [s]
    h       : water depth [m]
    x       : point location [m]
    sten    : Point averaging stencil
    vd      : Use the extension proposed by van Dongeren et al. (2007). 
              Defaults to True.
    verbose : (optional) True for some printed info
    
    RETURNS:
    --------
    etaInc  : incident wave time series [m]
    etaRef  : reflected wave time series [m]
    
    NOTES:
    ------
    1. eta has to be sampled at the same rate for all points
    2. numpy arrays are assumed
    3. x axis should point landward (i.e. eta_inc travel with increasing x)
    4. van Dongeren et al. (2007) extended the separation method of 
       Battjes et al. (2004) by considering wave shoaling and phase speed
       effects.
    
    REFERENCES:
    -----------
    Battjes, J. A., H. J. Bakkenes, T. T. Janssen, and A. R. van Dongeren, 2004:
        Shoaling of subharmonic gravity waves. Journal of Geophysical Research,
        109, C02009, doi:10.1029/2003JC001863.
    van Dongeren, A., J. Battjes, T. Janssen, J. van Noorloos, K. Steenhauer, 
        G. Steenbergen, and A. Reniers, 2007: Shoaling and shoreline 
        dissipation of low-frequency waves. Journal of Geophysical Research,
        112, C02011, doi:10.1029/2006JC003701.
    """
    
    # Compute general Fourier parameters
    N  = ot.shape[0]
    dt = np.mean(ot[1:] - ot[:-1])
    fN = 1.0/(2*dt)
        
    # Compute group velocities for incoming waves and shallow water propagation
    # velocities for reflected waves. 
    freq = np.fft.fftfreq(N,dt)
    k    = np.zeros_like(eta)
    c    = np.zeros_like(eta)
    cg   = np.zeros_like(eta)
    clin = np.zeros_like(eta)
    
    # Loop over frequencies (may take advantage of the symmetry properties)
    if verbose:
        print('Long wave incident and reflected wave separation')
        if vd:
            print('  Using the van Dongeren et al. (2007) methodology')
        else:
            print('  Using the Battjes et al. (2004) methodology')
        print('Computing phase and group velocities based on linear theory')
        print('  Be patient ...')
        
    # Time loop        
    for aa in range(k.shape[0]):
            
        # Loop over points in the array
        for bb in range(k.shape[1]):
            
            # Compute wave number
            if np.isclose(freq[aa],0):
                k[aa,bb]    = 0.0
                c[aa,bb]    = 0.0
                cg[aa,bb]   = 0.0
                clin[aa,bb] = 0.0
            else:
                k[aa,bb] = _gwaves.dispersion(np.abs(1.0/freq[aa]),h[bb])
                # Compute the wave celerity and group velocity
                c[aa,bb],n,cg[aa,bb] = _gwaves.celerity(np.abs(1.0/freq[aa]),
                                                       h[bb])
                # Compute celerity based on shallow water equations
                clin[aa,bb] = np.sqrt(9.81*h[bb])
    
    
    # Equation numbers based on van Dongeren et al 2007
    # First working on equation A1 ---------------------------------------------
    
    # Compute the Fourier transform and arrange the frequencies
    z_mp = np.fft.fft(eta,axis=0)
    freq = np.fft.fftfreq(N,dt)
    
    # The reflected waves will be found by looking at finite stencils. 
    eta_i_b = np.zeros_like(eta) * np.NAN
    eta_r_b = np.zeros_like(eta) * np.NAN
    
    # Compute where to start the counter based on the stencil and the dx
    half_sten = int((sten - 1)/2)
    ind_min = half_sten
    ind_max = eta.shape[1] - ind_min
    
    # Loop over array
    for ii in range(ind_min,ind_max):
    
        # Progress update
        if verbose:
            print('  Point ' + np.str(ii-ind_min+1) + ' of ' + 
                  np.str(ind_max-ind_min))
    
        # Work on a subset of eta now
        subset_ind = np.arange(ii-half_sten,ii+half_sten+1,1)
        cg_work    = cg[:,subset_ind].copy()
        clin_work  = clin[:,subset_ind].copy()
        h_work     = h[subset_ind].copy()
        x_work     = x[subset_ind].copy()
        z_mp_work  = z_mp[:,subset_ind].copy()
        
        # Equation A2 ----------------------------------------------------------
        # z_mp = q_i_mpn z_i_mRn + Q_r_mpn Z_r_mRn + e_mpn
        # The Fourier transform is considered as the sum of an incoming wave
        # component and a reflected wave component with an error term. 
        # The next step is to assume that the amplitude and phase factors are 
        # close to the values produced by linear wave theory. 
            
        # Estimate the factors Q (Equations A4,A5,A6)
        freq_mat = np.repeat(np.expand_dims(freq,axis=-1),
                             h_work.shape[0],axis=-1)
        q_i_mp   = np.zeros_like(freq_mat)*1j
        q_r_mp   = np.zeros_like(freq_mat)*1j
        for aa in range(x_work.shape[0]):
            q_i_mp[:,aa] = np.exp(-1j*np.trapz(2.0*np.pi*freq_mat[:,0:aa+1]/
                                               cg_work[:,0:aa+1],
                                               x_work[0:aa+1],axis=-1))
            q_r_mp[:,aa] = np.exp(1j*np.trapz(2.0*np.pi*freq_mat[:,0:aa+1]/
                                              clin_work[:,0:aa+1],
                                              x_work[0:aa+1],axis=-1))
            
    
        # Solve equation A3 to estimate z_i_mR and z_r_mR by using the least
        # squares method since the system is overdetermined --------------------
        z_i_mR = np.zeros((ot.shape[0],)) * 1j
        z_r_mR = np.zeros_like(z_i_mR)
        
        for aa in range(ot.shape[0]):
            # Put system of equations in the form Ax = B
            q_mat = np.vstack((q_i_mp[aa,:],q_r_mp[aa,:])).T
            if np.sum(np.isnan(q_mat)) > 0:
                continue
                z_i_mR[aa] = 0.0
                z_r_mR[aa] = 0.0
            else:
                # Use least squares method to find solution
                z_i_mR[aa],z_r_mR[aa] = np.linalg.lstsq(q_mat,
                                                        z_mp_work[aa,:])[0]
        
        
        # So far the methodology applied is the one described in Battjes (2004). 
        # If the user selected true then the modifications of 
        # van Dongeren et al. (2007) will be implemented. 
        if vd:
            
            # Correction for incident waves ------------------------------------
            # Phase correction equation (A7) 
            q_i_mp *= z_mp_work / np.repeat(np.expand_dims(np.abs(z_i_mR),
                                                           axis=-1),
                                            z_mp_work.shape[1],axis=-1)

            # Solve equation (A3)
            z_i_mR,z_r_mR = _vanDongeren2007A3(q_i_mp,q_r_mp,z_mp_work)
            
            # Correction for amplitude (A8)
            q_i_mp *= (np.abs(z_mp_work) / 
                       np.repeat(np.expand_dims(np.abs(z_i_mR),axis=-1),
                                 z_mp_work.shape[1],axis=-1))
                
            # Solve equation (A3)
            z_i_mR,z_r_mR = _vanDongeren2007A3(q_i_mp,q_r_mp,z_mp_work)                     
    
            # Correction for reflected waves -----------------------------------
            # Phase correction equation (A7) 
            q_r_mp *= (z_mp_work / 
                       np.repeat(np.expand_dims(np.abs(z_r_mR),axis=-1),
                                 z_mp_work.shape[1],axis=-1))
                                                    
            # Solve equation (A3)
            z_i_mR,z_r_mR = _vanDongeren2007A3(q_i_mp,q_r_mp,z_mp_work)
            
            # Correction for amplitude (A8)
            q_r_mp *= (np.abs(z_mp_work) / 
                       np.repeat(np.expand_dims(np.abs(z_r_mR),axis=-1),
                                 z_mp_work.shape[1],axis=-1)) 
                                    
            # Solve equation (A3)
            z_i_mR,z_r_mR = _vanDongeren2007A3(q_i_mp,q_r_mp,z_mp_work)
                            
        
        # Compute the inverse Fourier transform to get the time series of the 
        # reflected and incident waves.
        eta_i_b[:,ii] = np.fft.ifft(z_i_mR).real
        eta_r_b[:,ii] = np.fft.ifft(z_r_mR).real
        
    # End of function
    return eta_i_b,eta_r_b
Beispiel #3
0
def wave_tracks_predictor(local_maxima,wave_height,ot,xInst,x,h,wp=None):
    """
    Code to track the wave crests througout a linear instrument array using
    bathymetric data and linear wave theory as predictors

    USAGE:
    ------
    wave_tracks = wave_tracks(local_extrema,ot_lag,twind)

    PARAMETERS:
    -----------
    local_maxima  : Array of local maxima indices (see local_extrema)
    wave_height   : Array of wave heights (see wave_height)
    ot            : Time vector [s]
    xInst         : Instrument easting
    x             : Easting of topography/bathymetry [m]
                    Must increase landward
    h             : Water depth [m]
    wp            : (optional) Representative wave period [s]

    RETURNS:
    --------
    wave_tracks  : Best approximation of the wave position across shore.
    wave_ind     : Incides of the wave tracks for slicing local_maxima and 
                   wave_height
    
    NOTES:
    ------
    1. Do not include NANs in the x and h variables. 
    2. xInst should be within the limits of x
    3. If waves were not tracked an index of -999999 will be used.
    4. If wp is not provided, the shallow water wave celerity will be used 
       as predictor.
    """
    
    # Compute the wave celerity based on linear wave theory if the wave period
    # is provided, otherwise the shallow water celerity is computed
    if wp:
        cel = np.zeros_like(h)
        for aa in range(cel.shape[0]):
            tmpCel = _gwaves.celerity(wp,h[aa])
            cel[aa] = tmpCel[0]
            del tmpCel
        
    else:
        cel = (9.81*h)**0.5
        
    # Compute time of travel
    timeTravel = np.zeros_like(x)
    timeTravel[1:] = np.cumsum(2.0/(cel[1:]+cel[:-1])*(x[1:] - x[:-1]))
    
    # Interpolate the location of instruments
    timeInt    = spi.interpolate.interp1d(x,timeTravel)
    timeOffset = timeInt(xInst)
    
    # Normalize the time travel vector
    timeOffset -= timeOffset[0]

    # Find the water depth at the instruments 
    depthInt = spi.interpolate.interp1d(x,h)
    depth    = depthInt(xInst) 
    
    # Expected average velocity between instrument locations
    # Forward differences of course.
    meanCel     = np.zeros_like(xInst) * np.NAN
    meanCel[1:] = np.abs(np.diff(xInst)) / np.diff(timeOffset) 
    
    # Loop over local maxima and preallocate the variables
    wave_tracks = np.ones((len(local_maxima[0]),xInst.shape[0]),
                          dtype=np.int64) * -999999
    wave_ind = np.copy(wave_tracks)                      
    
    for aa in range(wave_tracks.shape[0]):
     
        # Preallocate temporary variables
        # tmp_ind will be allocated into wave_tracks 
        # tmp_wave_ind will be allocated into wave_ind
        tmp_ind = np.ones((wave_tracks.shape[1],)).astype(int) * -999999
        tmp_wave_ind = np.copy(tmp_ind)
        
        tmp_ind[0] = local_maxima[0][aa]
        tmp_wave_ind[0] = aa
        
        # Loop over sensors
        for bb in range(1,tmp_ind.shape[0]):
            
            # Previous wave time
            tmp_ot = ot[tmp_ind[bb-1]]
    
            # Find the next wave based on a celerity estimate
            tmp_dt = ot[local_maxima[bb]] - tmp_ot
            tmpCel = np.abs(xInst[bb-1] - xInst[bb]) / tmp_dt
            tmp_min_ind = np.argmin(np.abs(tmpCel - meanCel[bb]))
            
            # Check if we are tracking well into the past based on half of the
            # time series length
            futureFlag = ((ot[local_maxima[bb][tmp_min_ind]] - tmp_ot) < 
                          (ot[0] - ot[-1])/2.0)
            if futureFlag:
                break
            
            # Wave breaking flag based on saturated breaking (H=kh)
            dWH = ((wave_height[bb-1][tmp_wave_ind[bb-1]] - wave_height[bb]) /
                   wave_height[bb-1][tmp_wave_ind[bb-1]])
            maxdWH = (depth[bb-1] - depth[bb])/depth[bb-1]
            
            # Three checks here to consider the previous wave as the correct one
            # All must be true
            # 1. If the wave moves slower than the shallow water celerity
            # 2. The new trajectory does not exceed amplitude dispersion
            # 3. The wave is not much smaller than the one it maps to  
            
            # Find amplitude dispersion effect
            ampDisp = (9.81*wave_height[bb-1][tmp_wave_ind[bb-1]])**0.5   
            if (tmpCel[tmp_min_ind] < meanCel[bb] and
                tmpCel[tmp_min_ind-1] < (meanCel[bb]+ampDisp) and
                dWH[tmp_min_ind-1]<=dWH[tmp_min_ind]):
                tmp_min_ind -= 1
            
            # Check if we are tracking into the past      
            futureFlag = (ot[local_maxima[bb][tmp_min_ind]] - tmp_ot) < 0
            if futureFlag:
                tmp_min_ind += 1
                
            # Stand alone wave breaking flag
            if (dWH[tmp_min_ind] > maxdWH and 
                dWH[tmp_min_ind-1] < dWH[tmp_min_ind]):

                # Pick the previous wave if the speed makes sense
                dCel = (meanCel[bb] - tmpCel[tmp_min_ind-1]) / meanCel[bb]
                
                # Check if we are tracking into the past            
                futureFlag = ot[local_maxima[bb][tmp_min_ind-1]] > tmp_ot 
                
                # Negative means faster (need to do something objective here)
                if dCel > -0.5 and futureFlag:
                    tmp_min_ind -= 1       
            
            # Finally check for wave crossing (brute force bore capture)
            if aa > 0:
                if local_maxima[bb][tmp_min_ind] < wave_tracks[aa-1,bb]:
                    tmp_min_ind = wave_ind[aa-1,bb]                
                    
            # Allocate in arrays
            tmp_wave_ind[bb] = tmp_min_ind
            tmp_ind[bb] = local_maxima[bb][tmp_min_ind]
            
        # Allocate wave data        
        wave_tracks[aa,:] = np.copy(tmp_ind)
        wave_ind[aa,:] = np.copy(tmp_wave_ind)

    # Get out
    return wave_tracks,wave_ind