示例#1
0
    def test_depth_kwarg(self):
        nz = 100
        zN2 = 0.5*nz**-1 + np.arange(nz, dtype=np.float64)/nz
        zU = 0.5*nz**-1 + np.arange(nz+1, dtype=np.float64)/nz
        N2 = np.full(nz, 1.)
        f0 = 1.
        #beta = 1e-6
        beta = 0.
        Nx = 1
        Ny = 1
        dx = .1
        dy = .1
        k = fft.fftshift( fft.fftfreq(Nx, dx) )
        l = fft.fftshift( fft.fftfreq(Ny, dy) )
        ubar = np.zeros(nz+1)
        vbar = np.zeros(nz+1)
        etax = np.zeros(2)
        etay = np.zeros(2)

        with self.assertRaises(ValueError):
            z, growth_rate, vertical_modes = modes.instability_analysis_from_N2_profile(
                zN2, N2, f0, beta, k, l, zU, ubar, vbar, etax, etay, depth=zN2[-5]
            )

        # no error expected
        z, growth_rate, vertical_mode = modes.instability_analysis_from_N2_profile(
                zN2, N2, f0, beta, k, l, zU, ubar, vbar, etax, etay, depth=1.1
        )
示例#2
0
    def test_Eady(self, atol=5e-2, nz=20, Ah=0.):
        """ Eady setup
        """
        ###########
        # prepare parameters for Eady
        ###########
        nz = nz
        zin = np.arange(nz+1, dtype=np.float64)/nz
        N2 = np.full(nz, 1.)
        f0 = 1.
        beta = 0.
        Nx = 10
        Ny = 1
        dx = 1e-1
        dy = 1e-1
        k = fft.fftshift( fft.fftfreq(Nx, dx) )
        l = fft.fftshift( fft.fftfreq(Ny, dy) )
        vbar = np.zeros(nz+1)
        ubar = zin
        etax = np.zeros(2)
        etay = np.zeros(2)

        z, growth_rate, vertical_modes = \
            modes.instability_analysis_from_N2_profile(
                .5*(zin[1:]+zin[:-1]), N2, f0, beta, k, l,
                zin, ubar, vbar, etax, etay, depth=1., sort='LI', num=2
        )

        self.assertEqual(nz+1, vertical_modes.shape[0],
            msg='modes array must be in the right shape')

        self.assertTrue(np.all( np.diff(
                    growth_rate.reshape((growth_rate.shape[0], len(k)*len(l))).imag.max(axis=1) ) <= 0.),
            msg='imaginary part of modes should be descending')

        mode_amplitude1 = (np.absolute(vertical_modes[:, 0])**2).sum(axis=0)
        self.assertTrue(np.allclose(1., mode_amplitude1),
            msg='mode1 should be normalized to amplitude of 1 at all horizontal wavenumber points')

        mode_amplitude2 = (np.absolute(vertical_modes[:, 1])**2).sum(axis=0)
        self.assertTrue(np.allclose(1., mode_amplitude2),
            msg='mode2 should be normalized to amplitude of 1 at all horizontal wavenumber points')

        #########
        # Analytical solution for Eady growth rate
        #########
        growthEady = np.zeros(len(k))
        for i in range(len(k)):
            if (k[i]==0) or ((np.tanh(.5*k[i])**-1 - .5*k[i]) * (.5*k[i] - np.tanh(.5*k[i])) < 0):
                growthEady[i] = 0.
            else:
                growthEady[i] = ubar.max() * np.sqrt( (np.tanh(.5*k[i])**-1 - .5*k[i]) * (.5*k[i] - np.tanh(.5*k[i])) )

        self.assertTrue( np.allclose(growth_rate.imag[0, 0, :], growthEady, atol=atol),
            msg='The numerical growth rates should be close to the analytical Eady solution' )
示例#3
0
    def test_depth_kwarg(self):
        nz = 100
        zN2 = 0.5 * nz**-1 + np.arange(nz, dtype=np.float64) / nz
        zU = 0.5 * nz**-1 + np.arange(nz + 1, dtype=np.float64) / nz
        N2 = np.full(nz, 1.)
        f0 = 1.
        #beta = 1e-6
        beta = 0.
        Nx = 1
        Ny = 1
        dx = .1
        dy = .1
        k = fft.fftshift(fft.fftfreq(Nx, dx))
        l = fft.fftshift(fft.fftfreq(Ny, dy))
        ubar = np.zeros(nz + 1)
        vbar = np.zeros(nz + 1)
        etax = np.zeros(2)
        etay = np.zeros(2)

        with self.assertRaises(ValueError):
            z, growth_rate, vertical_modes = modes.instability_analysis_from_N2_profile(
                zN2,
                N2,
                f0,
                beta,
                k,
                l,
                zU,
                ubar,
                vbar,
                etax,
                etay,
                depth=zN2[-5])

        # no error expected
        z, growth_rate, vertical_mode = modes.instability_analysis_from_N2_profile(
            zN2, N2, f0, beta, k, l, zU, ubar, vbar, etax, etay, depth=1.1)
示例#4
0
    def test_OCCA_GulfStream(self, atol=1e-8):
        """ Actual profiles in the Gulf Stream region 
             (@ 39.5N, 299.5E)
        """
        ###########
        # prepare parameters for Gulf Stream region in OCCA
        ###########
        z_u = np.array([5.00000000e+00,   1.50000000e+01,   2.50000000e+01,
         3.50000000e+01,   4.50000000e+01,   5.50000000e+01,
         6.50000000e+01,   7.50050049e+01,   8.50250015e+01,
         9.50950012e+01,   1.05309998e+02,   1.15870003e+02,
         1.27150002e+02,   1.39739990e+02,   1.54470001e+02,
         1.72399994e+02,   1.94735001e+02,   2.22710007e+02,
         2.57470001e+02,   2.99929993e+02,   3.50679993e+02,
         4.09929993e+02,   4.77470001e+02,   5.52710022e+02,
         6.34735046e+02,   7.22400024e+02,   8.14470093e+02,
         9.09740112e+02,   1.00715503e+03,   1.10590503e+03,
         1.20553503e+03,   1.30620508e+03,   1.40914990e+03,
         1.51709497e+03,   1.63417480e+03,   1.76513477e+03,
         1.91414990e+03,   2.08403491e+03,   2.27622510e+03,
         2.49125000e+03,   2.72925000e+03,   2.99025000e+03,
         3.27425000e+03,   3.58125000e+03,   3.91125000e+03,
         4.26425000e+03,   4.64025000e+03,   5.03925000e+03,
         5.46125000e+03,   5.90625000e+03])
        z_N2 = -np.array([-10.00006115,   -20.00006114,   -30.00006113,   -40.00006112,
         -50.0000611 ,   -60.00006109,   -70.00256358,   -80.01506451,
         -90.06006328,  -100.20256308,  -110.5900682 ,  -121.51007976,
        -133.44509256,  -147.10512803,  -163.43519352,  -183.5678012 ,
        -208.72298023,  -240.09073926,  -278.70109317,  -325.30655719,
        -380.30712264,  -443.70276088,  -515.09343642,  -593.72659767,
        -678.57216844,  -768.44015906,  -862.11055267,  -958.45325725,
       -1056.53586028, -1155.72595435, -1255.87608991, -1357.68378579,
       -1463.12934261, -1575.64299213, -1699.66489761, -1839.65538686,
       -1999.10931291, -2180.15155508, -2383.76440293, -2610.28273438,
       -2859.78914881, -3132.29607118, -3427.80347989, -3746.3113517 ,
       -4087.81966191, -4452.32838443, -4839.83749199, -5250.34695635,
       -5683.85674858])
        ubar = np.array([0.24113144,  0.20566152,  0.18566666,  0.17763813,  0.17248898,
        0.16799432,  0.16402273,  0.16024273,  0.15672079,  0.1532983 ,
        0.15058691,  0.1480111 ,  0.14513075,  0.14221466,  0.13825534,
        0.13390785,  0.12829159,  0.12135932,  0.11275966,  0.10259634,
        0.09075638,  0.07769765,  0.06402871,  0.05062123,  0.0384005 ,
        0.02791209,  0.01922886,  0.01237531,  0.00755318,  0.00470483,
        0.00328818,  0.00261901,  0.00221545,  0.00182732,  0.0013118 ,
        0.00058111, -0.00035143, -0.0013624 , -0.00230507, -0.00308389,
       -0.00365073, -0.00393951, -0.00386523, -0.00344036, -0.00277483,
       -0.00189117, -0.00060206,  0.00060187,      np.nan,      np.nan])
        vbar = np.array([0.03732778,  0.03306238,  0.03844519,  0.04393799,  0.04580961,
        0.04673327,  0.04731352,  0.04768672,  0.04787091,  0.04791058,
        0.0476704 ,  0.04725287,  0.04666282,  0.04587267,  0.04479391,
        0.04350807,  0.04190299,  0.03983596,  0.03736874,  0.03421749,
        0.03057165,  0.02645037,  0.02181544,  0.01715759,  0.01278938,
        0.00886511,  0.00544434,  0.00260065,  0.00052863, -0.00065227,
       -0.00111283, -0.00120176, -0.00119863, -0.00122544, -0.00130761,
       -0.00143906, -0.00161413, -0.00183596, -0.00210659, -0.00240779,
       -0.002703  , -0.00296008, -0.00314709, -0.00320451, -0.00309561,
       -0.0028392 , -0.00253795,  0.        ,      np.nan,      np.nan])
        N2 = np.array([4.49013733e-05,   1.32619531e-04,   1.67213349e-04,
         1.39980381e-04,   1.08620176e-04,   8.89353316e-05,
         7.59696940e-05,   6.85660114e-05,   6.13053056e-05,
         4.96623307e-05,   4.26153730e-05,   3.83933836e-05,
         3.33244718e-05,   3.14573673e-05,   2.74780120e-05,
         2.50869570e-05,   2.35907064e-05,   2.26047540e-05,
         2.06309696e-05,   1.93499569e-05,   1.85802260e-05,
         1.73887368e-05,   1.49995125e-05,   1.25945779e-05,
         1.06210281e-05,   9.69791903e-06,   9.18845407e-06,
         7.56655382e-06,   5.00383224e-06,   2.83633215e-06,
         1.67170878e-06,   1.19350982e-06,   9.87252978e-07,
         9.54096555e-07,   1.05979705e-06,   1.18957478e-06,
         1.23432375e-06,   1.22190029e-06,   1.20084648e-06,
         1.18287498e-06,   1.14801849e-06,   1.08643614e-06,
         9.36511867e-07,   6.17342678e-07,   3.35507108e-07,
         3.19646379e-07,   2.60733349e-07,              np.nan,
                    np.nan])
        Rd = 25787.38588424
        f0 = 9.27671062527e-05
        beta = 1.76637107718e-11
        Nx = 100; dx = 4e3
        k = np.array([-1.88495559e-04,  -1.72787596e-04,  -1.57079633e-04,  -1.41371669e-04,
          -1.25663706e-04,  -1.09955743e-04,  -9.42477796e-05,  -7.85398163e-05,
          -6.28318531e-05,  -4.71238898e-05,  -3.14159265e-05,  -1.57079633e-05])
        l = np.array([0.])
        etax = np.zeros(2)
        etay = np.zeros(2)

        z, growth_rate, vertical_modes = \
            modes.instability_analysis_from_N2_profile(
                z_N2, N2, f0, beta, k, l,
                z_u, ubar, vbar, etax, etay, num=2
        )
        
        self.assertEqual(len(z), vertical_modes.shape[0],
            msg='modes array must be in the right shape')

        self.assertTrue(np.all( np.diff(
                    growth_rate.reshape((growth_rate.shape[0], 
                                         len(k)*len(l))).imag.max(axis=1) ) <= 0.),
            msg='imaginary part of modes should be descending')
        
        mode_amplitude1 = (np.absolute(vertical_modes[:, 0])**2).sum(axis=0)
        self.assertTrue(np.allclose(1., mode_amplitude1),
            msg='mode1 should be normalized to amplitude of 1 at all horizontal wavenumber points')
        
        mode_amplitude2 = (np.absolute(vertical_modes[:, 1])**2).sum(axis=0)
        self.assertTrue(np.allclose(1., mode_amplitude2),
            msg='mode2 should be normalized to amplitude of 1 at all horizontal wavenumber points')
        
        ##########
        # Row corresponding to l=0 of growth mode (Ah=0)
        ##########
        w_sol = np.array([1.04641026e-06,   8.55850224e-07,   6.56131690e-07,   4.40205651e-07,
       2.22218418e-07,   1.07589996e-07,   9.46591756e-08,   4.64407815e-08,
       1.29096295e-07,   6.74206451e-08,   5.74783413e-07,   6.86202530e-08])
        
        self.assertTrue( np.allclose(growth_rate.imag[0, 0], w_sol, atol=atol),
            msg='The OCCA numerical growth rates should be close to the solution with Ah=0' )
        
        z, growth_rate, vertical_modes = \
            modes.instability_analysis_from_N2_profile(
                z_N2, N2, f0, beta, k, l,
                z_u, ubar, vbar, etax, etay, Ah=1e1, num=2
        )
        
        ##########
        # Row corresponding to l=0 of growth mode (Ah=10.)
        ##########
        w_sol = np.array([3.15410778e-06,   2.82584613e-06,   2.47671069e-06,   2.10243465e-06,
       1.69802277e-06,   1.26121608e-06,   8.09682819e-07,   4.13752221e-07,
       1.43811161e-07,   7.84288795e-08,   5.93310629e-07,   6.33544320e-08])
        
        self.assertTrue( np.allclose(growth_rate.imag[0, 0], w_sol, atol=atol),
            msg='The OCCA numerical growth rates should be close to the solution with Ah=10' )
示例#5
0
    def test_linear_instability_args(self):
        nz = 10
        N2 = np.zeros(nz)
        depth = np.arange(nz)
        ubar = 1e-2 * np.ones(nz+1)
        vbar = 1e-2 * np.ones(nz+1)
        beta = 1e-6
        etax = np.array([1e-1*beta, beta])
        etay = np.array([1e-1*beta, beta])
        Nx = 1
        Ny = 1
        dx = .1
        dy = .1
        k = fft.fftshift( fft.fftfreq(Nx, dx) )
        l = fft.fftshift( fft.fftfreq(Ny, dy) )

        ###########
        # check for unequal lengths of arrays
        ###########
        with self.assertRaises(ValueError):
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth[1:], N2, 1., beta, k, l, depth, ubar, vbar, etax, etay
            )
        with self.assertRaises(ValueError):
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth, N2[1:], 1., beta, k ,l, depth, ubar, vbar, etax, etay
            )
        
        with self.assertRaises(ValueError):
            _, _, _ = modes.instability_analysis_from_N2_profile(
                -depth, N2, 1., beta, k ,l, np.append(depth, float(nz+1)), ubar, vbar, etax, etay
            )
        
        with self.assertRaises(ValueError):
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth, N2[1:], 1., beta, k ,l, -np.append(depth, float(nz+1)), ubar, vbar, etax, etay
            )

        depth_non_monotonic = depth
        depth_non_monotonic[0] = 5
        depth_non_monotonic[1] = 5
        # check for non-monotonic profile
        Nx = 50
        Ny = 50
        dx = 1e-1
        dy = 1e-1
        k = fft.fftshift( fft.fftfreq(Nx, dx) )
        l = fft.fftshift( fft.fftfreq(Ny, dy) )
        with self.assertRaises(ValueError) as cm:
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth_non_monotonic[1:], N2, 1., beta, k, l, depth, ubar, vbar, etax, etay
            )
        
        N2 = np.append(N2, [1.,1.]) #N2 has longer length than u
        with self.assertRaises(ValueError):
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth, N2, 1., beta, k ,l, depth, ubar, vbar, etax, etay
            )
        
        N2 = np.zeros(nz)
        depth = np.arange(nz+1)
        ubar = np.zeros(nz+1)
        vbar = np.zeros(nz+1)
        etax = np.zeros(2)
        etay = np.zeros(2)
        beta = 0.
        with warnings.catch_warnings(record=True) as w:
            # Trigger a warning
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth[:-1], N2, 0., beta, k ,l, depth, ubar, vbar, etax, etay
            )
            # Verify some things
            self.assertTrue( issubclass(w[-1].category, RuntimeWarning) )
            self.assertEqual("The matrix is ill-conditioned or singular", str(w[-1].message))
示例#6
0
    def test_OCCA_GulfStream(self, atol=1e-8):
        """ Actual profiles in the Gulf Stream region 
             (@ 39.5N, 299.5E)
        """
        ###########
        # prepare parameters for Gulf Stream region in OCCA
        ###########
        z_u = np.array([
            5.00000000e+00, 1.50000000e+01, 2.50000000e+01, 3.50000000e+01,
            4.50000000e+01, 5.50000000e+01, 6.50000000e+01, 7.50050049e+01,
            8.50250015e+01, 9.50950012e+01, 1.05309998e+02, 1.15870003e+02,
            1.27150002e+02, 1.39739990e+02, 1.54470001e+02, 1.72399994e+02,
            1.94735001e+02, 2.22710007e+02, 2.57470001e+02, 2.99929993e+02,
            3.50679993e+02, 4.09929993e+02, 4.77470001e+02, 5.52710022e+02,
            6.34735046e+02, 7.22400024e+02, 8.14470093e+02, 9.09740112e+02,
            1.00715503e+03, 1.10590503e+03, 1.20553503e+03, 1.30620508e+03,
            1.40914990e+03, 1.51709497e+03, 1.63417480e+03, 1.76513477e+03,
            1.91414990e+03, 2.08403491e+03, 2.27622510e+03, 2.49125000e+03,
            2.72925000e+03, 2.99025000e+03, 3.27425000e+03, 3.58125000e+03,
            3.91125000e+03, 4.26425000e+03, 4.64025000e+03, 5.03925000e+03,
            5.46125000e+03, 5.90625000e+03
        ])
        z_N2 = -np.array([
            -10.00006115, -20.00006114, -30.00006113, -40.00006112,
            -50.0000611, -60.00006109, -70.00256358, -80.01506451,
            -90.06006328, -100.20256308, -110.5900682, -121.51007976,
            -133.44509256, -147.10512803, -163.43519352, -183.5678012,
            -208.72298023, -240.09073926, -278.70109317, -325.30655719,
            -380.30712264, -443.70276088, -515.09343642, -593.72659767,
            -678.57216844, -768.44015906, -862.11055267, -958.45325725,
            -1056.53586028, -1155.72595435, -1255.87608991, -1357.68378579,
            -1463.12934261, -1575.64299213, -1699.66489761, -1839.65538686,
            -1999.10931291, -2180.15155508, -2383.76440293, -2610.28273438,
            -2859.78914881, -3132.29607118, -3427.80347989, -3746.3113517,
            -4087.81966191, -4452.32838443, -4839.83749199, -5250.34695635,
            -5683.85674858
        ])
        ubar = np.array([
            0.24113144, 0.20566152, 0.18566666, 0.17763813, 0.17248898,
            0.16799432, 0.16402273, 0.16024273, 0.15672079, 0.1532983,
            0.15058691, 0.1480111, 0.14513075, 0.14221466, 0.13825534,
            0.13390785, 0.12829159, 0.12135932, 0.11275966, 0.10259634,
            0.09075638, 0.07769765, 0.06402871, 0.05062123, 0.0384005,
            0.02791209, 0.01922886, 0.01237531, 0.00755318, 0.00470483,
            0.00328818, 0.00261901, 0.00221545, 0.00182732, 0.0013118,
            0.00058111, -0.00035143, -0.0013624, -0.00230507, -0.00308389,
            -0.00365073, -0.00393951, -0.00386523, -0.00344036, -0.00277483,
            -0.00189117, -0.00060206, 0.00060187, np.nan, np.nan
        ])
        vbar = np.array([
            0.03732778, 0.03306238, 0.03844519, 0.04393799, 0.04580961,
            0.04673327, 0.04731352, 0.04768672, 0.04787091, 0.04791058,
            0.0476704, 0.04725287, 0.04666282, 0.04587267, 0.04479391,
            0.04350807, 0.04190299, 0.03983596, 0.03736874, 0.03421749,
            0.03057165, 0.02645037, 0.02181544, 0.01715759, 0.01278938,
            0.00886511, 0.00544434, 0.00260065, 0.00052863, -0.00065227,
            -0.00111283, -0.00120176, -0.00119863, -0.00122544, -0.00130761,
            -0.00143906, -0.00161413, -0.00183596, -0.00210659, -0.00240779,
            -0.002703, -0.00296008, -0.00314709, -0.00320451, -0.00309561,
            -0.0028392, -0.00253795, 0., np.nan, np.nan
        ])
        N2 = np.array([
            4.49013733e-05, 1.32619531e-04, 1.67213349e-04, 1.39980381e-04,
            1.08620176e-04, 8.89353316e-05, 7.59696940e-05, 6.85660114e-05,
            6.13053056e-05, 4.96623307e-05, 4.26153730e-05, 3.83933836e-05,
            3.33244718e-05, 3.14573673e-05, 2.74780120e-05, 2.50869570e-05,
            2.35907064e-05, 2.26047540e-05, 2.06309696e-05, 1.93499569e-05,
            1.85802260e-05, 1.73887368e-05, 1.49995125e-05, 1.25945779e-05,
            1.06210281e-05, 9.69791903e-06, 9.18845407e-06, 7.56655382e-06,
            5.00383224e-06, 2.83633215e-06, 1.67170878e-06, 1.19350982e-06,
            9.87252978e-07, 9.54096555e-07, 1.05979705e-06, 1.18957478e-06,
            1.23432375e-06, 1.22190029e-06, 1.20084648e-06, 1.18287498e-06,
            1.14801849e-06, 1.08643614e-06, 9.36511867e-07, 6.17342678e-07,
            3.35507108e-07, 3.19646379e-07, 2.60733349e-07, np.nan, np.nan
        ])
        Rd = 25787.38588424
        f0 = 9.27671062527e-05
        beta = 1.76637107718e-11
        Nx = 100
        dx = 4e3
        k = np.array([
            -1.88495559e-04, -1.72787596e-04, -1.57079633e-04, -1.41371669e-04,
            -1.25663706e-04, -1.09955743e-04, -9.42477796e-05, -7.85398163e-05,
            -6.28318531e-05, -4.71238898e-05, -3.14159265e-05, -1.57079633e-05
        ])
        l = np.array([0.])
        etax = np.zeros(2)
        etay = np.zeros(2)

        z, growth_rate, vertical_modes = \
            modes.instability_analysis_from_N2_profile(
                z_N2, N2, f0, beta, k, l,
                z_u, ubar, vbar, etax, etay, num=2
        )

        self.assertEqual(len(z),
                         vertical_modes.shape[0],
                         msg='modes array must be in the right shape')

        self.assertTrue(np.all(
            np.diff(
                growth_rate.reshape((growth_rate.shape[0], len(k) *
                                     len(l))).imag.max(axis=1)) <= 0.),
                        msg='imaginary part of modes should be descending')

        mode_amplitude1 = (np.absolute(vertical_modes[:, 0])**2).sum(axis=0)
        self.assertTrue(
            np.allclose(1., mode_amplitude1),
            msg=
            'mode1 should be normalized to amplitude of 1 at all horizontal wavenumber points'
        )

        mode_amplitude2 = (np.absolute(vertical_modes[:, 1])**2).sum(axis=0)
        self.assertTrue(
            np.allclose(1., mode_amplitude2),
            msg=
            'mode2 should be normalized to amplitude of 1 at all horizontal wavenumber points'
        )

        ##########
        # Row corresponding to l=0 of growth mode (Ah=0)
        ##########
        w_sol = np.array([
            1.04641026e-06, 8.55850224e-07, 6.56131690e-07, 4.40205651e-07,
            2.22218418e-07, 1.07589996e-07, 9.46591756e-08, 4.64407815e-08,
            1.29096295e-07, 6.74206451e-08, 5.74783413e-07, 6.86202530e-08
        ])

        self.assertTrue(
            np.allclose(growth_rate.imag[0, 0], w_sol, atol=atol),
            msg=
            'The OCCA numerical growth rates should be close to the solution with Ah=0'
        )

        z, growth_rate, vertical_modes = \
            modes.instability_analysis_from_N2_profile(
                z_N2, N2, f0, beta, k, l,
                z_u, ubar, vbar, etax, etay, Ah=1e1, num=2
        )

        ##########
        # Row corresponding to l=0 of growth mode (Ah=10.)
        ##########
        w_sol = np.array([
            3.15410778e-06, 2.82584613e-06, 2.47671069e-06, 2.10243465e-06,
            1.69802277e-06, 1.26121608e-06, 8.09682819e-07, 4.13752221e-07,
            1.43811161e-07, 7.84288795e-08, 5.93310629e-07, 6.33544320e-08
        ])

        self.assertTrue(
            np.allclose(growth_rate.imag[0, 0], w_sol, atol=atol),
            msg=
            'The OCCA numerical growth rates should be close to the solution with Ah=10'
        )
示例#7
0
    def test_Eady(self, atol=5e-2, nz=20, Ah=0.):
        """ Eady setup
        """
        ###########
        # prepare parameters for Eady
        ###########
        nz = nz
        zin = np.arange(nz + 1, dtype=np.float64) / nz
        N2 = np.full(nz, 1.)
        f0 = 1.
        beta = 0.
        Nx = 10
        Ny = 1
        dx = 1e-1
        dy = 1e-1
        k = fft.fftshift(fft.fftfreq(Nx, dx))
        l = fft.fftshift(fft.fftfreq(Ny, dy))
        vbar = np.zeros(nz + 1)
        ubar = zin
        etax = np.zeros(2)
        etay = np.zeros(2)

        z, growth_rate, vertical_modes = \
            modes.instability_analysis_from_N2_profile(
                .5*(zin[1:]+zin[:-1]), N2, f0, beta, k, l,
                zin, ubar, vbar, etax, etay, depth=1., sort='LI', num=2
        )

        self.assertEqual(nz + 1,
                         vertical_modes.shape[0],
                         msg='modes array must be in the right shape')

        self.assertTrue(np.all(
            np.diff(
                growth_rate.reshape((growth_rate.shape[0], len(k) *
                                     len(l))).imag.max(axis=1)) <= 0.),
                        msg='imaginary part of modes should be descending')

        mode_amplitude1 = (np.absolute(vertical_modes[:, 0])**2).sum(axis=0)
        self.assertTrue(
            np.allclose(1., mode_amplitude1),
            msg=
            'mode1 should be normalized to amplitude of 1 at all horizontal wavenumber points'
        )

        mode_amplitude2 = (np.absolute(vertical_modes[:, 1])**2).sum(axis=0)
        self.assertTrue(
            np.allclose(1., mode_amplitude2),
            msg=
            'mode2 should be normalized to amplitude of 1 at all horizontal wavenumber points'
        )

        #########
        # Analytical solution for Eady growth rate
        #########
        growthEady = np.zeros(len(k))
        for i in range(len(k)):
            if (k[i] == 0) or ((np.tanh(.5 * k[i])**-1 - .5 * k[i]) *
                               (.5 * k[i] - np.tanh(.5 * k[i])) < 0):
                growthEady[i] = 0.
            else:
                growthEady[i] = ubar.max() * np.sqrt(
                    (np.tanh(.5 * k[i])**-1 - .5 * k[i]) *
                    (.5 * k[i] - np.tanh(.5 * k[i])))

        self.assertTrue(
            np.allclose(growth_rate.imag[0, 0, :], growthEady, atol=atol),
            msg=
            'The numerical growth rates should be close to the analytical Eady solution'
        )
示例#8
0
    def test_linear_instability_args(self):
        nz = 10
        N2 = np.zeros(nz)
        depth = np.arange(nz)
        ubar = 1e-2 * np.ones(nz + 1)
        vbar = 1e-2 * np.ones(nz + 1)
        beta = 1e-6
        etax = np.array([1e-1 * beta, beta])
        etay = np.array([1e-1 * beta, beta])
        Nx = 1
        Ny = 1
        dx = .1
        dy = .1
        k = fft.fftshift(fft.fftfreq(Nx, dx))
        l = fft.fftshift(fft.fftfreq(Ny, dy))

        ###########
        # check for unequal lengths of arrays
        ###########
        with self.assertRaises(ValueError):
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth[1:], N2, 1., beta, k, l, depth, ubar, vbar, etax, etay)
        with self.assertRaises(ValueError):
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth, N2[1:], 1., beta, k, l, depth, ubar, vbar, etax, etay)

        with self.assertRaises(ValueError):
            _, _, _ = modes.instability_analysis_from_N2_profile(
                -depth, N2, 1., beta, k, l, np.append(depth, float(nz + 1)),
                ubar, vbar, etax, etay)

        with self.assertRaises(ValueError):
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth, N2[1:], 1., beta, k, l,
                -np.append(depth, float(nz + 1)), ubar, vbar, etax, etay)

        depth_non_monotonic = depth
        depth_non_monotonic[0] = 5
        depth_non_monotonic[1] = 5
        # check for non-monotonic profile
        Nx = 50
        Ny = 50
        dx = 1e-1
        dy = 1e-1
        k = fft.fftshift(fft.fftfreq(Nx, dx))
        l = fft.fftshift(fft.fftfreq(Ny, dy))
        with self.assertRaises(ValueError) as cm:
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth_non_monotonic[1:], N2, 1., beta, k, l, depth, ubar, vbar,
                etax, etay)

        N2 = np.append(N2, [1., 1.])  #N2 has longer length than u
        with self.assertRaises(ValueError):
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth, N2, 1., beta, k, l, depth, ubar, vbar, etax, etay)

        N2 = np.zeros(nz)
        depth = np.arange(nz + 1)
        ubar = np.zeros(nz + 1)
        vbar = np.zeros(nz + 1)
        etax = np.zeros(2)
        etay = np.zeros(2)
        beta = 0.
        with warnings.catch_warnings(record=True) as w:
            # Trigger a warning
            _, _, _ = modes.instability_analysis_from_N2_profile(
                depth[:-1], N2, 0., beta, k, l, depth, ubar, vbar, etax, etay)
            # Verify some things
            self.assertTrue(issubclass(w[-1].category, RuntimeWarning))
            self.assertEqual("The matrix is ill-conditioned or singular",
                             str(w[-1].message))