How to add boolean expression in for loop python instead of pasting computation lines under every elif

Question:

I am trying to convert a MATLAB script to Python. I have a working code, but it is quite clunky and I have pasted the computation lines under each if and elif lines to make it work. I am hoping to get any advice to make this code more elegant

The script is supposed to:

  1. Iterate through each value in an array, f.
  2. If f[j] is larger than 0.09, the variable, sigma = 0.09.
  3. If f[j] is smaller than 0.07, the variable, sigma = 0.07.
  4. Then, use the variable sigma to compute a value S[j].

My current code is here below.
(Edited) I put in my actual code after getting suggestions. I didn’t post it earlier as there was a problem with my formula to compute the wave spectrum S (Yes, it is the JONSWAP spectrum), My main focus is still on whether I can make my loop more elegant.

c,d and G and z are intermediate steps taken before computing S, to make things easier for me to compute. The formula in question:


# Part c : Assuming generated waves follows a JONSWAP spectrum with shape parameter = 3
#Plot spectrum and wave time series

import numpy as np
import matplotlib.pyplot as plt

U0 = 24 #m/s, wind speed @10m above water level
Fe = 400 #km,fetch
g = 9.81 #ms^-2, gravity
fp = 1/10.2 #peak frequency (Hz)
T1 = 10    #min duration for wave generation
shape = 3  #shape parameter

f = np.arange(0,180,1)/(T1*60) #array of frequencies
w = 2*np.pi*f
en = 0 + 2*np.pi*np.random.rand(181,1); #generating random phase numbers

#Calculating JONSWAP wave spectral density
a = 0.076*(Fe*1000*g/(U0**2))**-0.22
c = []
d = []
G = []
S = np.empty(max(f.shape),dtype=object)

for j in range(1,max(f.shape)):
    if f[j]<fp:
         sigma = 0.07
         c = -(f[j]-fp)**2
         d = 2*(sigma**2)*f[j]**2
         G = shape**np.exp(c/d) #shape function
         S[j-1] = a*g**2*G/((2*np.pi)**4*(f[j]**5)*np.exp((5/4)*(f[j]/fp)**-4))
    elif f[j]>fp:
        sigma = 0.09
        c = -(f[j]-fp)**2
        d = 2*(sigma**2)*f[j]**2
        G = shape**np.exp(c/d) #shape function
        S[j-1] = a*g**2*G/((2*np.pi)**4*(f[j]**5)*np.exp((5/4)*(f[j]/fp)**-4)) #Wave spectral density


#Plot wave spectrum

plt.plot(f,S,color = 'red', linestyle = 'solid',linewidth = 3, label = 'Fetch = 400km, shape parameter = 3, U0 = 24m/s')
plt.xlim(0,0.3)
plt.ylim(0,70)
plt.xlabel('Frequency (Hz)');plt.ylabel('Wave Spectral Density (m^2/Hz)');
plt.legend(loc='upper right')
plt.title('Wave Spectra of sea')
plt.show()
Asked By: Schlink

||

Answers:

Here you go (using np.where()).

SJ ends up as a normalised JONSWAP energy spectrum (i.e., area underneath = 1.0). Multiply it by (1/16)(rho.g)Hm02/fp if you want the absolute energy spectrum. (Hm0 is significant wave height; fp is peak frequency.)

import numpy as np
import matplotlib.pyplot as plt

nx = 400000
df = 0.0001
fmax = nx * df

ffp = np.linspace( df, fmax, nx )                # frequencies (as f/f_p)

#########################################################################
# The following spectra are normalised (to area = 1.0 )                 #
# Multiply by (1/16) (rho.g) H_m0^2 / fp to get absolute energy density #
#########################################################################

# Bretschneider spectrum (normalised)
SB = 5.0 / ffp ** 5 * np.exp( -1.25 / ffp ** 4 )

# JONSWAP spectrum (narrow-band version of above)
gamma = 3.3
sigma = np.where( ffp < 1.0, 0.07, 0.09 )
SJ = SB * gamma ** np.exp( -0.5 * ( ( ffp - 1 ) / sigma ) ** 2 )
SJ /= SJ.sum() * df                              # Normalise to area 1

fs = 14
fig, ax = plt.subplots( figsize=(8,5) )
ax.set_xlim( 0.0, 3.0 )
ax.set_ylim( 0.0, 3.5 )
ax.set_xlabel( r"$f / f_p$"       , fontsize=fs )
ax.set_ylabel( r"$S (normalised)$", fontsize=fs )
ax.xaxis.set_tick_params( labelsize=fs )
ax.yaxis.set_tick_params( labelsize=fs )
ax.plot( ffp, SB, "b-" , label="Bretschneider" )
ax.plot( ffp, SJ, "r-.", label="JONSWAP"       )
ax.legend()
plt.show()

Output:
enter image description here

Answered By: lastchance
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.