This tutorial demonstrates how to analyse global data on the sphere using spherical harmonic functions. In contrast to the two Introductory notebooks that make use of the pyshtools classes
SHGrid, these examples will instead make use of the fortran wrapped functions.
%matplotlib inline from __future__ import print_function # only necessary if using Python 2.x import matplotlib.pyplot as plt import numpy as np from pyshtools.shio.shread import shread from pyshtools.expand import MakeGridDH from pyshtools.expand import SHExpandDH from pyshtools.spectralanalysis import spectrum
In this example, we will use the topography of Earth that is provided in the example directory.
infile = '../ExampleDataFiles/srtmp300.msl' clm, lmax = shread(infile) topo = MakeGridDH(clm, sampling=2) fig, ax = plt.subplots(1, 1, figsize=(10, 10)) ax.imshow(topo, extent=(0, 360, -90, 90), cmap='viridis') ax.set(xlabel='longitude', ylabel='latitude');
Using the grid
topo, we will first demonstrate how to calculate the power spectrum, and second, how to perform simple filtering operations.
The power spectrum of a function describes how the variance of the function is distributed as a function of spherical harmonic degree. Concentration of power (or energy) in spherical harmonics with a particular wavelength can give hints about the origin of the feature. First, let's expand the gridded data into spherical harmonics:
coeffs = SHExpandDH(topo, sampling=2) nl = coeffs.shape ls = np.arange(nl)
The "power spectrum" can be calculated using different conventions. The default in pyshtools is to calculate the total power of all angular orders as a function of spherical harmonic degee, which corresponds to the option
unit='per_l'. The power per degree l is somewhat equivalent to the power at a given wavenumber magnitude |k| in 2D Fourier analyses.
power_per_l = spectrum(coeffs) fig, ax = plt.subplots(1, 1, figsize=(10, 5)) ax.plot(ls, power_per_l) ax.set_yscale('log') ax.set_xscale('log') ax.grid()
The average power per coefficient as a function of spherical harmonic degree can be calculated by setting the parameter
unit equal to
'per_lm'. This is simply the power per degree divided by (2l+1), and is analogous to the power per wavenumber kx and ky in 2D Fourier analyses.
power_per_lm = spectrum(coeffs, unit='per_lm') fig, ax = plt.subplots(1, 1, figsize=(10, 5)) ax.plot(ls, power_per_lm) ax.set_yscale('log') ax.set_xscale('log') ax.grid()
Finally, the contribution to the total power from all angular orders over an infinitessimal logarithmic degree band
dlog_a(l) can be calculated by setting
unit='per_dlogl'. In this case, the contrubution in the band
spectrum(l, 'per_dlogl')*dlog_a(l), where
a is the base, and where
spectrum(l, 'per_dlogl) is equal to
spectrum(l, 'per_l')*l*log(a). This power spectrum is useful to analyse dominant scales.
power_per_dlogl = spectrum(coeffs, unit='per_dlogl', base=2.) fig, ax = plt.subplots(1, 1, figsize=(10, 5)) ax.plot(ls, power_per_dlogl) ax.set_yscale('log', basey=2) ax.set_xscale('log', basex=2) ax.grid()
A global dataset can be filtered isostropically by multiplying the spherical harmonic coefficients by a degree-dependent function. We demonstrate this by setting the coefficients greater or equal to degree 8 equal to zero.
coeffs_filtered = coeffs.copy() lmax = 8 coeffs_filtered[:, lmax:, :] = 0. topo_filtered = MakeGridDH(coeffs_filtered, sampling=2)
Next, we bandpass filter the data to retain only spherical harmonic coefficients between 8 <= l < 20.
coeffs_filtered2 = coeffs.copy() lmin, lmax = 8, 20 coeffs_filtered2[:, :lmin, :] = 0. coeffs_filtered2[:, lmax:, :] = 0. topo_filtered2 = MakeGridDH(coeffs_filtered2, sampling=2)
Finally, let's plot the two filtered data sets:
fig, (row1, row2) = plt.subplots(2, 1, figsize=(10, 10)) row1.imshow(topo_filtered, extent=(0, 360, -90, 90), cmap='viridis') row1.set(xlabel='longitude', ylabel='latitude', title='l = 0 - 7'); row2.imshow(topo_filtered2, extent=(0, 360, -90, 90), cmap='viridis') row2.set(xlabel='longitude', ylabel='latitude', title='l = 8 - 19');