def test_rotate_gauss_fft(self): nmax = 2 kmax = 2 # load matfile test = load_matfile(MATFILE_PATH, 'test_rotate_gauss_fft') for reference in ['gsm', 'sm']: frequency, amplitude, _, _ = c.rotate_gauss_fft( nmax, kmax, step=1., N=int(365*24), filter=20, save_to=False, reference=reference, scaled=False) omega = 2*pi*frequency / (24*3600) # transpose and take complex conjugate (to match original output) omega_mat = \ test['omega_{:}'.format(reference)].transpose((2, 1, 0)) amplitude_mat = \ test['amplitude_{:}'.format(reference)].transpose((2, 1, 0)) amplitude_mat = amplitude_mat.conj() # absolute tolerance to account for close-to-zero matrix entries self.assertIsNone(np.testing.assert_allclose( omega_mat, omega, atol=1e-3)) self.assertIsNone(np.testing.assert_allclose( amplitude_mat, amplitude, atol=1e-10))
def test_q_response_sphere_pre7(self): a = 6371.2 n = 1 # load matfile test = load_matfile(MATFILE_PATH, 'test_conducting_sphere') C_n_mat = np.ravel(test['C_n']) rho_a_mat = np.ravel(test['rho_a']) phi_mat = np.ravel(test['phi']) Q_n_mat = np.ravel(test['Q_n']) model = np.loadtxt( os.path.join(ROOT, '../data/gsm_sm_coefficients', 'conductivity_Utada2003.dat')) radius = a - model[:, 0] # perfectly conducting core will automatically be removed sigma = model[:, 1] periods = np.logspace(np.log10(1/48), np.log10(365*24))*3600 C_n, rho_a, phi, Q_n = c.q_response_1D(periods, sigma, radius, n, kind='constant') self.assertIsNone(np.testing.assert_allclose(C_n, C_n_mat)) self.assertIsNone(np.testing.assert_allclose(rho_a, rho_a_mat)) self.assertIsNone(np.testing.assert_allclose(phi, phi_mat)) self.assertIsNone(np.testing.assert_allclose(Q_n, Q_n_mat))
def test_q_response_sphere(self): a = 6371.2 n = 1 # load matfile test = load_matfile(MATFILE_PATH, 'test_conducting_sphere_thinlayer') C_n_mat = np.ravel(test['C_n']) rho_a_mat = np.ravel(test['rho_a']) phi_mat = np.ravel(test['phi']) Q_n_mat = np.ravel(test['Q_n']) model = np.loadtxt(c.basicConfig['file.Earth_conductivity']) radius = a - model[:, 0] sigma = model[:, 1] periods = np.logspace(np.log10(1/48), np.log10(365*24))*3600 C_n, rho_a, phi, Q_n = c.q_response_1D( periods, sigma, radius, n, kind='quadratic') self.assertIsNone(np.testing.assert_allclose(C_n, C_n_mat)) self.assertIsNone(np.testing.assert_allclose(rho_a, rho_a_mat)) self.assertIsNone(np.testing.assert_allclose(phi, phi_mat)) self.assertIsNone(np.testing.assert_allclose(Q_n, Q_n_mat))
def test_sun_position(self): start = d.mjd2000(1910, 1, 1) end = d.mjd2000(2090, 12, 31) time = np.linspace(start, end, 100) theta, phi = c.sun_position(time) # load matfile test = load_matfile(MATFILE_PATH, 'test_sun_position') # reduce 2-D matrix to 1-D vectors theta_mat = np.ravel(test['theta']) phi_mat = np.ravel(test['phi']) self.assertIsNone(np.testing.assert_allclose(theta, theta_mat)) self.assertIsNone(np.testing.assert_allclose(phi, phi_mat)) # test position of sun close to zenith in Greenwich # (lat 51.48, lon -0.0077) on July 18, 2018, 12h06 (from # sunearthtools.com): time_gmt = d.mjd2000(2018, 7, 18, 12, 6) lat = 51.4825766 # geogr. latitude lon = -0.0076589 # geogr. longitude el = 59.59 # elevation above horizon az = 179.86 # angle measured from north (sun close to zenith) theta_gmt = 180. - (el + lat) # subsolar colat. given geogr. lat. phi_gmt = 180. + (lon - az) # subsolar phi given geogr. longitude theta, phi = c.sun_position(time_gmt) self.assertAlmostEqual(theta_gmt, theta, places=0) self.assertAlmostEqual(phi_gmt, phi, places=0)
def test_geo_to_gg(self): mat = load_matfile(MATFILE_PATH, 'test_geo_to_gg') height, beta = c.geo_to_gg(mat['radius'], mat['theta']) # self.assertIsNone(np.testing.assert_allclose(height, mat['height'])) self.assertIsNone(np.testing.assert_allclose(beta, mat['beta']))
def test_gg_to_geo(self): mat = load_matfile(MATFILE_PATH, 'test_gg_to_geo') radius, theta = c.gg_to_geo(mat['height'], mat['beta']) self.assertIsNone(np.testing.assert_allclose(radius, mat['radius'])) self.assertIsNone(np.testing.assert_allclose(theta, mat['theta']))
def test_synth_euler_angles(self): model = cp.load_CHAOS_matfile(CHAOS_PATH) test = load_matfile(MATFILE_PATH, 'test_synth_euler_angles') time = np.squeeze(test['time']) swarm_c = model.synth_euler_angles(time, 'swarm_c') self.assertIsNone(np.testing.assert_allclose(swarm_c, test['swarm_c']))
def test_gg_geo_gg(self): mat = load_matfile(MATFILE_PATH, 'test_gg_to_geo') radius, theta = c.gg_to_geo(mat['height'], mat['beta']) height, beta = c.geo_to_gg(radius, theta) self.assertIsNone( np.testing.assert_allclose(height, mat['height'], atol=1e-10)) self.assertIsNone( np.testing.assert_allclose(beta, mat['beta'], atol=1e-10))
def test_rotate_gauss(self): # test 1 time = 20 # random day nmax = 4 kmax = 2 s = timer() base_1, base_2, base_3 = c.basevectors_gsm(time) matrix = c.rotate_gauss(nmax, kmax, base_1, base_2, base_3) e = timer() # load matfile test = load_matfile(MATFILE_PATH, 'test_rotate_gauss') matrix_mat = test['m_all'].transpose() # transposed in Matlab code runtime = test['runtime'] print(" Time for matrix computation (Python): ", e - s) print(" Time for matrix computation (Matlab): {:}".format( runtime[0, 0])) # absolute tolerance to account for close-to-zero matrix entries self.assertIsNone(np.testing.assert_allclose( matrix, matrix_mat, atol=1e-8)) # test 2 # rotate around y-axis to have dipole axis aligned with x-axis base_1 = np.array([0, 0, -1]) base_2 = np.array([0, 1, 0]) base_3 = np.array([1, 0, 0]) nmax = 1 # only dipole terms kmax = 1 matrix = c.rotate_gauss(nmax, kmax, base_1, base_2, base_3) desired = np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]]) self.assertIsNone(np.testing.assert_allclose( matrix, desired, atol=1e-10)) # test 3 time = np.arange(9).reshape((3, 3)) # random day nmax = 4 kmax = 2 base_1, base_2, base_3 = c.basevectors_gsm(time) matrix = c.rotate_gauss(nmax, kmax, base_1, base_2, base_3) self.assertEqual(matrix.shape, (3, 3, 24, 8))
def test_design_matrix(self): """ Test matrices for time-dependent field model using B-spline basis. """ n_data = int(300) t_start = 1997.1 t_end = 2018.1 n_breaks = int((t_end - t_start) / 0.5 + 1) time = np.linspace(t_start, t_end, num=n_data) radius = R_REF * np.ones(time.shape) theta = np.linspace(1, 179, num=n_data) phi = np.linspace(-180, 179, num=n_data) n_static = int(80) n_tdep = int(20) order = int(6) # order of spline basis functions (4 = cubic) # create a knot vector without endpoint repeats and # add endpoint # repeats as appropriate for spline degree p knots = np.linspace(t_start, t_end, num=n_breaks) knots = m.augment_breaks(knots, order) s = timer() G_radius, G_theta, G_phi = m.design_matrix(knots, order, n_tdep, time, radius, theta, phi, n_static=n_static) e = timer() # load matfile test = load_matfile(MATFILE_PATH, 'test_design_matrix') G_radius_mat = test['G_radius'] G_theta_mat = test['G_theta'] G_phi_mat = test['G_phi'] runtime = test['runtime'] print(" Time for design_matrix computation (Python): ", e - s) print(" Time for design_matrix computation (Matlab): {:}".format( runtime[0, 0])) self.assertIsNone( np.testing.assert_allclose(G_radius, G_radius_mat, atol=1e-5)) self.assertIsNone( np.testing.assert_allclose(G_theta, G_theta_mat, atol=1e-5)) self.assertIsNone( np.testing.assert_allclose(G_phi, G_phi_mat, atol=1e-5))
def test_synth_gsm_field(self): # load matfile test = load_matfile(MATFILE_PATH, 'test_synth_gsm_field') model = load_CHAOS_matfile(CHAOS_PATH) N = int(1000) time = np.linspace(-1000, 6000, num=N) radius = R_REF theta = np.linspace(1, 179, num=N) phi = np.linspace(-180, 179, num=N) B_radius = np.zeros(time.shape) B_theta = np.zeros(time.shape) B_phi = np.zeros(time.shape) for source in ['internal', 'external']: B_radius_new, B_theta_new, B_phi_new = model.synth_values_gsm( time, radius, theta, phi, source=source) B_radius += B_radius_new B_theta += B_theta_new B_phi += B_phi_new B_radius_mat = np.ravel(test['B_radius']) B_theta_mat = np.ravel(test['B_theta']) B_phi_mat = np.ravel(test['B_phi']) for component in ['B_radius', 'B_theta', 'B_phi']: res = np.abs(eval(component) - eval('_'.join((component, 'mat')))) print(' -------------------') print(f' {component}:') print(' MAE =', np.mean(res), 'nT') print(' RMSE =', np.sqrt(np.mean(res**2)), 'nT') print(' Max Error =', np.amax(res), 'nT') print(' Min Error =', np.amin(res), 'nT') self.assertIsNone(np.testing.assert_allclose( B_radius, B_radius_mat, rtol=1e-2, atol=1e-2)) self.assertIsNone(np.testing.assert_allclose( B_theta, B_theta_mat, rtol=1e-2, atol=1e-2)) self.assertIsNone(np.testing.assert_allclose( B_phi, B_phi_mat, rtol=1e-2, atol=1e-2))
def test_geo_to_gsm(self): time = np.linspace(1, 100, 10) theta_geo = np.linspace(1, 179, 10) phi_geo = np.linspace(-180, 179, 10) # load matfile test = load_matfile(MATFILE_PATH, 'test_geo_to_gsm') # reduce 2-D matrix to 1-D vectors theta_gsm_mat = np.ravel(test['theta_gsm']) phi_gsm_mat = np.ravel(test['phi_gsm']) theta_gsm, phi_gsm = c.transform_points( theta_geo, phi_geo, time=time, reference='gsm') self.assertIsNone(np.testing.assert_allclose(theta_gsm, theta_gsm_mat)) self.assertIsNone(np.testing.assert_allclose(phi_gsm, phi_gsm_mat))
def test_rotate_gauss_coeffs(self): """ Compare GSM/SM rotation matrices synthezised from chaosmagpy and Matlab. """ for reference in ['GSM', 'SM']: print(f' Testing {reference} frame of reference.') # load spectrum to synthesize matrices in time-domain filepath = c.basicConfig[f'file.{reference}_spectrum'] try: data = np.load(filepath) except FileNotFoundError as e: raise ValueError( f'{reference} file not found in "chaosmagpy/lib/".' ' Correct reference?') from e data_mat = load_matfile(MATFILE_PATH, 'test_rotate_gauss_coeffs') time = 10 * 365.25 * np.random.random_sample((30, )) for freq, spec in zip(['frequency', 'frequency_ind'], ['spectrum', 'spectrum_ind']): matrix = c.synth_rotate_gauss(time, data[freq], data[spec], scaled=True) matrix_mat = c.synth_rotate_gauss( time, data_mat[reference + '_' + freq], data_mat[reference + '_' + spec], scaled=True) self.assertIsNone( np.testing.assert_allclose(matrix, matrix_mat, atol=1e-3))
def test_colloc_matrix(self): breaks = np.linspace(0., 300., 20) order = 6 knots = m.augment_breaks(breaks, order) x = np.linspace(0., 300., 1000) test = load_matfile(MATFILE_PATH, 'test_colloc_matrix') colloc_m = test['colloc'] for deriv in range(order): print(f"Checking deriv = {deriv} of collocation matrix.") colloc = m.colloc_matrix(x, knots, order, deriv=deriv) self.assertIsNone( np.testing.assert_allclose(colloc, colloc_m[deriv::order], atol=1e-5))
def test_surface_field(self): model = cp.load_CHAOS_matfile(CHAOS_PATH) time = 2015. radius = R_REF theta = np.linspace(1, 179, num=180) phi = np.linspace(-180, 179, num=360) B_radius, B_theta, B_phi = model.synth_values_tdep(time, radius, theta, phi, nmax=13, grid=True, deriv=0) B_radius = np.ravel(B_radius, order='F') # ravel column-major B_theta = np.ravel(B_theta, order='F') B_phi = np.ravel(B_phi, order='F') # load matfile test = load_matfile(MATFILE_PATH, 'test_surface_field') B_radius_mat = np.ravel(test['B_radius']) B_theta_mat = np.ravel(test['B_theta']) B_phi_mat = np.ravel(test['B_phi']) for component in ['B_radius', 'B_theta', 'B_phi']: res = np.abs(eval(component) - eval('_'.join((component, 'mat')))) print(' -------------------') print(f' {component}:') print(' MAE =', np.mean(res), 'nT') print(' RMSE =', np.sqrt(np.mean(res**2)), 'nT') print(' Max Error =', np.amax(res), 'nT') print(' Min Error =', np.amin(res), 'nT') self.assertIsNone(np.testing.assert_allclose(B_radius, B_radius_mat)) self.assertIsNone(np.testing.assert_allclose(B_theta, B_theta_mat)) self.assertIsNone(np.testing.assert_allclose(B_phi, B_phi_mat))
def test_sv_timeseries(self): # some observatory location radius = R_REF theta = 90 - 14.308 phi = -16.950 model = cp.load_CHAOS_matfile(CHAOS_PATH) time = np.linspace(model.model_tdep.breaks[0], model.model_tdep.breaks[-1], num=1000) B_radius, B_theta, B_phi = model.synth_values_tdep(time, radius, theta, phi, nmax=16, deriv=1) # load matfile test = load_matfile(MATFILE_PATH, 'test_sv_timeseries') B_radius_mat = np.ravel(test['B_radius']) B_theta_mat = np.ravel(test['B_theta']) B_phi_mat = np.ravel(test['B_phi']) for component in ['B_radius', 'B_theta', 'B_phi']: res = np.abs(eval(component) - eval('_'.join((component, 'mat')))) print(' -------------------') print(f' {component}:') print(' MAE =', np.mean(res), 'nT') print(' RMSE =', np.sqrt(np.mean(res**2)), 'nT') print(' Max Error =', np.amax(res), 'nT') print(' Min Error =', np.amin(res), 'nT') self.assertIsNone(np.testing.assert_allclose(B_radius, B_radius_mat)) self.assertIsNone(np.testing.assert_allclose(B_theta, B_theta_mat)) self.assertIsNone(np.testing.assert_allclose(B_phi, B_phi_mat))
def test_complete_forward(self): n_data = int(300) t_start = -200.0 t_end = 6000.0 time = np.linspace(t_start, t_end, num=n_data) radius = R_REF * np.ones(time.shape) theta = np.linspace(1, 179, num=n_data) phi = np.linspace(-180, 179, num=n_data) model = load_CHAOS_matfile(CHAOS_PATH) B_radius, B_theta, B_phi = model(time, radius, theta, phi) # load matfile test = load_matfile(MATFILE_PATH, 'test_complete_forward') B_radius_mat = np.ravel(test['B_radius']) B_theta_mat = np.ravel(test['B_theta']) B_phi_mat = np.ravel(test['B_phi']) for component in ['B_radius', 'B_theta', 'B_phi']: res = np.abs(eval(component) - eval('_'.join((component, 'mat')))) print(' -------------------') print(f' {component}:') print(' MAE =', np.mean(res), 'nT') print(' RMSE =', np.sqrt(np.mean(res**2)), 'nT') print(' Max Error =', np.amax(res), 'nT') print(' Min Error =', np.amin(res), 'nT') self.assertIsNone(np.testing.assert_allclose( B_radius, B_radius_mat, rtol=1e-7, atol=1e-2)) self.assertIsNone(np.testing.assert_allclose( B_theta, B_theta_mat, rtol=1e-7, atol=1e-2)) self.assertIsNone(np.testing.assert_allclose( B_phi, B_phi_mat, rtol=1e-7, atol=1e-2))
def test_geo_to_base(self): time = np.linspace(1, 100, 10) theta_geo = np.linspace(1, 179, 10) phi_geo = np.linspace(-180, 179, 10) # TEST GSM COORDINATES # GSM test: load matfile test = load_matfile(MATFILE_PATH, 'test_geo_to_gsm') # reduce 2-D matrix to 1-D vectors theta_gsm_mat = np.ravel(test['theta_gsm']) phi_gsm_mat = np.ravel(test['phi_gsm']) gsm_1, gsm_2, gsm_3 = c.basevectors_gsm(time) theta_gsm, phi_gsm = c.geo_to_base( theta_geo, phi_geo, gsm_1, gsm_2, gsm_3) self.assertIsNone(np.testing.assert_allclose(theta_gsm, theta_gsm_mat)) self.assertIsNone(np.testing.assert_allclose(phi_gsm, phi_gsm_mat)) # test the inverse option: GEO -> GSM -> GEO theta_geo2, phi_geo2 = c.geo_to_base( theta_gsm, phi_gsm, gsm_1, gsm_2, gsm_3, inverse=True) self.assertIsNone(np.testing.assert_allclose(theta_geo, theta_geo2)) self.assertIsNone(np.testing.assert_allclose( phi_geo, c.center_azimuth(phi_geo2))) # test the inverse option: GSM -> GEO -> GSM theta_gsm2, phi_gsm2 = c.geo_to_base( theta_geo2, phi_geo2, gsm_1, gsm_2, gsm_3) self.assertIsNone(np.testing.assert_allclose(theta_gsm, theta_gsm2)) self.assertIsNone(np.testing.assert_allclose( c.center_azimuth(phi_gsm), c.center_azimuth(phi_gsm2))) # TEST SM COORDINATES # SM test: load matfile test = load_matfile(MATFILE_PATH, 'test_geo_to_sm') # reduce 2-D matrix to 1-D vectors theta_sm_mat = np.ravel(test['theta_sm']) phi_sm_mat = np.ravel(test['phi_sm']) sm_1, sm_2, sm_3 = c.basevectors_sm(time) theta_sm, phi_sm = c.geo_to_base( theta_geo, phi_geo, sm_1, sm_2, sm_3) self.assertIsNone(np.testing.assert_allclose(theta_sm, theta_sm_mat)) self.assertIsNone(np.testing.assert_allclose(phi_sm, phi_sm_mat)) # test the inverse option: GEO -> SM -> GEO theta_geo2, phi_geo2 = c.geo_to_base( theta_sm, phi_sm, sm_1, sm_2, sm_3, inverse=True) self.assertIsNone(np.testing.assert_allclose(theta_geo, theta_geo2)) self.assertIsNone(np.testing.assert_allclose(phi_geo, phi_geo2)) # test the inverse option: SM -> GEO -> SM theta_sm2, phi_sm2 = c.geo_to_base( theta_geo2, phi_geo2, sm_1, sm_2, sm_3) self.assertIsNone(np.testing.assert_allclose(theta_sm, theta_sm2)) self.assertIsNone(np.testing.assert_allclose(phi_sm, phi_sm2))