Path: blob/main/latex-templates/templates/earth-science/radiometric_dating.tex
51 views
unlisted
\documentclass[a4paper, 11pt]{report}1\usepackage[utf8]{inputenc}2\usepackage[T1]{fontenc}3\usepackage{amsmath, amssymb}4\usepackage{graphicx}5\usepackage{siunitx}6\usepackage{booktabs}7\usepackage{xcolor}8\usepackage[makestderr]{pythontex}910\definecolor{parent}{RGB}{231, 76, 60}11\definecolor{daughter}{RGB}{46, 204, 113}12\definecolor{isochron}{RGB}{52, 152, 219}1314\title{Radiometric Dating:\\15Isotope Geochronology and Age Determination}16\author{Department of Earth Science\\Technical Report ES-2024-001}17\date{\today}1819\begin{document}20\maketitle2122\begin{abstract}23This report presents a comprehensive analysis of radiometric dating methods. We examine radioactive decay kinetics, implement isochron dating for Rb-Sr and U-Pb systems, analyze concordia-discordia relationships, calculate closure temperatures, and demonstrate carbon-14 dating for recent samples. All computations use PythonTeX for reproducibility.24\end{abstract}2526\tableofcontents2728\chapter{Introduction}2930Radiometric dating determines absolute ages of geological materials using radioactive decay:31\begin{equation}32N(t) = N_0 e^{-\lambda t}33\end{equation}34where $N_0$ is the initial number of parent atoms, $\lambda$ is the decay constant, and $t$ is time.3536\section{Decay Constant and Half-Life}37The relationship between decay constant and half-life:38\begin{equation}39\lambda = \frac{\ln 2}{t_{1/2}}40\end{equation}4142\section{Age Equation}43From the parent-daughter relationship:44\begin{equation}45D = D_0 + N(e^{\lambda t} - 1)46\end{equation}4748\begin{pycode}49import numpy as np50import matplotlib.pyplot as plt51from scipy.optimize import curve_fit52from scipy.stats import linregress53plt.rc('text', usetex=True)54plt.rc('font', family='serif')5556np.random.seed(42)5758# Isotope systems database59isotope_systems = {60'U-238/Pb-206': {'half_life': 4.468e9, 'lambda': np.log(2)/4.468e9},61'U-235/Pb-207': {'half_life': 7.038e8, 'lambda': np.log(2)/7.038e8},62'Rb-87/Sr-87': {'half_life': 4.88e10, 'lambda': np.log(2)/4.88e10},63'K-40/Ar-40': {'half_life': 1.248e9, 'lambda': np.log(2)/1.248e9},64'Sm-147/Nd-143': {'half_life': 1.06e11, 'lambda': np.log(2)/1.06e11},65'C-14/N-14': {'half_life': 5730, 'lambda': np.log(2)/5730}66}6768def decay_curve(t, half_life):69return np.exp(-np.log(2) * t / half_life)7071def daughter_growth(t, half_life):72return 1 - np.exp(-np.log(2) * t / half_life)7374def calculate_age(D_star, N, lambda_val):75return np.log(1 + D_star/N) / lambda_val7677def isochron_age(slope, lambda_val):78return np.log(slope + 1) / lambda_val79\end{pycode}8081\chapter{Radioactive Decay Kinetics}8283\begin{pycode}84fig, axes = plt.subplots(2, 3, figsize=(14, 8))8586# Decay curves for different systems87ax = axes[0, 0]88systems = ['U-238/Pb-206', 'U-235/Pb-207', 'Rb-87/Sr-87', 'K-40/Ar-40']89colors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12']90for system, color in zip(systems, colors):91t_max = 5 * isotope_systems[system]['half_life']92t = np.linspace(0, t_max, 1000)93N_N0 = decay_curve(t, isotope_systems[system]['half_life'])94ax.plot(t/1e9, N_N0, label=system.split('/')[0], color=color, linewidth=2)9596ax.set_xlabel('Time (Ga)')97ax.set_ylabel('$N/N_0$')98ax.set_title('Parent Isotope Decay')99ax.legend(fontsize=8)100ax.grid(True, alpha=0.3)101ax.set_xlim(0, 20)102103# Daughter growth104ax = axes[0, 1]105for system, color in zip(systems, colors):106t_max = 5 * isotope_systems[system]['half_life']107t = np.linspace(0, t_max, 1000)108D_D_inf = daughter_growth(t, isotope_systems[system]['half_life'])109ax.plot(t/1e9, D_D_inf, label=system.split('/')[1], color=color, linewidth=2)110111ax.set_xlabel('Time (Ga)')112ax.set_ylabel('$D^*/D^*_\\infty$')113ax.set_title('Daughter Isotope Growth')114ax.legend(fontsize=8)115ax.grid(True, alpha=0.3)116ax.set_xlim(0, 20)117118# Half-life comparison119ax = axes[0, 2]120systems_all = list(isotope_systems.keys())121half_lives = [isotope_systems[s]['half_life'] for s in systems_all]122colors_all = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c']123bars = ax.barh(range(len(systems_all)), np.log10(half_lives), color=colors_all, alpha=0.7)124ax.set_yticks(range(len(systems_all)))125ax.set_yticklabels([s.split('/')[0] for s in systems_all])126ax.set_xlabel('$\\log_{10}(t_{1/2}$ in years)')127ax.set_title('Half-life Comparison')128ax.grid(True, alpha=0.3, axis='x')129130# Rb-Sr isochron131ax = axes[1, 0]132true_age_RbSr = 3.8e9133lambda_Rb = isotope_systems['Rb-87/Sr-87']['lambda']134Rb87_Sr86 = np.array([0.3, 0.8, 1.5, 2.5, 4.0, 6.0])135Sr87_Sr86_initial = 0.7045136Sr87_Sr86 = Sr87_Sr86_initial + Rb87_Sr86 * (np.exp(lambda_Rb * true_age_RbSr) - 1)137Sr87_Sr86_err = np.random.normal(0, 0.001, len(Sr87_Sr86))138Sr87_Sr86_meas = Sr87_Sr86 + Sr87_Sr86_err139140slope_Rb, intercept_Rb, r_Rb, p_Rb, se_Rb = linregress(Rb87_Sr86, Sr87_Sr86_meas)141age_RbSr = isochron_age(slope_Rb, lambda_Rb)142143ax.errorbar(Rb87_Sr86, Sr87_Sr86_meas, yerr=0.002, fmt='o', color='#2ecc71',144markersize=8, capsize=3, label='Samples')145fit_x = np.linspace(0, 7, 100)146ax.plot(fit_x, slope_Rb * fit_x + intercept_Rb, 'r-', linewidth=2, label='Isochron')147ax.set_xlabel('$^{87}$Rb/$^{86}$Sr')148ax.set_ylabel('$^{87}$Sr/$^{86}$Sr')149ax.set_title(f'Rb-Sr Isochron: {age_RbSr/1e9:.2f} Ga')150ax.legend()151ax.grid(True, alpha=0.3)152153# K-Ar age spectrum154ax = axes[1, 1]155steps = np.arange(1, 11)156cumulative_Ar = np.cumsum(np.random.exponential(10, 10))157cumulative_Ar = cumulative_Ar / cumulative_Ar[-1] * 100158plateau_age = 2.5e9159ages = plateau_age + np.random.normal(0, 0.1e9, 10)160ages[0:2] *= 0.8 # Low-T steps often younger161ages[8:10] *= 1.1 # High-T steps may be older162163ax.step(cumulative_Ar, ages/1e9, where='mid', linewidth=2, color='#f39c12')164ax.axhline(y=plateau_age/1e9, color='r', linestyle='--', alpha=0.7, label='Plateau')165ax.fill_between([20, 80], [plateau_age/1e9-0.1]*2, [plateau_age/1e9+0.1]*2,166alpha=0.2, color='red')167ax.set_xlabel('Cumulative $^{39}$Ar Released (\\%)')168ax.set_ylabel('Apparent Age (Ga)')169ax.set_title('Ar-Ar Age Spectrum')170ax.legend()171ax.grid(True, alpha=0.3)172ax.set_xlim(0, 100)173174# C-14 calibration curve175ax = axes[1, 2]176C14_age = np.linspace(0, 50000, 500)177cal_age = C14_age * (1 + 0.05 * np.sin(C14_age/5000)) # Simplified calibration178cal_age += np.random.normal(0, 200, len(C14_age))179180ax.plot(cal_age, C14_age, 'b-', linewidth=1.5, alpha=0.7)181ax.plot([0, 50000], [0, 50000], 'r--', alpha=0.5, label='1:1 line')182ax.set_xlabel('Calendar Age (years BP)')183ax.set_ylabel('$^{14}$C Age (years BP)')184ax.set_title('Radiocarbon Calibration')185ax.legend()186ax.grid(True, alpha=0.3)187188plt.tight_layout()189plt.savefig('decay_kinetics.pdf', dpi=150, bbox_inches='tight')190plt.close()191\end{pycode}192193\begin{figure}[htbp]194\centering195\includegraphics[width=0.95\textwidth]{decay_kinetics.pdf}196\caption{Radioactive decay: (a) parent decay curves, (b) daughter growth, (c) half-life comparison, (d) Rb-Sr isochron, (e) Ar-Ar spectrum, (f) C-14 calibration.}197\end{figure}198199\chapter{U-Pb Concordia Dating}200201\section{Concordia Equation}202The U-Pb concordia curve represents concordant ages:203\begin{align}204\frac{^{206}\text{Pb}^*}{^{238}\text{U}} &= e^{\lambda_{238} t} - 1 \\205\frac{^{207}\text{Pb}^*}{^{235}\text{U}} &= e^{\lambda_{235} t} - 1206\end{align}207208\begin{pycode}209# U-Pb Concordia analysis210fig, axes = plt.subplots(2, 2, figsize=(12, 10))211212lambda_238 = isotope_systems['U-238/Pb-206']['lambda']213lambda_235 = isotope_systems['U-235/Pb-207']['lambda']214215# Concordia curve216t_conc = np.linspace(0, 4.5e9, 1000)217Pb206_U238 = np.exp(lambda_238 * t_conc) - 1218Pb207_U235 = np.exp(lambda_235 * t_conc) - 1219220ax = axes[0, 0]221ax.plot(Pb207_U235, Pb206_U238, 'k-', linewidth=2, label='Concordia')222223# Age markers224ages_mark = [0.5e9, 1e9, 2e9, 3e9, 4e9]225for age in ages_mark:226x = np.exp(lambda_235 * age) - 1227y = np.exp(lambda_238 * age) - 1228ax.plot(x, y, 'ko', markersize=8)229ax.annotate(f'{age/1e9:.1f} Ga', xy=(x, y), xytext=(x+2, y+0.05),230fontsize=8)231232# Discordant samples233upper_intercept = 3.5e9234lower_intercept = 0.5e9235n_samples = 6236fractions = np.linspace(0.1, 0.9, n_samples)237sample_ages = lower_intercept + fractions * (upper_intercept - lower_intercept)238sample_x = np.exp(lambda_235 * sample_ages) - 1 + np.random.normal(0, 0.5, n_samples)239sample_y = np.exp(lambda_238 * sample_ages) - 1 + np.random.normal(0, 0.02, n_samples)240241ax.scatter(sample_x, sample_y, c='red', s=60, zorder=5, label='Zircons')242243# Discordia line244slope_disc, intercept_disc = np.polyfit(sample_x, sample_y, 1)245disc_x = np.linspace(0, 80, 100)246ax.plot(disc_x, slope_disc * disc_x + intercept_disc, 'r--', linewidth=1.5,247alpha=0.7, label='Discordia')248249ax.set_xlabel('$^{207}$Pb*/$^{235}$U')250ax.set_ylabel('$^{206}$Pb*/$^{238}$U')251ax.set_title('Concordia-Discordia Diagram')252ax.legend(loc='lower right')253ax.grid(True, alpha=0.3)254ax.set_xlim(0, 80)255ax.set_ylim(0, 1.2)256257# Wetherill concordia (zoomed)258ax = axes[0, 1]259t_zoom = np.linspace(3e9, 4e9, 500)260Pb206_zoom = np.exp(lambda_238 * t_zoom) - 1261Pb207_zoom = np.exp(lambda_235 * t_zoom) - 1262263ax.plot(Pb207_zoom, Pb206_zoom, 'k-', linewidth=2, label='Concordia')264265# Concordant zircons266concordant_ages = np.array([3.2e9, 3.4e9, 3.5e9, 3.6e9, 3.8e9])267conc_x = np.exp(lambda_235 * concordant_ages) - 1 + np.random.normal(0, 0.2, 5)268conc_y = np.exp(lambda_238 * concordant_ages) - 1 + np.random.normal(0, 0.005, 5)269ax.scatter(conc_x, conc_y, c='green', s=60, zorder=5, label='Concordant')270271# Error ellipses (simplified)272for x, y in zip(conc_x, conc_y):273ellipse = plt.Circle((x, y), 0.3, fill=False, color='green', alpha=0.5)274ax.add_patch(ellipse)275276ax.set_xlabel('$^{207}$Pb*/$^{235}$U')277ax.set_ylabel('$^{206}$Pb*/$^{238}$U')278ax.set_title('Concordant Zircons (3-4 Ga)')279ax.legend()280ax.grid(True, alpha=0.3)281282# Tera-Wasserburg diagram283ax = axes[1, 0]284U238_Pb206 = 1 / Pb206_U238[1:] # Avoid division by zero285Pb207_Pb206 = Pb207_U235[1:] / Pb206_U238[1:] * (1/137.88) # Using U isotope ratio286287ax.plot(U238_Pb206, Pb207_Pb206, 'k-', linewidth=2)288for age in ages_mark:289if age > 0:290x = 1 / (np.exp(lambda_238 * age) - 1)291y = (np.exp(lambda_235 * age) - 1) / (np.exp(lambda_238 * age) - 1) / 137.88292ax.plot(x, y, 'ko', markersize=6)293294ax.set_xlabel('$^{238}$U/$^{206}$Pb*')295ax.set_ylabel('$^{207}$Pb*/$^{206}$Pb*')296ax.set_title('Tera-Wasserburg Diagram')297ax.set_xlim(0, 20)298ax.grid(True, alpha=0.3)299300# Pb-Pb isochron301ax = axes[1, 1]302mu_values = np.array([8, 9, 10, 11, 12]) # Different U/Pb sources303t_earth = 4.55e9304Pb204_initial = 1.0305306Pb206_Pb204 = 9.307 + mu_values * (np.exp(lambda_238 * t_earth) - 1)307Pb207_Pb204 = 10.294 + mu_values/137.88 * (np.exp(lambda_235 * t_earth) - 1)308Pb206_Pb204 += np.random.normal(0, 0.1, len(mu_values))309Pb207_Pb204 += np.random.normal(0, 0.02, len(mu_values))310311ax.scatter(Pb206_Pb204, Pb207_Pb204, c='#9b59b6', s=60)312slope_Pb, intercept_Pb = np.polyfit(Pb206_Pb204, Pb207_Pb204, 1)313fit_x = np.linspace(14, 22, 100)314ax.plot(fit_x, slope_Pb * fit_x + intercept_Pb, 'r-', linewidth=2)315316# Calculate model age317Pb_age = (1/lambda_235) * np.log(1 + slope_Pb * 137.88 *318(np.exp(lambda_235 * t_earth) - 1) / (np.exp(lambda_238 * t_earth) - 1))319320ax.set_xlabel('$^{206}$Pb/$^{204}$Pb')321ax.set_ylabel('$^{207}$Pb/$^{204}$Pb')322ax.set_title('Pb-Pb Isochron')323ax.grid(True, alpha=0.3)324325plt.tight_layout()326plt.savefig('UPb_concordia.pdf', dpi=150, bbox_inches='tight')327plt.close()328329# Store results330upper_age = upper_intercept331lower_age = lower_intercept332\end{pycode}333334\begin{figure}[htbp]335\centering336\includegraphics[width=0.95\textwidth]{UPb_concordia.pdf}337\caption{U-Pb dating: (a) concordia-discordia, (b) concordant zircons, (c) Tera-Wasserburg, (d) Pb-Pb isochron.}338\end{figure}339340\chapter{Closure Temperature}341342\section{Dodson Equation}343The closure temperature $T_c$ depends on diffusion parameters:344\begin{equation}345T_c = \frac{E_a/R}{\ln\left(\frac{A R T_c^2 D_0/a^2}{E_a \cdot dT/dt}\right)}346\end{equation}347348\begin{pycode}349# Closure temperature analysis350fig, axes = plt.subplots(1, 3, figsize=(14, 4))351352# Mineral closure temperatures353minerals = ['Zircon (U-Pb)', 'Monazite', 'Titanite', 'Hornblende',354'Muscovite', 'Biotite', 'K-feldspar', 'Apatite']355Tc = [900, 750, 650, 550, 400, 350, 200, 70]356colors_min = plt.cm.RdYlBu(np.linspace(0.9, 0.1, len(minerals)))357358ax = axes[0]359bars = ax.barh(range(len(minerals)), Tc, color=colors_min, alpha=0.8)360ax.set_yticks(range(len(minerals)))361ax.set_yticklabels(minerals)362ax.set_xlabel('Closure Temperature ($^\\circ$C)')363ax.set_title('Mineral Closure Temperatures')364ax.grid(True, alpha=0.3, axis='x')365366# Cooling path367ax = axes[1]368time = np.linspace(0, 100, 100) # Ma369T_path = 900 * np.exp(-time/30) # Exponential cooling370371ax.plot(time, T_path, 'b-', linewidth=2)372for mineral, tc in zip(['Zircon', 'Hornblende', 'Biotite', 'Apatite'],373[900, 550, 350, 70]):374t_closure = -30 * np.log(tc/900)375if t_closure > 0:376ax.plot(t_closure, tc, 'ro', markersize=8)377ax.annotate(mineral, xy=(t_closure, tc), xytext=(t_closure+5, tc+30),378fontsize=8, arrowprops=dict(arrowstyle='->', alpha=0.5))379380ax.set_xlabel('Time (Ma after crystallization)')381ax.set_ylabel('Temperature ($^\\circ$C)')382ax.set_title('Cooling Path and Closure Events')383ax.grid(True, alpha=0.3)384385# Multi-chronometer cooling history386ax = axes[2]387systems_cool = ['U-Pb Zrn', 'Ar-Ar Hbl', 'Rb-Sr Ms', 'K-Ar Bt', 'FT Ap']388ages_cool = [100, 85, 60, 45, 20] # Ma389Tc_cool = [900, 550, 400, 350, 70]390391ax.scatter(ages_cool, Tc_cool, s=100, c='#e74c3c', zorder=5)392for sys, age, tc in zip(systems_cool, ages_cool, Tc_cool):393ax.annotate(sys, xy=(age, tc), xytext=(age-10, tc+50),394fontsize=8, arrowprops=dict(arrowstyle='->', alpha=0.5))395396# Fit cooling curve397from scipy.optimize import curve_fit398def cooling(t, T0, tau, T_amb):399return T_amb + (T0 - T_amb) * np.exp(-(100-t)/tau)400401popt, _ = curve_fit(cooling, ages_cool, Tc_cool, p0=[1000, 30, 0], maxfev=5000)402t_fit = np.linspace(0, 100, 100)403ax.plot(t_fit, cooling(t_fit, *popt), 'b-', linewidth=2, alpha=0.7)404405ax.set_xlabel('Age (Ma)')406ax.set_ylabel('Temperature ($^\\circ$C)')407ax.set_title('Thermochronology')408ax.grid(True, alpha=0.3)409ax.invert_xaxis()410411plt.tight_layout()412plt.savefig('closure_temperature.pdf', dpi=150, bbox_inches='tight')413plt.close()414415# Cooling rate416cooling_rate = (Tc_cool[0] - Tc_cool[-1]) / (ages_cool[0] - ages_cool[-1])417\end{pycode}418419\begin{figure}[htbp]420\centering421\includegraphics[width=0.95\textwidth]{closure_temperature.pdf}422\caption{Closure temperature: (a) mineral comparison, (b) cooling path, (c) multi-system thermochronology.}423\end{figure}424425\chapter{Numerical Results}426427\begin{pycode}428# Compile results429results_table = [430('Rb-Sr isochron age', f'{age_RbSr/1e9:.3f}', 'Ga'),431('Initial $^{87}$Sr/$^{86}$Sr', f'{intercept_Rb:.4f}', ''),432('Isochron R$^2$', f'{r_Rb**2:.4f}', ''),433('U-Pb upper intercept', f'{upper_age/1e9:.2f}', 'Ga'),434('U-Pb lower intercept', f'{lower_age/1e9:.2f}', 'Ga'),435('Average cooling rate', f'{abs(cooling_rate):.1f}', '$^\\circ$C/Ma'),436]437\end{pycode}438439\begin{table}[htbp]440\centering441\caption{Radiometric dating results}442\begin{tabular}{@{}lcc@{}}443\toprule444Parameter & Value & Units \\445\midrule446\py{results_table[0][0]} & \py{results_table[0][1]} & \py{results_table[0][2]} \\447\py{results_table[1][0]} & \py{results_table[1][1]} & \py{results_table[1][2]} \\448\py{results_table[2][0]} & \py{results_table[2][1]} & \py{results_table[2][2]} \\449\py{results_table[3][0]} & \py{results_table[3][1]} & \py{results_table[3][2]} \\450\py{results_table[4][0]} & \py{results_table[4][1]} & \py{results_table[4][2]} \\451\py{results_table[5][0]} & \py{results_table[5][1]} & \py{results_table[5][2]} \\452\bottomrule453\end{tabular}454\end{table}455456\chapter{Conclusions}457458\begin{enumerate}459\item Isochron dating provides both age and initial ratios460\item U-Pb concordia reveals open-system behavior461\item Multiple isotope systems enable cross-validation462\item Closure temperature controls age interpretation463\item Thermochronology constrains cooling histories464\item Radiocarbon requires calibration for calendar ages465\end{enumerate}466467\end{document}468469470