Examples#
Note
In order to access the example files, it is necessary to download or clone the ctplanet repo from GitHub. The files are located in the examples
directory.
Moon#
Moon-Crust.py
#!/usr/bin/env python3
"""
Moon-Crust
Create a crustal thickness map of the Moon from gravity and topography.
This script generates two different crustal thickness maps. The first assumes
that the density of both the crust and mantle are constant, whereas the second
includes the effect of lateral variations in crustal density. This script can
be used to reproduce the results presented in Wieczorek et al. (2013).
Wieczorek, M. A., G. A. Neumann, F. Nimmo, W. S. Kiefer, G. J. Taylor,
H. J. Melosh, R. J. Phillips, S. C. Solomon, J. C. Andrews-Hanna,
S. W. Asmar, A. S. Konopliv, F. G. Lemoine, D. E. Smith, M. M. Watkins,
J. G. Williams, M. T. Zuber (2013), The crust of the Moon as seen by GRAIL,
Science, 339, 671-675, doi:10.1126/science.1231530, 2013.
"""
import os
import pyshtools as pysh
from ctplanet import pyMoho
from ctplanet import pyMohoRho
# ==== MAIN FUNCTION ====
def main():
lmax = 900 # determines spatial resolution of grids
lmax_calc = 600 # maximum degree to use in calculations
densityfile = 'Data/density_no_mare_n3000_f3050_719.sh'
pot = pysh.datasets.Moon.GRGM900C()
try:
os.mkdir('figs')
except Exception:
pass
print('Gravity file = {:s}'.format('GRGM900C'))
print('Lmax of potential coefficients = {:d}'.format(pot.lmax))
print('Reference radius (m) = {:e}'.format(pot.r0))
print('GM = {:e}\n'.format(pot.gm))
topo = pysh.datasets.Moon.LDEM_shape_pa(lmax=lmax)
topo.r0 = topo.coeffs[0, 0, 0]
print('Topography file = {:s}'.format('LDEM_shape_pa'))
print('Lmax of topography coefficients = {:d}'.format(topo.lmax))
print('Reference radius (m) = {:e}\n'.format(topo.r0))
density = pysh.SHCoeffs.from_file(densityfile, lmax=719)
rho_c0 = density.coeffs[0, 0, 0] # average grain density
print('Average grain density of crust (kg/m3) = {:e}'.format(rho_c0))
print('Lmax of density coefficients = {:d}\n'.format(density.lmax))
a_12_14_lat = -3.3450
a_12_14_long = -20.450
# Parameters corresponding to model 1 of Wieczorek et al. (2013),
# with the exception that the average thickness has been increased by 1 km.
thickave = 35.e3
porosity = 0.12
rho_m = 3220.0
filter = 1
half = 80
print('Average thickness of the crust (km) = {:e}'.format(thickave / 1.e3))
print('Porosity (%)= {:e}'.format(porosity * 100))
print('Mantle density (kg/m3)= {:e}'.format(rho_m))
# Constant density model
print('\n=== Constant density crust ===')
rho_c = rho_c0 * (1. - porosity) # assumed constant density
print('Bulk density of the crust(kg/m3)= {:e}'.format(rho_c * 100))
moho = pyMoho(pot, topo, lmax, rho_c, rho_m, thickave,
filter_type=filter, half=half, lmax_calc=lmax_calc,
quiet=False, delta_max=50.)
thick_grid = (topo.pad(lmax) - moho.pad(lmax)).expand(grid='DH2') / 1.e3
thick_grid.plot(show=False, colorbar='bottom',
cb_label='Crustal thickness, km',
fname='figs/Thick-Moon-1.png')
moho.plot_spectrum(show=False, fname='figs/Moho-spectrum-Moon-1.png')
print('Crustal thickness at Apollo 12/14 landing sites (km) = {:e}'
.format((topo.pad(lmax) - moho.pad(lmax))
.expand(lat=a_12_14_lat, lon=a_12_14_long) / 1.e3))
# Model with variable density
print('\n=== Variable density crust ===')
moho = pyMohoRho(pot, topo, density, porosity, lmax, rho_m,
thickave, filter_type=filter, half=half,
lmax_calc=lmax_calc, quiet=False, delta_max=50.)
thick_grid = (topo-moho.pad(topo.lmax)).expand(grid='DH2') / 1.e3
thick_grid.plot(show=False, colorbar='bottom',
cb_label='Crustal thickness, km',
fname='figs/Thick-Moon-2.png')
moho.plot_spectrum(show=False, fname='figs/Moho-spectrum-Moon-2.png')
print('Crustal thickness at Apollo 12/14 landing sites (km) = {:e}'.format(
(topo-moho.pad(topo.lmax)).expand(lat=a_12_14_lat,
lon=a_12_14_long) / 1.e3))
# ==== EXECUTE SCRIPT ====
if __name__ == "__main__":
main()
A script that demonstrates how to calculate the thickness of the lunar crust using either a constant or variable density crust. The latter can be used to reproduce the results presented in Wieczorek et al. (2013).
Moon-Core.py
#!/usr/bin/env python3
"""
Moon-Core
Calculate the hydrostatic shape of the core of the Moon, as presented in
Wieczorek et al. (2019).
"""
import os
import numpy as np
import pyshtools as pysh
from ctplanet import HydrostaticShapeLith
from ctplanet import HydrostaticShape
from ctplanet import InertiaTensor_from_shape
# ==== MAIN FUNCTION ====
def main():
lmax = 20
lmax_grid = 719
omega = pysh.constants.Moon.angular_velocity.value
rem = pysh.constants.Moon.orbit_semimajor_axis.value
mass_earth = pysh.constants.Earth.egm2008.mass.value
cthick = 34.e3 # 43.e3 or 34.0e3
rho_crust = 2550.
try:
os.mkdir('figs')
except Exception:
pass
out_rc_fc = "figs/rc_fc_34_2550.dat"
out_rc_rhoc = "figs/rc_rhoc_34_2550.dat"
out_rc_beta = "figs/rc_beta_34_2550.dat"
sh_core = "figs/core_34.sh"
sh_core_fluid = "figs/core_fluid_34.sh"
core_shape_wo_d1 = "figs/core_shape_wo_d1_330_34.dat"
core_shape = "figs/core_shape_330_34.dat"
rcore_int = 1.e3
rcore_start = 250.e3
rcore_end = 450.e3
rhocore_start = 5000.
rhocore_end = 8000.
rhocore_int = 1.
potential = pysh.datasets.Moon.GRGM900C()
topo = pysh.datasets.Moon.LDEM_shape_pa(lmax=900)
r0 = topo.coeffs[0, 0, 0]
r_sigma = r0 - cthick
ismr2 = 0.3927280 # Williams et al. (2014)
ismr2 = ismr2 * (1738.e3 / r0)**2
print("Mean planetary radius (km) = {:e}".format(r0 / 1.e3))
print("Is/MR2 (solid Moon using mean radius) = {:e}".format(ismr2))
print("Lmax of Gravitational potential = {:d}".format(potential.lmax))
print("Reference radius of potential model (km) = {:e}"
.format(potential.r0/1.e3))
print("GM = {:e}".format(potential.gm))
mass = potential.gm / pysh.constants.G.value
print("Mass (kg) = {:e}".format(mass))
print("Omega = {:e}".format(omega))
print("Period (days) = {:e}".format(2. * np.pi / omega / 60. / 60. / 24.))
print("Average crustal thickness (km) = {:e}".format(cthick / 1.e3))
print("Crustal density (kg/m3) = {:e}".format(rho_crust))
radius = np.zeros(4)
radius[0] = 0.
radius[2] = r0 - cthick
radius[3] = r0
rho = np.zeros(4)
rho[2] = rho_crust
mass_crust = 4. * np.pi / 3. * rho_crust * (radius[3]**3 - radius[2]**3)
n = 3
i_lith = 2
i_core = 1
# For each core radius, find rho_mantle and rho_core that fit total mass
# and moment of inertia
f_rc_fc = open(out_rc_fc, 'w')
f_rc_rhoc = open(out_rc_rhoc, 'w')
f_rc_beta = open(out_rc_beta, 'w')
for r_core in np.arange(rcore_start, rcore_end + rcore_int, rcore_int,
dtype=float):
radius[1] = r_core
first = True
for rho_core in np.arange(rhocore_start, rhocore_end + rhocore_int,
rhocore_int, dtype=float):
mass_core = 4. * np.pi / 3. * rho_core * r_core**3
mass_mantle = mass - mass_crust - mass_core
rho_mantle = mass_mantle * 3. / np.pi / 4. / (radius[2]**3 -
r_core**3)
rho[0] = rho_core
rho[1] = rho_mantle
if rho_mantle >= rho_core:
continue
ismr2_model = moi_solid(radius, rho, n)
if first is True:
diff_old = ismr2 - ismr2_model
first = False
else:
diff_new = ismr2 - ismr2_model
if diff_new * diff_old <= 0.:
# interpolate to get the best fitting core density
rho_core_final = (rho_core - rhocore_int) - diff_old * \
(rhocore_int) / (diff_new - diff_old)
rho[0] = rho_core_final
mass_core = 4. * np.pi / 3. * rho[0] * r_core**3
mass_mantle = mass - mass_crust - mass_core
rho_mantle = mass_mantle * 3. / np.pi / 4. / \
(radius[2]**3 - r_core**3)
rho[1] = rho_mantle
hlm, clm_hydro, mass_model = \
HydrostaticShapeLith(radius, rho, i_lith,
potential, topo, rho_crust,
r_sigma, omega, lmax,
rp=rem, mp=mass_earth)
# set degree-1 terms to zero
hlm[1].coeffs[:, 1, :] = 0.
a = hlm[1].expand(lat=0., lon=0., lmax_calc=lmax)
b = hlm[1].expand(lat=0., lon=90., lmax_calc=lmax)
c = hlm[1].expand(lat=90., lon=0., lmax_calc=lmax)
f_core = ((a+b)/2. - c) / ((a + b) / 2.)
beta_core = (a**2 - b**2) / (a**2 + b**2)
print(r_core/1.e3, rho[0], rho[1], f_core, beta_core)
f_rc_fc.write('{:e}, {:e}\n'.format(r_core/1.e3, f_core))
f_rc_rhoc.write('{:e}, {:e}\n'.format(r_core/1.e3, rho[0]))
f_rc_beta.write('{:e}, {:e}\n'
.format(r_core/1.e3, beta_core))
if r_core == 330.e3:
print("Rcore (km) = {:e}".format(r_core/1.e3))
print("A (km) = {:e}".format(a/1.e3))
print("B (km) = {:e}".format(b/1.e3))
print("C (km) = {:e}".format(c/1.e3))
print("rho_core (kg/m3) = {:e}".format(rho[0]))
II, AA, BB, CC, mass_model, RR, vec = \
InertiaTensor_from_shape(hlm, rho, 1, quiet=False)
grid = hlm[i_core].expand(lmax=lmax_grid, grid='DH2')
grid.to_file(core_shape_wo_d1)
print("Size of output grid = {:d}, {:d}"
.format(grid.nlat, grid.nlon))
print("Maximum = {:e}\nMinimum = {:e}"
.format(grid.max(), grid.min()))
hlm, clm_hydro, mass_model = \
HydrostaticShapeLith(radius, rho, i_lith,
potential, topo, rho_crust,
r_sigma, omega, lmax,
rp=rem, mp=mass_earth)
hlm_fluid, clm_fluid, mass_model = \
HydrostaticShape(radius, rho, omega, potential.gm,
potential.r0,
rp=rem, mp=mass_earth)
grid = hlm[i_core].expand(lmax=lmax_grid, grid='DH2')
grid_fluid = hlm_fluid[i_core].expand(lmax=lmax_grid,
grid='DH2')
a_fluid = hlm_fluid[1].expand(lat=0., lon=0.)
b_fluid = hlm_fluid[1].expand(lat=0., lon=90.)
c_fluid = hlm_fluid[1].expand(lat=90., lon=0.)
grid_fluid_surface = hlm_fluid[3].expand(
lmax=lmax_grid, grid='DH2')
print("Surface relief: Maximum = {:}, Minimum = {:}"
.format(grid_fluid_surface.max(),
grid_fluid_surface.min()))
f_core_fluid = (((a_fluid+b_fluid)/2. - c_fluid)
/ ((a_fluid + b_fluid) / 2.))
beta_core_fluid = ((a_fluid**2 - b_fluid**2) /
(a_fluid**2 + b_fluid**2))
print('f_core for a fluid planet = ', f_core_fluid)
print('beta_core for a fluid planet = ',
beta_core_fluid)
diff = grid - grid_fluid
print('Maximuim and miniumum core relief for '
'a fluid planet (m) = ',
grid_fluid.max(), grid_fluid.min())
print('Maximuim and miniumum difference with respect '
'to a fluid planet (m) = ',
diff.max(), diff.min())
hlm[i_core].to_file(sh_core)
hlm_fluid[i_core].to_file(sh_core_fluid)
grid.to_file(core_shape)
print("Maximum = {:e}\nMinimum = {:e}"
.format(grid.max(), grid.min()))
for l in range(0, 4):
for m in range(0, l+1):
print(l, m, hlm[i_core].coeffs[0, l, m],
hlm[i_core].coeffs[1, l, m])
diff_old = diff_new
def moi_solid(radius, rho, n):
"""
Calculate the mean, normalized, moment of inertia of the solid portion
of the planet.
The radius and density are discretized into shells as in the hydrostatic
flattening routines:
radius[0] = 0
radius[1] = radius of core
radius[n] = surface
rho[i] = density from radius[i] to radius[i+1]
"""
moi_solid = 0.
mass = 4. * np.pi / 3. * rho[0] * radius[1]**3
for i in range(2, n+1):
mass += 4. * np.pi / 3. * rho[i-1] * (radius[i]**3 - radius[i-1]**3)
moi_solid += 8. * np.pi / 15. * rho[i-1] * (radius[i]**5 -
radius[i-1]**5)
return moi_solid / mass / radius[n]**2
# ==== EXECUTE SCRIPT ====
if __name__ == "__main__":
main()
Calculate the hydrostatic relief of the lunar core accounting for the non-hydrostatic potential that comes from the lithosphere.
Mars#
Mars-Crust.py
#!/usr/bin/env python3
"""
Mars-Crust
Create a crustal thickness map of Mars from gravity and topography.
This script generates two different crustal thickness maps. The first assumes
that the density of both the crust and mantle are constant, whereas the second
includes the effect of different densities on either side of the dichotomy
boundary. The average crustal thickness is iterated in order to obtain
a specified minimum crustal thickness. The routine does not consider the low
densities of the polar deposits.
"""
import os
import pyshtools as pysh
from ctplanet import pyMoho
from ctplanet import pyMohoRho
from ctplanet import HydrostaticShapeLith
from ctplanet import HydrostaticShape
from ctplanet import ReadRefModel
# ==== MAIN FUNCTION ====
def main():
densityfile = 'Data/dichotomy_359.sh'
model_name = ['DWThot', 'DWThotCrust1', 'DWThotCrust1r', 'EH45Tcold',
'EH45TcoldCrust1', 'EH45TcoldCrust1r', 'EH45ThotCrust2',
'EH45ThotCrust2r', 'LFAK', 'SANAK', 'TAYAK', 'DWAK',
'ZG_DW']
spec = 'Data/Mars-reference-interior-models/Smrekar/'
interior_file = [spec + name + '.deck' for name in model_name]
lmax_calc = 90
lmax = lmax_calc * 4
potential = pysh.datasets.Mars.GMM3()
try:
os.mkdir('figs')
except Exception:
pass
print('Gravity file = {:s}'.format('GMM3'))
print('Lmax of potential coefficients = {:d}'.format(potential.lmax))
print('Reference radius (km) = {:f}'.format(potential.r0 / 1.e3))
print('GM = {:e}\n'.format(potential.gm))
topo = pysh.datasets.Mars.MOLA_shape(lmax=lmax)
topo.r0 = topo.coeffs[0, 0, 0]
print('Topography file = {:s}'.format('MOLA_shape'))
print('Lmax of topography coefficients = {:d}'.format(topo.lmax))
print('Reference radius (km) = {:f}\n'.format(topo.r0 / 1.e3))
density = pysh.SHCoeffs.from_file(densityfile).pad(lmax=lmax)
print('Lmax of density coefficients = {:d}\n'.format(density.lmax))
lat_insight = 4.502384
lon_insight = 135.623447
filter = 1
half = 50
nmax = 7
lmax_hydro = 15
t0_sigma = 5. # maximum difference between minimum crustal thickness
omega = pysh.constants.Mars.angular_velocity.value
d_lith = 150.e3
t0 = 1.e3 # minimum crustal thickness
model = 10 # identifier for the interior reference model
# --- read 1D reference interior model ---
radius, rho, i_crust, i_core, i_lith = ReadRefModel(
interior_file[model], depth=d_lith, quiet=False)
rho_mantle = rho[i_crust-1]
# rho_core = rho[i_core-1]
n = len(radius) - 1
# r0_model = radius[n]
# --- Compute gravity contribution from hydrostatic density interfaces ---
thickave = 44.e3 # initial guess of average crustal thickness
r_sigma = topo.r0 - thickave
rho_c = 2900.
if True:
# compute values for a planet that is completely fluid
hlm_fluid, clm_fluid, mass_model = \
HydrostaticShape(radius, rho, omega, potential.gm, potential.r0)
print('--- Hydrostatic potential coefficients for a fluid planet ---')
print('c20 = {:e}\nc40 = {:e}'.format(clm_fluid.coeffs[0, 2, 0],
clm_fluid.coeffs[0, 4, 0]))
print('--- Hydrostatic relief of surface for a fluid planet ---')
print('h20 = {:e}\nh40 = {:e}'.format(hlm_fluid[n].coeffs[0, 2, 0],
hlm_fluid[n].coeffs[0, 4, 0]))
hlm, clm_hydro, mass_model = \
HydrostaticShapeLith(radius, rho, i_lith, potential, topo, rho_c,
r_sigma, omega, lmax_hydro)
print('Total mass of model (kg) = {:e}'.format(mass_model))
print('% of J2 arising from beneath lithosphere = {:f}'
.format(clm_hydro.coeffs[0, 2, 0]/potential.coeffs[0, 2, 0] * 100.))
potential.coeffs[:, :lmax_hydro+1, :lmax_hydro+1] -= \
clm_hydro.coeffs[:, :lmax_hydro+1, :lmax_hydro+1]
# --- Constant density model ---
rho_c = 2900.
print('-- Constant density model --\nrho_c = {:f}'.format(rho_c))
tmin = 1.e9
thickave = 44.e3 # initial guess of average crustal thickness
while abs(tmin - t0) > t0_sigma:
# iterate to fit assumed minimum crustal thickness
moho = pyMoho(potential, topo, lmax, rho_c, rho_mantle,
thickave, filter_type=filter, half=half,
lmax_calc=lmax_calc, nmax=nmax, quiet=True)
thick_grid = (topo.pad(lmax) - moho.pad(lmax)).expand(grid='DH2')
print('Average crustal thickness (km) = {:f}'.format(thickave / 1.e3))
print('Crustal thickness at InSight landing sites (km) = {:f}'
.format((topo.pad(lmax) - moho.pad(lmax))
.expand(lat=lat_insight, lon=lon_insight) / 1.e3))
tmin = thick_grid.min()
tmax = thick_grid.max()
print('Minimum thickness (km) = {:e}'.format(tmin / 1.e3))
print('Maximum thickness (km) = {:e}'.format(tmax / 1.e3))
thickave += t0 - tmin
thick_grid.plot(colorbar='bottom', show=False,
cb_label='Crustal thickness, km',
fname='figs/Thick-Mars-1.png')
moho.plot_spectrum(show=False, fname='figs/Moho-spectrum-Mars-1.png')
# --- Model with variable density ---
rho_south = 2900.
rho_north = 2900.
porosity = 0.0
print('-- Variable density model ---\n' +
'rho_south = {:f}\n'.format(rho_south) +
'rho_north = {:f}'.format(rho_north))
density = density * (rho_north - rho_south)
density.coeffs[0, 0, 0] += rho_south
tmin = 1.e9
thickave = 44.e3 # initial guess of average crustal thickness
while abs(tmin - t0) > t0_sigma:
# iterate to fit assumed minimum crustal thickness
moho = pyMohoRho(potential, topo, density, porosity, lmax,
rho_mantle, thickave, filter_type=filter,
half=half, lmax_calc=lmax_calc, quiet=True,
nmax=nmax)
thick_grid = (topo.pad(lmax) - moho.pad(lmax)).expand(grid='DH2')
print('Average crustal thickness (km) = {:e}'.format(thickave / 1.e3))
print('Crustal thickness at InSight landing sites (km) = {:e}'
.format((topo.pad(lmax) - moho.pad(lmax))
.expand(lat=lat_insight, lon=lon_insight) / 1.e3))
tmin = thick_grid.data.min()
tmax = thick_grid.data.max()
print('Minimum thickness (km) = {:e}'.format(tmin / 1.e3))
print('Maximum thickness (km) = {:e}'.format(tmax / 1.e3))
thickave += t0 - tmin
thick_grid.plot(colorbar='bottom', show=False,
cb_label='Crustal thickness, km',
fname='figs/Thick-Mars-2.png')
moho.plot_spectrum(show=False, fname='figs/Moho-spectrum-Mars-2.png')
# ==== EXECUTE SCRIPT ====
if __name__ == "__main__":
main()
A script that demonstrates how to calculate the thickness of the Martian crust using either a constant or variable density crust. For the variable density crust, the density is assumed to change discontinuously across the dichotomy boundary.
Mars-Crust-hydrostatic-tests.py
#!/usr/bin/env python3
"""
Mars-Crust-hydrostatic-tests
Create a crustal thickness map of Mars from gravity and topography and compare
how results change if hydrostatic interfaces are not taken into account.
"""
import os
import numpy as np
import pyshtools as pysh
from ctplanet import pyMoho
from ctplanet import HydrostaticShapeLith
from ctplanet import HydrostaticShape
# ==== MAIN FUNCTION ====
def main():
model_name = ['DWThot', 'DWThotCrust1', 'DWThotCrust1r', 'EH45Tcold',
'EH45TcoldCrust1', 'EH45TcoldCrust1r', 'EH45ThotCrust2',
'EH45ThotCrust2r', 'LFAK', 'SANAK', 'TAYAK', 'DWAK',
'ZG_DW']
spec = 'Data/Mars-reference-interior-models/Smrekar/'
interior_file = [spec + name + '.deck' for name in model_name]
model = 10
d_lith = 150.e3
lmax_calc = 90
lmax = lmax_calc * 4
lmax_grid = 719
potential = pysh.datasets.Mars.GMM3()
topo = pysh.datasets.Mars.MOLA_shape(lmax=lmax_grid)
topo.r0 = topo.coeffs[0, 0, 0]
try:
os.mkdir('figs')
except Exception:
pass
print('Gravity file = {:s}'.format('GMM3'))
print('Lmax of potential coefficients = {:d}'.format(potential.lmax))
print('Reference radius (km) = {:f}'.format(potential.r0 / 1.e3))
print('GM = {:e}'.format(potential.gm))
print('Mass = {:e}'.format(potential.mass))
print('Topography file = {:s}'.format('MOLA_shape'))
print('Lmax of topography coefficients = {:d}'.format(topo.lmax))
print('Reference radius (km) = {:f}\n'.format(topo.r0 / 1.e3))
lat_insight = 4.43
lon_insight = 135.84
filter = 1
half = 50
nmax = 7
lmax_hydro = 50
t0_sigma = 5. # maximum difference between minimum crustal thickness
rho_c = 2900.
t0 = 1.e3 # minimum crustal thickness
omega = pysh.constants.Mars.angular_velocity.value
print('Omega = {:e}'.format(omega))
# --- read 1D reference interior model ---
with open(interior_file[model], 'r') as f:
lines = f.readlines()
print(lines[0].strip())
data = lines[1].split()
if float(data[2]) != 1:
raise RuntimeError('Program not capable of reading polynomial ' +
'files')
num_file = int(lines[2].split()[0])
crust_index_file = int(lines[2].split()[3])
core_index_file = int(lines[2].split()[2])
i_crust_file = crust_index_file - 1
i_core_file = core_index_file - 1
radius = np.zeros(num_file)
rho = np.zeros(num_file)
num = 0
for i in range(0, num_file-1):
data = lines[i+3].split()
rb = float(data[0])
rhob = float(data[1])
data = lines[i+4].split()
rt = float(data[0])
rhot = float(data[1])
if rb == rt:
if i == i_core_file:
i_core = num
if i == i_crust_file:
i_crust = num
else:
radius[num] = rb
rho[num] = (rhot + rhob) / 2.
num += 1
radius[num] = rt
rho[num] = 0. # the density above the surface is zero
num += 1
n = num - 1
radius = radius[:n+1]
rho = rho[:n+1]
r0_model = radius[n]
print('Surface radius of model (km) = {:f}'.format(r0_model / 1.e3))
for i in range(0, n+1):
if radius[i] <= (r0_model - d_lith) and \
radius[i+1] > (r0_model - d_lith):
if radius[i] == (r0_model - d_lith):
i_lith = i
elif (r0_model - d_lith) - radius[i] <= radius[i+1] -\
(r0_model - d_lith):
i_lith = i
else:
i_lith = i + 1
break
rho_mantle = rho[i_crust-1]
rho_core = rho[i_core-1]
print('Mantle density (kg/m3) = {:f}'.format(rho_mantle))
print('Mantle radius (km) = {:f}'.format(radius[i_crust]/1.e3))
print('Core density (kg/m3) = {:f}'.format(rho_core))
print('Core radius (km) = {:f}'.format(radius[i_core]/1.e3))
print('Assumed depth of lithosphere (km) = {:f}'.format(d_lith / 1.e3))
print('Actual depth of lithosphere in discretized model (km) = {:f}'
.format((r0_model - radius[i_lith]) / 1.e3))
# --- Compute gravity contribution from hydrostatic density interfaces ---
thickave = 44.e3 # initial guess of average crustal thickness
r_sigma = topo.r0 - thickave
if True:
# compute values for a planet that is completely fluid
hlm_fluid, clm_fluid, mass_model = \
HydrostaticShape(radius, rho, omega, potential.gm, potential.r0,
i_clm_hydro=i_lith)
print('--- Hydrostatic potential coefficients for a fluid planet ---')
print('c20 = {:e}\nc40 = {:e}'.format(clm_fluid.coeffs[0, 2, 0],
clm_fluid.coeffs[0, 4, 0]))
print('--- Hydrostatic relief of surface for a fluid planet ---')
print('h20 = {:e}\nh40 = {:e}'.format(hlm_fluid[n].coeffs[0, 2, 0],
hlm_fluid[n].coeffs[0, 4, 0]))
print('% of J2 arising from beneath lithosphere = {:f}'
.format(clm_fluid.coeffs[0, 2, 0]
/ potential.coeffs[0, 2, 0] * 100.))
hlm, clm_hydro, mass_model = \
HydrostaticShapeLith(radius, rho, i_lith, potential, topo, rho_c,
r_sigma, omega, lmax_hydro)
print('Total mass of model (kg) = {:e}'.format(mass_model))
print('% of J2 arising from beneath lithosphere = {:f}'
.format(clm_hydro.coeffs[0, 2, 0]/potential.coeffs[0, 2, 0] * 100.))
# --- Constant density model without hydrostatic interfaces ---
print('-- Constant density model --\nrho_c = {:f}'.format(rho_c))
tmin = 1.e9
thickave = 44.e3 # initial guess of average crustal thickness
while abs(tmin - t0) > t0_sigma:
# iterate to fit assumed minimum crustal thickness
moho = pyMoho(potential, topo, lmax, rho_c, rho_mantle,
thickave, filter_type=filter, half=half,
lmax_calc=lmax_calc, nmax=nmax, quiet=True)
thick_grid = (topo.pad(lmax_grid)
- moho.pad(lmax_grid)).expand(grid='DH2')
print('Average crustal thickness (km) = {:f}'.format(thickave / 1.e3))
print('Crustal thickness at InSight landing sites (km) = {:f}'
.format((topo.pad(lmax) - moho.pad(lmax))
.expand(lat=lat_insight, lon=lon_insight) / 1.e3))
tmin = thick_grid.min()
tmax = thick_grid.max()
print('Minimum thickness (km) = {:e}'.format(tmin / 1.e3))
print('Maximum thickness (km) = {:e}'.format(tmax / 1.e3))
thickave += t0 - tmin
(thick_grid/1.e3).plot(show=False, colorbar='bottom',
cb_label='Crustal thickness, km',
fname='figs/Thick-Mars-without-hydro.png')
print('Thickness at north pole (km) = ', thick_grid.data[0, 0] / 1.e3)
# --- Constant density model with hydrostatic interfaces beneath
# --- lithosphere
potential.coeffs[:, :lmax_hydro+1, :lmax_hydro+1] -= \
clm_hydro.coeffs[:, :lmax_hydro+1, :lmax_hydro+1]
print('-- Constant density model with hydrostatic interfaces beneath '
'lithosphere--\nrho_c = {:f}'.format(rho_c))
tmin = 1.e9
thickave = 44.e3 # initial guess of average crustal thickness
while abs(tmin - t0) > t0_sigma:
# iterate to fit assumed minimum crustal thickness
moho = pyMoho(potential, topo, lmax, rho_c, rho_mantle,
thickave, filter_type=filter, half=half,
lmax_calc=lmax_calc, nmax=nmax, quiet=True)
thick2_grid = (topo.pad(lmax_grid)
- moho.pad(lmax_grid)).expand(grid='DH2')
print('Average crustal thickness (km) = {:f}'.format(thickave / 1.e3))
print('Crustal thickness at InSight landing sites (km) = {:f}'
.format((topo.pad(lmax) - moho.pad(lmax))
.expand(lat=lat_insight, lon=lon_insight) / 1.e3))
tmin = thick2_grid.min()
tmax = thick2_grid.max()
print('Minimum thickness (km) = {:e}'.format(tmin / 1.e3))
print('Maximum thickness (km) = {:e}'.format(tmax / 1.e3))
thickave += t0 - tmin
(thick2_grid/1.e3).plot(show=False, colorbar='bottom',
cb_label='Crustal thickness, km',
fname='figs/Thick-Mars-with-hydro-lith.png')
(thick2_grid/1.e3 - thick_grid/1.e3).plot(
show=False, colorbar='bottom', cb_label='Crustal thickness, km',
fname='figs/Thick-Mars-diff-hydro-lith.png')
print('Thickness at north pole (km) = ', thick2_grid.data[0, 0] / 1.e3)
min = (thick2_grid/1.e3 - thick_grid/1.e3).min()
max = (thick2_grid/1.e3 - thick_grid/1.e3).max()
print('Minimum and maximum difference (km) = ', min, max)
(thick2_grid/1.e3).to_file('figs/Thick-Mars-hydro-lith.dat')
(thick2_grid/1.e3 - thick_grid/1.e3).to_file(
'figs/Thick-Mars-diff-hydro-lith.dat')
# --- Constant density model with hydrostatic interfaces of fluid planet
potential.coeffs[:, :lmax_hydro+1, :lmax_hydro+1] += \
clm_hydro.coeffs[:, :lmax_hydro+1, :lmax_hydro+1]
potential.coeffs[:, :5, :5] -= clm_fluid.coeffs[:, :5, :5]
print('-- Constant density model with hydrostatic interfaces of a fluid '
'planet--\nrho_c = {:f}'.format(rho_c))
tmin = 1.e9
thickave = 44.e3 # initial guess of average crustal thickness
while abs(tmin - t0) > t0_sigma:
# iterate to fit assumed minimum crustal thickness
moho = pyMoho(potential, topo, lmax, rho_c, rho_mantle,
thickave, filter_type=filter, half=half,
lmax_calc=lmax_calc, nmax=nmax, quiet=True)
thick3_grid = (topo.pad(lmax_grid)
- moho.pad(lmax_grid)).expand(grid='DH2')
print('Average crustal thickness (km) = {:f}'.format(thickave / 1.e3))
print('Crustal thickness at InSight landing sites (km) = {:f}'
.format((topo.pad(lmax) - moho.pad(lmax))
.expand(lat=lat_insight, lon=lon_insight) / 1.e3))
tmin = thick3_grid.min()
tmax = thick3_grid.max()
print('Minimum thickness (km) = {:e}'.format(tmin / 1.e3))
print('Maximum thickness (km) = {:e}'.format(tmax / 1.e3))
thickave += t0 - tmin
(thick3_grid/1.e3).plot(show=False, colorbar='bottom',
cb_label='Crustal thickness, km',
fname='figs/Thick-Mars-with-fluid.png')
print('Thickness at north pole (km) = ', thick3_grid.data[0, 0] / 1.e3)
(thick2_grid/1.e3 - thick3_grid/1.e3).plot(
show=False, colorbar='bottom', cb_label='Crustal thickness, km',
fname='figs/Thick-Mars-diff-lith-fluid.png')
min = (thick2_grid/1.e3 - thick3_grid/1.e3).min()
max = (thick2_grid/1.e3 - thick3_grid/1.e3).max()
print('Minimum and maximum difference (km) = ', min, max)
(thick2_grid/1.e3 - thick3_grid/1.e3).to_file(
'figs/Thick-Mars-diff-lith-fluid.dat')
# ==== EXECUTE SCRIPT ====
if __name__ == "__main__":
main()
Create a crustal thickness map of Mars from gravity and topography and compare how results change if hydrostatic interfaces are not taken into account.
Mars-Crust-InSight.py
#!/usr/bin/env python3
"""
Mars-Crust-InSight
Create a crustal thickness map of Mars from gravity and topography, using
the InSight crustal thickness constraint.
The script assumes that the density of both the crust and mantle are constant,
and that porosity in present in a constant thickness surficial layer (excluding
the polar caps). The gravitational contribution of the polar caps are
explicitly accounted for, and the average crustal thickness is iterated in
order to fit the specified thickness at the InSight landing site.
"""
import os
import matplotlib.pyplot as plt
import pyshtools as pysh
from ctplanet import pyMoho
from ctplanet import HydrostaticShapeLith
from ctplanet import ReadRefModel
# ==== MAIN FUNCTION ====
def main():
northpolarcap = 'Data/Mars_NorthPolarCapThickness719.sh.gz'
southpolarcap = 'Data/Mars_SouthPolarCapThickness719.sh.gz'
model_name1 = ['DWThot', 'DWThotCrust1', 'DWThotCrust1r', 'EH45Tcold',
'EH45TcoldCrust1', 'EH45TcoldCrust1r', 'EH45ThotCrust2',
'EH45ThotCrust2r', 'LFAK', 'SANAK', 'TAYAK', 'DWAK',
'ZG_DW', 'YOTHotRc1760kmDc40km', 'YOTHotRc1810kmDc40km']
spec1 = 'Data/Mars-reference-interior-models/Smrekar/'
model_name2 = ['Khan2022']
spec2 = 'Data/Mars-reference-interior-models/'
interior_file = [spec1 + name + '.deck' for name in model_name1]
interior_file += [spec2 + name + '.deck' for name in model_name2]
model_name = model_name1 + model_name2
lmax_calc = 90
lmax = lmax_calc * 4
potential = pysh.datasets.Mars.GMM3()
print('Gravity file = {:s}'.format('GMM3'))
print('Lmax of potential coefficients = {:d}'.format(potential.lmax))
print('Reference radius (km) = {:f}'.format(potential.r0 / 1.e3))
print('GM = {:e}\n'.format(potential.gm))
# read topo up to degree lmax
topo = pysh.datasets.Mars.MOLA_shape(lmax=lmax)
topo_grid = topo.pad(lmax).expand(grid='DH2')
print('Topography file = {:s}'.format('MOLA_shape'))
print('Lmax of topography coefficients = {:d}'.format(topo.lmax))
print('Reference radius (km) = {:f}\n'.format(topo.coeffs[0, 0, 0] / 1.e3))
# read polar cap thicknesses up to lmax
npc = pysh.SHCoeffs.from_file(northpolarcap, lmax=lmax)
spc = pysh.SHCoeffs.from_file(southpolarcap, lmax=lmax)
rho_npc = 1250.
rho_spc = 1300.
print('North polar cap thickness file = {:s}'.format(northpolarcap))
print('Lmax of North polar cap coefficients = {:d}'.format(npc.lmax))
print('Assumed density of the North polar cap (kg m-3) = {:e}'
.format(rho_npc))
print('South polar cap thickness file = {:s}'.format(southpolarcap))
print('Lmax of South polar cap coefficients = {:d}'.format(spc.lmax))
print('Assumed density of the South polar cap (kg m-3) = {:e}'
.format(rho_npc))
# Topography excluding the polar caps
topo_no_pc = topo - npc - spc
topo_no_pc_grid = topo_no_pc.expand(grid='DH2')
# compute gravitational contribution of the polar caps
npc_correction = pysh.SHGravCoeffs.from_shape(shape=topo_no_pc+npc,
rho=1.0,
gm=potential.gm,
nmax=8,
lmax=lmax_calc,
lmax_grid=lmax,
lmax_calc=lmax)
spc_correction = pysh.SHGravCoeffs.from_shape(shape=topo_no_pc + spc,
rho=1.0,
gm=potential.gm,
nmax=8,
lmax=lmax_calc,
lmax_grid=lmax,
lmax_calc=lmax)
base_correction = pysh.SHGravCoeffs.from_shape(shape=topo_no_pc,
rho=1.0,
gm=potential.gm,
nmax=8,
lmax=lmax_calc,
lmax_grid=lmax,
lmax_calc=lmax)
pc_correction = rho_npc * npc_correction.change_ref(r0=potential.r0)
pc_correction += rho_spc * spc_correction.change_ref(r0=potential.r0)
pc_correction -= (rho_spc + rho_npc) * \
base_correction.change_ref(r0=potential.r0)
filter = 1
half = 50
nmax = 7
lmax_hydro = 15
t_sigma = 5. # maximum difference between crustal thickness iterations
omega = pysh.constants.Mars.angular_velocity.value
d_lith = 150.e3
# Get input model and InSight crustal thickness
lat_insight = 4.502384
lon_insight = 135.623447
print('Input crustal thickness at InSight landing site (km) >')
t_insight_ref = float(input())
t_insight_ref *= 1.e3
ident = str(int(t_insight_ref / 1.e3))
print('Input thickness of porous layer (km) >')
t_porosity = float(input())
t_porosity *= 1.e3
porosity = 0.
if t_porosity != 0.:
directory = 'InSight/constant-porosity/'
print('Input porosity of porous layer in percent >')
porosity = float(input())
porosity /= 100.
else:
directory = 'InSight/constant/'
if porosity != 0.:
ident += '-' + str(int(t_porosity / 1.e3)) + '-' \
+ str(int(porosity * 100))
try:
os.mkdir(directory)
except Exception:
pass
rho_c_min = 2550.
rho_c_max = 3300.
rho_c_int = 50.
f_summary = open(directory + 'summary-' + ident + '.txt', 'w')
f_summary.write('Model rho_c rho_mantle t_insight t_ave '
+ ' t_min t_max\n')
# Compute contribution to the gravitational potential resulting
# from porosity. The density contrast at the surface of this layer
# is: - porosity * rho_crust and at the base it is porosity * rho_crust.
# Here we assume that rho_c is 1 and then multiply this later by the
# correct value. Note that no porosity is added to the polar caps.
if porosity != 0.:
pot_porosity = pysh.SHGravCoeffs.from_shape(topo_no_pc, -porosity,
potential.gm,
nmax=nmax,
lmax=lmax_calc,
lmax_grid=lmax,
lmax_calc=lmax
)
pot_porosity = pot_porosity.change_ref(r0=potential.r0)
pot_lower = pysh.SHGravCoeffs.from_shape(topo_no_pc - t_porosity,
porosity,
potential.gm,
nmax=nmax,
lmax=lmax_calc,
lmax_grid=lmax,
lmax_calc=lmax
)
pot_porosity += pot_lower.change_ref(r0=potential.r0)
for model in range(len(model_name)):
print('Working on model : {:s}'.format(model_name[model]))
# --- read 1D reference interior model ---
radius, rho, i_crust, i_core, i_lith = ReadRefModel(
interior_file[model], depth=d_lith, quiet=False)
rho_mantle = rho[i_crust-1]
# rho_core = rho[i_core-1]
# n = len(radius) - 1
# r0_model = radius[n]
for i in range(int((rho_c_max - rho_c_min) / rho_c_int + 1)):
rho_c = rho_c_min + i * rho_c_int
print('rho_crust (kg/m3) = {:f}'.format(rho_c))
ident = model_name[model] + '-' + str(int(t_insight_ref / 1.e3)) \
+ '-' + str(int(rho_c))
if porosity != 0.:
ident += '-' + str(int(t_porosity / 1.e3)) + '-' \
+ str(int(porosity * 100))
# Compute gravity contribution from hydrostatic density interfaces
thickave = 44.e3 # initial guess of average crustal thickness
r_sigma = topo.coeffs[0, 0, 0] - thickave
hlm, clm_hydro, mass_model = \
HydrostaticShapeLith(radius, rho, i_lith, potential, topo,
rho_c, r_sigma, omega, lmax_hydro)
print('Total mass of model (kg) = {:e}'.format(mass_model))
print('% of J2 arising from beneath lithosphere = {:f}'
.format(clm_hydro.coeffs[0, 2, 0] /
potential.coeffs[0, 2, 0] * 100.))
pot_lith = potential.copy()
pot_lith.coeffs[:, :lmax_hydro+1, :lmax_hydro+1] -= \
clm_hydro.coeffs[:, :lmax_hydro+1, :lmax_hydro+1]
if porosity != 0.:
pot_lith.coeffs[:, :lmax_calc+1, :lmax_calc+1] -= \
rho_c * pot_porosity.coeffs[:, :lmax_calc+1, :lmax_calc+1]
t_insight = 1.e9
pot_temp = pot_lith.copy()
pot_porosity_correction = pysh.SHGravCoeffs.from_zeros(
lmax_calc, potential.gm, potential.r0)
# iterate to fit assumed InSight crustal thickness
while abs(t_insight_ref - t_insight) > t_sigma:
if porosity != 0.:
pot_temp = pot_lith.pad(lmax=lmax_calc) \
- pot_porosity_correction.pad(lmax=lmax_calc)
moho = pyMoho(pot_temp, topo_no_pc, lmax, rho_c, rho_mantle,
thickave, filter_type=filter, half=half,
lmax_calc=lmax_calc, nmax=nmax,
correction=pc_correction, quiet=True)
moho_grid = moho.pad(lmax).expand(grid='DH2')
thick_grid = topo_grid - moho_grid
t_insight = (topo.pad(lmax) -
moho.pad(lmax)).expand(lat=lat_insight,
lon=lon_insight)
tmin = thick_grid.min()
tmax = thick_grid.max()
thickave += t_insight_ref - t_insight
# Compute correction resulting from porosity in the mantle
if porosity != 0.:
lower_grid = topo_no_pc_grid - t_porosity
upper_grid = lower_grid.copy()
upper_grid.data[moho_grid.data > lower_grid.data] = \
moho_grid.data[moho_grid.data > lower_grid.data]
pot_porosity_correction = \
pysh.SHGravCoeffs.from_shape(
upper_grid, -porosity * (rho_mantle - rho_c),
potential.gm, nmax=nmax, lmax_grid=lmax,
lmax=lmax_calc)
pot_porosity_correction = \
pot_porosity_correction.change_ref(r0=potential.r0)
pot_lower = pysh.SHGravCoeffs.from_shape(
lower_grid, porosity * (rho_mantle - rho_c),
potential.gm, nmax=nmax, lmax_grid=lmax,
lmax=lmax_calc)
pot_porosity_correction += \
pot_lower.change_ref(r0=potential.r0)
print('Average crustal thickness (km) = {:f}'
.format(thickave / 1.e3))
print('Crustal thickness at InSight landing sites (km) = {:f}'
.format(t_insight / 1.e3))
print('Minimum thickness (km) = {:e}'.format(tmin / 1.e3))
print('Maximum thickness (km) = {:e}'.format(tmax / 1.e3))
if tmin < 0:
break
moho.pad(lmax_calc).to_file(directory + 'Moho-Mars-'
+ ident + '.sh')
fig, ax = (thick_grid/1.e3).plot(
show=False, colorbar='bottom',
cb_label='Crustal thickness (km)',
fname=directory + 'Thick-Mars-' + ident + '.png')
# fig2, ax2 = moho.plot_spectrum(
# show=False,
# fname=directory + 'Moho-spectrum-Mars-' + ident + '.png',
# legend=ident)
f_summary.write('{:s} {:f} {:f} {:f} {:f} '
'{:f} {:f}\n'
.format(model_name[model], rho_c, rho_mantle,
t_insight/1.e3, thickave / 1.e3,
tmin / 1.e3, tmax / 1.e3))
plt.close(fig)
# plt.close(fig2)
f_summary.close()
# ==== EXECUTE SCRIPT ====
if __name__ == "__main__":
main()
Create a crustal thickness map of Mars from gravity and topography, using the InSight crustal thickness constraint.
Mars-Crust-InSight-dichotomy.py
#!/usr/bin/env python3
"""
Mars-Crust-InSight-dichotomy
Create a crustal thickness map of Mars from gravity and topography, using
the InSight crustal thickness constraint.
The script assumes that the mantle density is constant and that the density of
the crust differs on either side of the dichotomy boundary. The gravitational
contribution of the polar caps are explicitly accounted for, and the average
crustal thickness is iterated in order to fit the specified thickness at the
InSight landing site.
"""
import os
import matplotlib.pyplot as plt
import pyshtools as pysh
from ctplanet import pyMohoRho
from ctplanet import HydrostaticShapeLith
from ctplanet import ReadRefModel
# ==== MAIN FUNCTION ====
def main():
densityfile = 'Data/dichotomy_359.sh'
northpolarcap = 'Data/Mars_NorthPolarCapThickness719.sh.gz'
southpolarcap = 'Data/Mars_SouthPolarCapThickness719.sh.gz'
model_name1 = ['DWThot', 'DWThotCrust1', 'DWThotCrust1r', 'EH45Tcold',
'EH45TcoldCrust1', 'EH45TcoldCrust1r', 'EH45ThotCrust2',
'EH45ThotCrust2r', 'LFAK', 'SANAK', 'TAYAK', 'DWAK',
'ZG_DW', 'YOTHotRc1760kmDc40km', 'YOTHotRc1810kmDc40km']
spec1 = 'Data/Mars-reference-interior-models/Smrekar/'
model_name2 = ['Khan2022']
spec2 = 'Data/Mars-reference-interior-models/'
interior_file = [spec1 + name + '.deck' for name in model_name1]
interior_file += [spec2 + name + '.deck' for name in model_name2]
model_name = model_name1 + model_name2
lmax_calc = 90
lmax = lmax_calc * 4
potential = pysh.datasets.Mars.GMM3()
directory = 'InSight/dichotomy/'
try:
os.mkdir(directory)
except Exception:
pass
print('Gravity file = {:s}'.format('GMM3'))
print('Lmax of potential coefficients = {:d}'.format(potential.lmax))
print('Reference radius (km) = {:f}'.format(potential.r0 / 1.e3))
print('GM = {:e}\n'.format(potential.gm))
topo = pysh.datasets.Mars.MOLA_shape(lmax=lmax)
topo_grid = topo.pad(lmax).expand(grid='DH2')
print('Topography file = {:s}'.format('MOLA_shape'))
print('Lmax of topography coefficients = {:d}'.format(topo.lmax))
print('Reference radius (km) = {:f}\n'.format(topo.coeffs[0, 0, 0] / 1.e3))
print('Crustal density file = {:s}'.format(densityfile))
dichotomy = pysh.SHCoeffs.from_file(densityfile).pad(lmax=lmax)
print('Lmax of density coefficients = {:d}\n'.format(dichotomy.lmax))
# read polar cap thicknesses up to lmax
npc = pysh.SHCoeffs.from_file(northpolarcap, lmax=lmax)
spc = pysh.SHCoeffs.from_file(southpolarcap, lmax=lmax)
rho_npc = 1250.
rho_spc = 1300.
print('North polar cap thickness file = {:s}'.format(northpolarcap))
print('Lmax of North polar cap coefficients = {:d}'.format(npc.lmax))
print('Assumed density of the North polar cap (kg m-3) = {:e}'
.format(rho_npc))
print('South polar cap thickness file = {:s}'.format(southpolarcap))
print('Lmax of South polar cap coefficients = {:d}'.format(spc.lmax))
print('Assumed density of the South polar cap (kg m-3) = {:e}'
.format(rho_npc))
# Topography excluding the polar caps
topo_no_pc = topo - npc - spc
# compute gravitational contribution of the polar caps
npc_correction = pysh.SHGravCoeffs.from_shape(shape=topo_no_pc+npc,
rho=1.0,
gm=potential.gm,
nmax=8,
lmax=lmax_calc,
lmax_grid=lmax,
lmax_calc=lmax)
spc_correction = pysh.SHGravCoeffs.from_shape(shape=topo_no_pc + spc,
rho=1.0,
gm=potential.gm,
nmax=8,
lmax=lmax_calc,
lmax_grid=lmax,
lmax_calc=lmax)
base_correction = pysh.SHGravCoeffs.from_shape(shape=topo_no_pc,
rho=1.0,
gm=potential.gm,
nmax=8,
lmax=lmax_calc,
lmax_grid=lmax,
lmax_calc=lmax)
pc_correction = rho_npc * npc_correction.change_ref(r0=potential.r0)
pc_correction += rho_spc * spc_correction.change_ref(r0=potential.r0)
pc_correction -= (rho_spc + rho_npc) * \
base_correction.change_ref(r0=potential.r0)
filter = 1
half = 50
nmax = 7
lmax_hydro = 15
t_sigma = 5. # maximum difference between crustal thickness iterations
omega = pysh.constants.Mars.angular_velocity.value
d_lith = 150.e3
# Get input model and InSight crustal thickness
lat_insight = 4.502384
lon_insight = 135.623447
print('Input crustal thickness at InSight landing site (km) >')
t_insight_ref = float(input())
t_insight_ref *= 1.e3
rho_c_min = 2550.
rho_c_max = 3200.
rho_c_int = 50.
ident = str(int(t_insight_ref / 1.e3))
f_summary = open(directory + 'summary-' + ident + '.txt', 'w')
f_summary.write('Model rho_south rho_north rho_mantle '
't_insight t_ave t_min t_max\n')
for model in range(len(model_name)):
print('Working on model : {:s}'.format(model_name[model]))
# --- read 1D reference interior model ---
radius, rho, i_crust, i_core, i_lith = ReadRefModel(
interior_file[model], depth=d_lith, quiet=False)
rho_mantle = rho[i_crust-1]
# rho_core = rho[i_core-1]
# n = len(radius) - 1
# r0_model = radius[n]
for i in range(int((rho_c_max - rho_c_min) / rho_c_int + 1)):
rho_south = rho_c_min + i * rho_c_int
for j in range(int((rho_c_max - rho_c_min) / rho_c_int + 1)):
rho_north = rho_c_min + j * rho_c_int
if rho_north < rho_south:
continue
print('rho_south = {:f}\n'.format(rho_south) +
'rho_north = {:f}'.format(rho_north))
density = dichotomy.copy()
density = density * (rho_north - rho_south)
density.coeffs[0, 0, 0] += rho_south
crustal_porosity = 0.0
ident = model_name[model] + '-' \
+ str(int(t_insight_ref / 1.e3)) \
+ '-' + str(int(rho_south)) + '-' + str(int(rho_north))
# Compute gravity contribution from hydrostatic density
# interfaces
thickave = 44.e3 # initial guess of average crustal thickness
r_sigma = topo.coeffs[0, 0, 0] - thickave
hlm, clm_hydro, mass_model = \
HydrostaticShapeLith(radius, rho, i_lith, potential, topo,
(rho_south + rho_north) / 2, r_sigma,
omega, lmax_hydro)
print('Total mass of model (kg) = {:e}'.format(mass_model))
print('% of J2 arising from beneath lithosphere = {:f}'
.format(clm_hydro.coeffs[0, 2, 0] /
potential.coeffs[0, 2, 0] * 100.))
pot_lith = potential.copy()
pot_lith.coeffs[:, :lmax_hydro+1, :lmax_hydro+1] -= \
clm_hydro.coeffs[:, :lmax_hydro+1, :lmax_hydro+1]
t_insight = 1.e9
thickave = 44.e3 # initial guess of average thickness
while abs(t_insight_ref - t_insight) > t_sigma:
# iterate to fit assumed minimum crustal thickness
moho = pyMohoRho(pot_lith, topo_no_pc, density,
crustal_porosity, lmax,
rho_mantle, thickave,
filter_type=filter,
half=half, lmax_calc=lmax_calc,
quiet=True,
correction=pc_correction,
nmax=nmax)
moho_grid = moho.pad(lmax).expand(grid='DH2')
thick_grid = topo_grid - moho_grid
t_insight = (topo.pad(lmax) -
moho.pad(lmax)).expand(lat=lat_insight,
lon=lon_insight)
tmin = thick_grid.min()
tmax = thick_grid.max()
thickave += t_insight_ref - t_insight
print('Average crustal thickness (km) = {:f}'
.format(thickave / 1.e3))
print('Crustal thickness at InSight landing sites (km) = {:f}'
.format(t_insight / 1.e3))
print('Minimum thickness (km) = {:e}'.format(tmin / 1.e3))
print('Maximum thickness (km) = {:e}'.format(tmax / 1.e3))
if tmin < 0:
break
moho.pad(lmax_calc).to_file(
directory + 'Moho-Mars-' + ident + '.sh')
fig, ax = (thick_grid/1.e3).plot(
show=False,
colorbar='bottom',
cb_label='Crustal thickness (km)',
fname=directory + 'Thick-Mars-' + ident + '.png')
# fig2, ax2 = moho.plot_spectrum(
# show=False,
# fname=directory + 'Moho-spectrum-Mars-'
# + ident + '.png',
# legend=ident)
f_summary.write('{:s} {:f} {:f} {:f} {:f} '
'{:f} {:f} {:f}\n'
.format(model_name[model], rho_south,
rho_north, rho_mantle,
t_insight / 1.e3,
thickave / 1.e3, tmin / 1.e3,
tmax / 1.e3))
plt.close(fig)
# plt.close(fig2)
f_summary.close()
# ==== EXECUTE SCRIPT ====
if __name__ == "__main__":
main()
Create a crustal thickness map of Mars from gravity and topography, using the InSight crustal thickness constraint and different densities across the dichotomy boundary.
Mars-fcn.py
#!/usr/bin/env python3
"""
Mars-fcn
Compute the free core nutation period of Mars.
"""
import numpy as np
import pyshtools as pysh
from ctplanet import InertiaTensor_from_C
# ==== MAIN FUNCTION ====
def main():
lmax = 2
potential = pysh.datasets.Mars.GMM3(lmax=lmax)
mass_mars = potential.mass
r0_pot = potential.r0
omega = pysh.constants.Mars.angular_velocity.value
print('Gravity file = {:s}'.format('GMM3'))
print('Reference radius (km) = {:f}'.format(potential.r0 / 1.e3))
print('GM = {:e}'.format(potential.gm))
print('G, m3 / (kg s2) = {:e}'.format(pysh.constants.G.value))
print('Mass = {:e}'.format(potential.mass))
print('Omega = {:e}'.format(omega))
topo = pysh.datasets.Mars.MOLA_shape(lmax=lmax)
r_mars = topo.coeffs[0, 0, 0]
print('Topography file = {:s}'.format('MOLA_shape'))
print('Mean planetary radius (km) = {:f}\n'.format(r_mars / 1.e3))
# Compute polar moment using precession rate and other constants
# defined in Konopliv et al. 2016 (and 2011).
J2 = - potential.to_array(normalization='unnorm', errors=False)[0, 2, 0]
print('J2 = {:e}'.format(J2))
phidot = -7608.3 # +- 2.1 mas / yr (Konopliv et al. 2016)
phidotp = -0.2 # planetary torque correction, from Konopliv et al. 2011
phidotg = 6.7 # relativistic correction, from Konopliv et al. 2011
phi0dot = phidot - phidotp - phidotg
print('Phi0-dot, mas/yr = {:f}'.format(phi0dot))
phi0dot *= np.pi / 180 / 1000 / 60 / 60 / 365.25 / 24 / 60 / 60
e_mars = 0.09341 # Konopliv et al. 2011
print('e_mars = {:f}'.format(e_mars))
obliquity = 25.1893823 # degrees, Konopliv et al. 2016
print('obliquity, degrees = {:f}'.format(obliquity))
obliquity *= np.pi / 180
n0 = 191.408 # degrees per year, Konopliv et al. 2011
print('n0, degrees/yr = {:f}'.format(n0))
n0 *= np.pi / 180 / 24 / 60 / 60 / 365.25
C = (-1 / phi0dot) * (3/2) * (n0**2 / omega) * (1 - e_mars**2)**(-3/2) \
* J2 * np.cos(obliquity)
C *= mass_mars * r0_pot**2
print('C (Konopliv et al. 2016) = {:e}'.format(C))
print('C / (M R^2) (Konopliv et al. 2016) = {:e}'.format(C / mass_mars /
(r0_pot)**2))
print('C / (M R_mpr^2) (Konopliv et al. 2016) = {:e}\n'
.format(C / mass_mars / r_mars**2))
II, AA, BB, CC, angles = InertiaTensor_from_C(C, potential, quiet=False,
normalize=True,
r_norm=r_mars)
beta = 0.00032
Acf = 0.0254088
Bcf = 0.0254088
Ccf = 0.0255172
Ac = 0.0254036
Bc = 0.0254113
Cc = 0.0255199
print('Free core nutation period (days), fluid planet = {:f}'
.format(2 * np.pi / sigma_fcn(omega, AA, Acf, Bcf, Ccf, beta)
/ 60 / 60 / 24))
print('Free core nutation period (days), planet with lithosphere = {:f}'
.format(2 * np.pi / sigma_fcn(omega, AA, Ac, Bc, Cc, beta)
/ 60 / 60 / 24))
def sigma_fcn(omega, A, Ac, Bc, Cc, beta):
'''
Compute the free core nutation frequency.
'''
alpha = (2 * Cc - (Ac + Bc)) / (Ac + Bc)
sigma = - omega * (A / (A - Ac)) * (alpha - beta)
return sigma
# ==== EXECUTE SCRIPT ====
if __name__ == "__main__":
main()
Compute the free core nutation period of Mars.
Mars-shape.py
#!/usr/bin/env python3
"""
Mars-shape
Calculations and images of the shape of density interfaces of Mars as presented
in Wieczorek et al. (2019).
"""
import os
import numpy as np
import pyshtools as pysh
from ctplanet import HydrostaticShapeLith
from ctplanet import HydrostaticShape
from ctplanet import InertiaTensor_from_shape
from ctplanet import ReadRefModel
# ==== MAIN FUNCTION ====
def main():
d_lith = 150.e3
rho_crust = 2900.
d_sigma = 45.e3
lmax_hydro = 50
model_name = ['DWThot', 'DWThotCrust1', 'DWThotCrust1r', 'EH45Tcold',
'EH45TcoldCrust1', 'EH45TcoldCrust1r', 'EH45ThotCrust2',
'EH45ThotCrust2r', 'LFAK', 'SANAK', 'TAYAK', 'DWAK',
'ZG_DW']
spec = 'Data/Mars-reference-interior-models/Smrekar/'
interior_file = [spec + name + '.deck' for name in model_name]
potential = pysh.datasets.Mars.GMM3()
omega = pysh.constants.Mars.angular_velocity.value
potential.omega = omega
mass_mars = np.float64(potential.mass)
try:
os.mkdir('figs')
except Exception:
pass
print('Gravity file = {:s}'.format('GMM3'))
print('Lmax of potential coefficients = {:d}'.format(potential.lmax))
print('Reference radius (km) = {:f}'.format(potential.r0 / 1.e3))
print('GM = {:e}'.format(potential.gm))
print('Mass = {:e}'.format(potential.mass))
print('Omega = {:e}'.format(potential.omega))
lmax_calc = 90
lmax = 359
model = 10
topo = pysh.datasets.Mars.MOLA_shape(lmax=lmax)
topo.r0 = topo.coeffs[0, 0, 0]
r_mars = topo.coeffs[0, 0, 0]
print('Topography file = {:s}'.format('MOLA_shape'))
print('Lmax of topography coefficients = {:d}'.format(topo.lmax))
print('Reference radius (km) = {:f}\n'.format(topo.r0 / 1.e3))
# --- Make geoid map, expand in spherical harmonics
# --- and then remove degree-0 term, for plotting purposes only.
u0 = potential.gm/potential.r0
geoid = potential.geoid(u0, r=topo.r0, order=2, lmax_calc=lmax_calc,
lmax=lmax)
geoidsh = geoid.geoid.expand()
geoidsh.coeffs[0, 0, 0] = 0.
geoid = geoidsh.expand(grid='DH2')
# --- read 1D reference interior model ---
radius, rho, i_crust, i_core, i_lith = ReadRefModel(interior_file[model],
depth=d_lith)
# rho_mantle = rho[i_crust-1]
# rho_core = rho[i_core-1]
n = len(radius)-1
# r0_model = radius[n]
# --- Compute purely hydrostatic relief of all interfaces ---
print('\n=== Fluid planet ===')
if False:
for i in range(1, n+1):
hlm_fluid, clm_fluid, mass_model = HydrostaticShape(
radius, rho, omega, potential.gm, potential.r0, i_clm_hydro=i)
print('i = {:d}, r = {:f}, rho = {:f}, %C20 = {:f}'
.format(i, radius[i], rho[i], clm_fluid.coeffs[0, 2, 0] /
potential.coeffs[0, 2, 0] * 100))
hlm_fluid, clm_fluid, mass_model = \
HydrostaticShape(radius, rho, omega, potential.gm, potential.r0)
print('--- Hydrostatic relief of surface for a fluid planet ---')
print('h20 = {:e}\n'.format(hlm_fluid[n].coeffs[0, 2, 0]) +
'h40 = {:e}'.format(hlm_fluid[n].coeffs[0, 4, 0]))
hydro_surface = hlm_fluid[n].expand()
print('Elevation difference between pole and equator (km)'
' {:e}'.format(hydro_surface.max()/1.e3 - hydro_surface.min()/1.e3))
print('--- Hydrostatic relief of core-mantle boundary for a fluid planet '
'---')
print('h20 = {:e}\n'.format(hlm_fluid[i_core].coeffs[0, 2, 0]) +
'h40 = {:e}'.format(hlm_fluid[i_core].coeffs[0, 4, 0]))
print('Moments of hydrostatic core')
II, AA, BB, CC, mass, RR, vec = InertiaTensor_from_shape(hlm_fluid, rho,
i_core,
quiet=True)
print('I = ', II)
print('A, B, C = ', AA, BB, CC)
print('A, B, C / (mass_mars r0^2) = ', (AA, BB, CC) / mass_mars /
r_mars**2)
print('mass of core (kg) = ', mass)
print('R core (m) = ', RR)
print('Moments of hydrostatic planet')
II, AA, BB, CC, mass, RR, vec = InertiaTensor_from_shape(hlm_fluid, rho, n,
quiet=True)
print('I = ', II)
print('A, B, C = ', AA, BB, CC)
print('A, B, C / (mass_mars r0^2) = ', (AA, BB, CC) / mass_mars /
r_mars**2)
print('mass of planet (kg) = ', mass)
print('R surface (m) = ', RR)
# --- Compute relief along hydrostatic interfaces with a lithosphere ---
print('\n=== Planet with a lithosphere ===')
r_sigma = topo.r0 - d_sigma
hlm, clm_hydro, mass_model = \
HydrostaticShapeLith(radius, rho, i_lith, potential, topo, rho_crust,
r_sigma, omega, lmax_hydro)
print('--- Core shape, with lithosphere ---')
for l in range(0, 5):
for m in range(0, l+1):
print(l, m, hlm[i_core].coeffs[0, l, m],
hlm[i_core].coeffs[1, l, m], )
print('Max and min of degree-1 core shape =',
hlm[i_core].expand(lmax=1).max(),
hlm[i_core].expand(lmax=1).min())
II, AA, BB, CC, mass, RR, vec = InertiaTensor_from_shape(hlm, rho, i_core,
quiet=True)
print('I = ', II)
print('A, B, C = ', AA, BB, CC)
print('A, B, C / (mass_mars r0^2) = ', (AA, BB, CC) / mass_mars /
r_mars**2)
print('mass of core (kg) = ', mass)
print('R core (m) = ', RR)
# --- Calculate relief, with respect to hydrostatic solution ---
# --- at i_lith and i_core
print('\n=== Difference between fluid planet and planet with a '
'lithosphere ===')
diff_ilith = hlm[i_lith] - hlm_fluid[i_lith].pad(lmax=lmax_hydro)
grid_ilith = diff_ilith.expand()
print('Maximum and minimum difference at i_lith (km) =- ',
grid_ilith.max()/1.e3, grid_ilith.min()/1.e3)
diff_icore = hlm[i_core] - hlm_fluid[i_core].pad(lmax=lmax_hydro)
grid_icore = diff_icore.expand()
print('Maximum and minimum difference at i_core (km) =- ',
grid_icore.max()/1.e3, grid_icore.min()/1.e3)
# ---- Write data to files ---
print('\n=== Output gridded data for use with GMT ===')
print('Output grid sizes = ', geoid.nlat, geoid.nlon)
(geoid/1000).to_file('figs/Mars_geoid.dat')
diff = (geoid - hlm_fluid[n].pad(lmax=lmax).expand(grid='DH2')
+ radius[n])
(diff/1000).to_file('figs/Mars_geoid_diff.dat')
diff = hlm[i_lith].pad(lmax=lmax).expand(grid='DH2') - radius[i_lith]
(diff/1000).to_file('figs/hydro_ilith.dat')
diff = hlm[i_core].pad(lmax=lmax).expand(grid='DH2') - radius[i_core]
(diff/1000).to_file('figs/hydro_icore.dat')
diff = hlm[i_lith] - hlm_fluid[i_lith].pad(lmax=lmax_hydro)
(diff.expand(grid='DH2', lmax=lmax)/1000).to_file(
'figs/hydro_ilith_diff.dat')
diff = hlm[i_core] - hlm_fluid[i_core].pad(lmax=lmax_hydro)
(diff.expand(grid='DH2', lmax=lmax)/1000).to_file(
'figs/hydro_icore_diff.dat')
# Sensitivity tests
print('\n=== Sensitivity tests ===')
r_sigma = topo.r0
hlm2, clm_hydro2, mass_model2 = \
HydrostaticShapeLith(radius, rho, i_lith, potential, topo, rho_crust,
r_sigma, omega, lmax_hydro)
print('d_sigma = 0')
print('Minimum and maximum differences at i_lith (m) = ',
(hlm2[i_lith] - hlm[i_lith]).expand().min(),
(hlm2[i_lith] - hlm[i_lith]).expand().max())
print('Minimum and maximum differences at i_core (m) = ',
(hlm2[i_core] - hlm[i_core]).expand().min(),
(hlm2[i_core] - hlm[i_core]).expand().max())
r_sigma = topo.r0 - 100.e3
hlm2, clm_hydro2, mass_model2 = \
HydrostaticShapeLith(radius, rho, i_lith, potential, topo, rho_crust,
r_sigma, omega, lmax_hydro)
print('d_sigma = 100 km')
print('Minimum and maximum differences at i_lith (m) = ',
(hlm2[i_lith] - hlm[i_lith]).expand().min(),
(hlm2[i_lith] - hlm[i_lith]).expand().max())
print('Minimum and maximum differences at i_core (m) = ',
(hlm2[i_core] - hlm[i_core]).expand().min(),
(hlm2[i_core] - hlm[i_core]).expand().max())
r_sigma = topo.r0 - d_sigma
hlm2, clm_hydro2, mass_model2 = \
HydrostaticShapeLith(radius, rho, i_lith, potential, topo, 2500.,
r_sigma, omega, lmax_hydro)
print('rho = 2500 kg / m3')
print('Minimum and maximum differences at i_lith (m) = ',
(hlm2[i_lith] - hlm[i_lith]).expand().min(),
(hlm2[i_lith] - hlm[i_lith]).expand().max())
print('Minimum and maximum differences at i_core (m) = ',
(hlm2[i_core] - hlm[i_core]).expand().min(),
(hlm2[i_core] - hlm[i_core]).expand().max())
r_sigma = topo.r0 - d_sigma
hlm2, clm_hydro2, mass_model2 = \
HydrostaticShapeLith(radius, rho, i_lith, potential, topo, 3300.,
r_sigma, omega, lmax_hydro)
print('rho = 3300 kg / m3')
print('Minimum and maximum differences at i_lith (m) = ',
(hlm2[i_lith] - hlm[i_lith]).expand().min(),
(hlm2[i_lith] - hlm[i_lith]).expand().max())
print('Minimum and maximum differences at i_core (m) = ',
(hlm2[i_core] - hlm[i_core]).expand().min(),
(hlm2[i_core] - hlm[i_core]).expand().max())
# ==== EXECUTE SCRIPT ====
if __name__ == "__main__":
main()
Create images related to Mars in Wieczorek et al. (2019).
Mars-j2.py
#!/usr/bin/env python3
"""
Mars-j2
Compute the contribution to the gravitational J2 of Mars from hydrostatic
interfaces beneath the lithosphere.
"""
import numpy as np
import pyshtools as pysh
from ctplanet import HydrostaticShapeLith
# ==== MAIN FUNCTION ====
def main():
d_lith = 150.e3
rho_crust = 2900.
d_sigma = 45.e3
lmax_hydro = 2
potential = pysh.datasets.Mars.GMM3()
omega = pysh.constants.Mars.angular_velocity.value
potential.omega = omega
print('Gravity file = {:s}'.format('GMM3'))
print('Lmax of potential coefficients = {:d}'.format(potential.lmax))
print('Reference radius (km) = {:f}'.format(potential.r0 / 1.e3))
print('GM = {:e}'.format(potential.gm))
print('Mass = {:e}'.format(potential.mass))
print('Omega = {:e}'.format(potential.omega))
lmax = 359
topo = pysh.datasets.Mars.MOLA_shape(lmax=lmax)
topo.r0 = topo.coeffs[0, 0, 0]
print('Topography file = {:s}'.format('MOLA_shape'))
print('Lmax of topography coefficients = {:d}'.format(topo.lmax))
print('Reference radius (km) = {:f}\n'.format(topo.r0 / 1.e3))
# --- read 1D reference interior model ---
model_name = ['DWThot', 'DWThotCrust1', 'DWThotCrust1r', 'EH45Tcold',
'EH45TcoldCrust1', 'EH45TcoldCrust1r', 'EH45ThotCrust2',
'EH45ThotCrust2r', 'LFAK', 'SANAK', 'TAYAK', 'DWAK',
'ZG_DW']
spec = 'Data/Mars-reference-interior-models/Smrekar/'
interior_file = [spec + name + '.deck' for name in model_name]
for file in interior_file:
print('=== Reading model {:s} ==='.format(file))
with open(file, 'r') as f:
lines = f.readlines()
print(lines[0].strip())
data = lines[1].split()
if float(data[2]) != 1:
raise RuntimeError('Program not capable of reading '
'polynomial files')
num_file = int(lines[2].split()[0])
crust_index_file = int(lines[2].split()[3])
core_index_file = int(lines[2].split()[2])
i_crust_file = crust_index_file - 1
i_core_file = core_index_file - 1
radius = np.zeros(num_file)
rho = np.zeros(num_file)
num = 0
for i in range(0, num_file-1):
data = lines[i+3].split()
rb = float(data[0])
rhob = float(data[1])
data = lines[i+4].split()
rt = float(data[0])
rhot = float(data[1])
if rb == rt:
if i == i_core_file:
i_core = num
if i == i_crust_file:
i_crust = num
else:
radius[num] = rb
rho[num] = (rhot + rhob) / 2.
num += 1
radius[num] = rt
rho[num] = 0. # the density above the surface is zero
num += 1
n = num - 1
radius = radius[:n+1]
rho = rho[:n+1]
r0_model = radius[n]
print('Surface radius of model (km) = {:f}'
.format(r0_model / 1.e3))
for i in range(0, n+1):
if radius[i] <= (r0_model - d_lith) and \
radius[i+1] > (r0_model - d_lith):
if radius[i] == (r0_model - d_lith):
i_lith = i
elif (r0_model - d_lith) - radius[i] <= radius[i+1] -\
(r0_model - d_lith):
i_lith = i
else:
i_lith = i + 1
break
rho_mantle = rho[i_crust-1]
rho_core = rho[i_core-1]
print('Mantle density (kg/m3) = {:f}'.format(rho_mantle))
print('Mantle radius (km) = {:f}'.format(radius[i_crust]/1.e3))
print('Core density (kg/m3) = {:f}'.format(rho_core))
print('Core radius (km) = {:f}'.format(radius[i_core]/1.e3))
print('Assumed depth of lithosphere (km) = {:f}'
.format(d_lith / 1.e3))
print('Actual depth of lithosphere in discretized '
'model (km) = {:f}'
.format((r0_model - radius[i_lith]) / 1.e3))
r_sigma = topo.r0 - d_sigma
hlm, clm_hydro, mass_model = \
HydrostaticShapeLith(radius, rho, i_lith, potential, topo,
rho_crust, r_sigma, omega, lmax_hydro)
print('Percentage of h20 derived from hydrostatic mantle = '
'{:f}'.format(clm_hydro.coeffs[0, 2, 0] /
potential.coeffs[0, 2, 0]*100))
# ==== EXECUTE SCRIPT ====
if __name__ == "__main__":
main()
Compute the contribution to the gravitational J2 of Mars from hydrostatic interfaces beneath the lithosphere.
Earth#
Earth-shape.py
#!/usr/bin/env python3
"""
Earth-shape
Compute hydrostatic shape of Earth using PREM.
"""
import numpy as np
import pyshtools as pysh
from ctplanet import HydrostaticShape
# ==== MAIN FUNCTION ====
def main():
model_name = ['PREM.dat']
spec = 'Data/'
interior_file = [spec + name for name in model_name]
r_ref = pysh.constants.Earth.wgs84.a.value
gm = pysh.constants.Earth.wgs84.gm.value
mass = gm / pysh.constants.G.value
omega = pysh.constants.Earth.wgs84.omega.value
print('Reference radius (km) = {:f}'.format(r_ref / 1.e3))
print('GM = {:e}'.format(gm))
print('Mass = {:e}'.format(mass))
print('Omega = {:e}'.format(omega))
model = 0
# --- read 1D reference interior model ---
print('=== Reading model {:s} ==='.format(model_name[model]))
with open(interior_file[model], 'r') as f:
lines = f.readlines()
print(lines[0].strip())
data = lines[1].split()
if float(data[2]) != 1:
raise RuntimeError('Program not capable of reading polynomial ' +
'files')
num = int(lines[2].split()[0])
crust_index = int(lines[2].split()[3])
# mantle_index = int(lines[2].split()[3])
radius = np.zeros(num)
rho = np.zeros(num)
for i in range(0, num):
data = lines[i+3].split()
radius[i] = float(data[0])
rho[i] = float(data[1])
r0_model = radius[num-1]
print('Surface radius of model (km) = {:f}'.format(r0_model / 1.e3))
n = num - 1
rho[n] = 0. # the density above the surface is zero
rho_mantle = rho[crust_index-1]
print('Mantle density (kg/m3) = {:f}'.format(rho_mantle))
# --- Compute gravity contribution from hydrostatic density interfaces ---
hlm_fluid, clm_fluid, mass_model = HydrostaticShape(radius, rho, omega,
gm, r_ref)
hlm_surf_unnorm = hlm_fluid[n].convert(normalization='unnorm')
print('--- Hydrostatic relief of surface ---')
print('h20 = {:e}\n'.format(hlm_fluid[n].coeffs[0, 2, 0]) +
'h40 = {:e}'.format(hlm_fluid[n].coeffs[0, 4, 0]))
print('h20 (unnorm)= {:e}\n'
.format(hlm_surf_unnorm.coeffs[0, 2, 0]/r0_model) +
'h40 (unnorm)= {:e}'
.format(hlm_surf_unnorm.coeffs[0, 4, 0]/r0_model))
print(mass, mass_model)
# ==== EXECUTE SCRIPT ====
if __name__ == "__main__":
main()
Compute hydrostatic relief of Earth using PREM.
Ceres#
Ceres-shape.py
#!/usr/bin/env python3
"""
Ceres-shape
Calculate the hydrostatic shape of Ceres, as in Wieczorek et al. (2019).
"""
import numpy as np
import pyshtools
from ctplanet import HydrostaticShape
# ==== MAIN FUNCTION ====
def main():
# Thomas et al. 2005
mass = 9.395e20
gm = mass * pyshtools.constants.G.value
r0 = 476.2e3
omega = 2 * np.pi / (9.076 * 60 * 60)
volume = 4 * np.pi / 3 * r0**3
lmax = 4
# Model C1
radius = np.ndarray(2)
radius[0] = 0.
radius[1] = r0
rho = np.ndarray(2)
rho[0] = mass / volume
rho[1] = 0
print(rho[0])
hlm, clm, mass_model = HydrostaticShape(radius, rho, omega, gm, r0)
a = hlm[1].expand(lat=0., lon=0., lmax_calc=lmax)
b = hlm[1].expand(lat=0., lon=90., lmax_calc=lmax)
c = hlm[1].expand(lat=90., lon=0., lmax_calc=lmax)
print(a, b, c, a-c)
# ==== EXECUTE SCRIPT ====
if __name__ == "__main__":
main()
Calculate the hydrostatic shape of Ceres.