Show the code
import sympy as sp
from sympy import pi
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sympy as sp
from sympy import pi
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
In this notebook we demonstrate how to model the Earth’s density as piecewise quadratic functions, such that \[ \rho(r) = a_i r^{2} + b_i r + c_i, \quad r_{i-1}<r \le r_{i} \] for any shell enclosed by the radii \(r_{i-1}\) and \(r_i\), \(i=1,2,\dots,11\).
The coefficients \(a_i, b_i, c_i\) as well as the layer boundaries \(r_i\) have been published by Dziewonski & Anderson (1981).
The following Python
code reads the content of the file PREM.csv
into memory.
= pd.read_csv('PREM.csv',
df =',',
sep=0,
header=[1],
skiprows=['i', 'layer', 'height', 'a', 'b', 'c']) names
= df['height'].to_numpy()
h = df['a'].to_numpy()
an = df['b'].to_numpy()
bn = df['c'].to_numpy() cn
We define a function rho(r,a,b,c)
which evaluates for any \(r\) a second order polynomial with the given coefficients \(a,b,c\):
= lambda r, a, b, c: a * r**2 + b * r + c
rho = 6.371e6
R_E
= np.linspace(0, R_E, 501)
rr # Initialize myrho with zeros
= np.zeros(len(rr))
myrho
for i in range(len(rr)):
# Find the first index where rr[i] < h
= np.where(rr[i] < h)[0]
ii if ii.size > 0:
= ii[0] # Get the first index where the condition is met
first_index # Ensure rr[i], an[first_index], bn[first_index], and cn[first_index] are scalars
= rho(float(rr[i]), float(an[first_index]), float(bn[first_index]), float(cn[first_index]))
myrho[i]
# Set the last element as in MATLAB
-1] = rho(float(R_E), float(an[10]), float(bn[10]), float(cn[10]))
myrho[
= plt.subplots(figsize=(6,4))
fig, ax / 1000, myrho / 1000)
plt.plot(rr True)
plt.grid(/ 1000, 1, 14, color='r', linewidth=0.2)
plt.vlines(h 1, 14)
plt.ylim('PREM density profile')
plt.title('km')
plt.xlabel('density'); plt.ylabel(
The total mass of the Earth results from \[ m_E = 4 \pi \int\limits_0^{R_E} \rho(r) r^2 \, \mathrm dr. \]
However, there are density discontinuities which require a split of the integral at the jumps of \(\rho(r)\). We integrate layer-wise, such that the mass of layer \(i\) is obtained by \[
m_i = 4 \pi \int_{r_{i-1}}^{r_i} \rho(r) r^2 \, \mathrm d r ,\quad 1 \le i \le 11.
\] We use Python
’s Sympy
library.
= sp.symbols('a b c r h_1 h_2', real=True) a, b, c, r, h_1, h_2
We denote with i1 the following lambda function which is equivalent to the evaluation of the integral \[ 4 \pi \int_{h_1}^{h_2} (a r^2 + b r + c) r^2 \, \mathrm d r \]
= lambda h_1, h_2: 4 * pi * sp.integrate((a * r**2 + b * r + c) * r**2, (r, h_1, h_2))
i1
= np.zeros(len(an))
mass 0] = i1(0, h[0]).subs(a, an[0]).subs(b, bn[0]).subs(c, cn[0]).subs(pi, np.pi)
mass[
for i in range(1, 11):
= i1(h[i-1], h[i]).subs(a, an[i]).subs(b, bn[i]).subs(c, cn[i]).subs(pi, np.pi)
mass[i]
mass
= np.sum(mass)
M_Earth print('The mass of the Earth is:')
print(M_Earth)
The mass of the Earth is:
5.972734577607561e+24
= plt.subplots(figsize=(6,4))
fig, ax 0], h)) / 1e3, np.concatenate(([0], np.cumsum(mass))) / 1e24)
plt.plot(np.concatenate(([/ 1000, 0, 6.1, color='k', linewidth=0.2)
plt.vlines(h -0.2, 6.1)
plt.ylim('Earth\'s accumulated mass profile')
plt.title('km')
plt.xlabel(r'Mass in 10$^{24}$ kg')
plt.ylabel(True); plt.grid(
# Constants and assumptions
= 6.6743e-11 # Gravitational constant
G = np.zeros(len(rr)) # Initialize myg as a zero array of the same length as rr
myg
# Loop through each element in rr
for i in range(1,len(rr)):
# Find the first index where rr[i] < h
= np.where(rr[i] < h)[0]
ii if ii.size > 0:
= ii[0] + 1 # Adjusting for MATLAB's 1-based indexing
ii
# Condition where ii == 1
if ii == 1:
= i1(0, rr[i]).subs([(a, an[0]), (b, bn[0]), (c, cn[0])])
M
# Condition where ii > 1
elif ii > 1:
# Calculating M as the sum of mass up to ii-1 plus the substituted function value
= np.sum(mass[:ii-1]) + i1(h[ii-2], rr[i]).subs([(a, an[ii-1]), (b, bn[ii-1]), (c, cn[ii-1])])
M
# Calculate myg[i] using the gravitational constant
= G / rr[i]**2 * M
myg[i]
# Set boundary conditions as in MATLAB
0] = 0.0
myg[-1] = G / R_E**2 * M_Earth myg[
= np.linspace(R_E, 2*R_E, 41)
rext = plt.subplots(figsize=(6,4))
fig, ax / R_E, myg, color='b')
plt.plot(rr / R_E, G * M_Earth / rext**2, color='r')
plt.plot(rext 0, 1, facecolor='g', alpha=0.2)
plt.axvspan(/ R_E, 0, 12, color='k', linewidth=0.2)
plt.vlines(h 'Acceleration profile')
plt.title('Earth radii')
plt.xlabel(r'g in m$\cdot s^{-2}$')
plt.ylabel(0, 12)
plt.ylim(True) plt.grid(
The results above do not agree well with the true surface acceleration due to the Earth’s ellipsoidal shape. The WGS84 gravity formula is valid for points at the Earth’s surface and accounts for the change of acceleration due to the ellipticity:
= 9.7803253359
g_equator = 9.8321849378
g_pole = 6378137.0
semi_axis_major = 6356752.3142
semi_axis_minor = np.sqrt(1 - semi_axis_minor**2 / semi_axis_major**2)
ecc = semi_axis_minor / semi_axis_major * g_pole / g_equator - 1.0
k
= lambda phi: g_equator * (1 + k * np.sin(phi * np.pi / 180)**2) / np.sqrt(1 - ecc**2 * np.sin(phi * np.pi / 180)**2)
g_WGS
= np.linspace(-90, 90, 101)
lat = plt.subplots(figsize=(6,4))
fig, ax for v in lat], label='WGS')
plt.plot(lat, [g_WGS(v) =myg[-1], color='r', label='PREM')
plt.axhline(yTrue)
plt.grid('g')
plt.ylabel('Latitude in degrees')
plt.xlabel(; plt.legend()