Skip to content

Commit 9670e44

Browse files
committed
Deployed 6cae333 with MkDocs version: 1.4.2
1 parent cfa7fcd commit 9670e44

15 files changed

Lines changed: 704 additions & 426 deletions

File tree

css/custom.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
details {
2+
margin: 1em 0;
3+
padding: 0.5em;
4+
border: 1px solid #ccc;
5+
border-radius: 4px;
6+
background-color: #f8f8f8;
7+
}
8+
9+
details[open] summary::before {
10+
content: "▼ ";
11+
}
12+
13+
details summary::before {
14+
content: "▶ ";
15+
}

gallery-Lagrangian-CPO-parcel/index.html

Lines changed: 306 additions & 130 deletions
Large diffs are not rendered by default.

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,5 +195,5 @@ <h1 id="specfab-documentation">specfab documentation</h1>
195195

196196
<!--
197197
MkDocs version : 1.4.2
198-
Build Date UTC : 2025-06-25 09:07:23.313894+00:00
198+
Build Date UTC : 2025-06-26 09:53:26.979250+00:00
199199
-->

search/search_index.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

sitemap.xml

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,122 +2,122 @@
22
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
33
<url>
44
<loc>None</loc>
5-
<lastmod>2025-06-25</lastmod>
5+
<lastmod>2025-06-26</lastmod>
66
<changefreq>daily</changefreq>
77
</url>
88
<url>
99
<loc>None</loc>
10-
<lastmod>2025-06-25</lastmod>
10+
<lastmod>2025-06-26</lastmod>
1111
<changefreq>daily</changefreq>
1212
</url>
1313
<url>
1414
<loc>None</loc>
15-
<lastmod>2025-06-25</lastmod>
15+
<lastmod>2025-06-26</lastmod>
1616
<changefreq>daily</changefreq>
1717
</url>
1818
<url>
1919
<loc>None</loc>
20-
<lastmod>2025-06-25</lastmod>
20+
<lastmod>2025-06-26</lastmod>
2121
<changefreq>daily</changefreq>
2222
</url>
2323
<url>
2424
<loc>None</loc>
25-
<lastmod>2025-06-25</lastmod>
25+
<lastmod>2025-06-26</lastmod>
2626
<changefreq>daily</changefreq>
2727
</url>
2828
<url>
2929
<loc>None</loc>
30-
<lastmod>2025-06-25</lastmod>
30+
<lastmod>2025-06-26</lastmod>
3131
<changefreq>daily</changefreq>
3232
</url>
3333
<url>
3434
<loc>None</loc>
35-
<lastmod>2025-06-25</lastmod>
35+
<lastmod>2025-06-26</lastmod>
3636
<changefreq>daily</changefreq>
3737
</url>
3838
<url>
3939
<loc>None</loc>
40-
<lastmod>2025-06-25</lastmod>
40+
<lastmod>2025-06-26</lastmod>
4141
<changefreq>daily</changefreq>
4242
</url>
4343
<url>
4444
<loc>None</loc>
45-
<lastmod>2025-06-25</lastmod>
45+
<lastmod>2025-06-26</lastmod>
4646
<changefreq>daily</changefreq>
4747
</url>
4848
<url>
4949
<loc>None</loc>
50-
<lastmod>2025-06-25</lastmod>
50+
<lastmod>2025-06-26</lastmod>
5151
<changefreq>daily</changefreq>
5252
</url>
5353
<url>
5454
<loc>None</loc>
55-
<lastmod>2025-06-25</lastmod>
55+
<lastmod>2025-06-26</lastmod>
5656
<changefreq>daily</changefreq>
5757
</url>
5858
<url>
5959
<loc>None</loc>
60-
<lastmod>2025-06-25</lastmod>
60+
<lastmod>2025-06-26</lastmod>
6161
<changefreq>daily</changefreq>
6262
</url>
6363
<url>
6464
<loc>None</loc>
65-
<lastmod>2025-06-25</lastmod>
65+
<lastmod>2025-06-26</lastmod>
6666
<changefreq>daily</changefreq>
6767
</url>
6868
<url>
6969
<loc>None</loc>
70-
<lastmod>2025-06-25</lastmod>
70+
<lastmod>2025-06-26</lastmod>
7171
<changefreq>daily</changefreq>
7272
</url>
7373
<url>
7474
<loc>None</loc>
75-
<lastmod>2025-06-25</lastmod>
75+
<lastmod>2025-06-26</lastmod>
7676
<changefreq>daily</changefreq>
7777
</url>
7878
<url>
7979
<loc>None</loc>
80-
<lastmod>2025-06-25</lastmod>
80+
<lastmod>2025-06-26</lastmod>
8181
<changefreq>daily</changefreq>
8282
</url>
8383
<url>
8484
<loc>None</loc>
85-
<lastmod>2025-06-25</lastmod>
85+
<lastmod>2025-06-26</lastmod>
8686
<changefreq>daily</changefreq>
8787
</url>
8888
<url>
8989
<loc>None</loc>
90-
<lastmod>2025-06-25</lastmod>
90+
<lastmod>2025-06-26</lastmod>
9191
<changefreq>daily</changefreq>
9292
</url>
9393
<url>
9494
<loc>None</loc>
95-
<lastmod>2025-06-25</lastmod>
95+
<lastmod>2025-06-26</lastmod>
9696
<changefreq>daily</changefreq>
9797
</url>
9898
<url>
9999
<loc>None</loc>
100-
<lastmod>2025-06-25</lastmod>
100+
<lastmod>2025-06-26</lastmod>
101101
<changefreq>daily</changefreq>
102102
</url>
103103
<url>
104104
<loc>None</loc>
105-
<lastmod>2025-06-25</lastmod>
105+
<lastmod>2025-06-26</lastmod>
106106
<changefreq>daily</changefreq>
107107
</url>
108108
<url>
109109
<loc>None</loc>
110-
<lastmod>2025-06-25</lastmod>
110+
<lastmod>2025-06-26</lastmod>
111111
<changefreq>daily</changefreq>
112112
</url>
113113
<url>
114114
<loc>None</loc>
115-
<lastmod>2025-06-25</lastmod>
115+
<lastmod>2025-06-26</lastmod>
116116
<changefreq>daily</changefreq>
117117
</url>
118118
<url>
119119
<loc>None</loc>
120-
<lastmod>2025-06-25</lastmod>
120+
<lastmod>2025-06-26</lastmod>
121121
<changefreq>daily</changefreq>
122122
</url>
123123
</urlset>

sitemap.xml.gz

0 Bytes
Binary file not shown.
123 KB
Loading
123 KB
Loading
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
"""
2+
Model CPO profile of the GRIP ice core, Greenland
3+
"""
4+
5+
import numpy as np
6+
from scipy.integrate import solve_ivp
7+
from scipy import interpolate
8+
import pandas as pd
9+
10+
from specfabpy import specfab as sf
11+
from specfabpy import common as sfcom
12+
from specfabpy import plotting as sfplt
13+
14+
import matplotlib.pyplot as plt
15+
16+
from matplotlib import rc
17+
#rc('font',**{'family':'sans-serif','sans-serif':['Helvetica']})
18+
rc('font',**{'family':'serif','serif':['Palatino']})
19+
rc('text', usetex=True)
20+
21+
"""
22+
Setup
23+
"""
24+
25+
### Velocity gradient experienced by parcel
26+
27+
H = 3027 # ice thickness (Montagnat et al., 2014)
28+
a = 0.24 # meter ice equiv. per yr (Montagnat et al., 2014)
29+
tau = H/a # e-folding time scale
30+
ugrad = -1/tau*np.diag([-0.5, -0.5, 1]) # uniaxial compression along z-axis
31+
32+
### Numerics
33+
34+
tend = 50e3 # time (in years) to trace out trajectory, starting from the surface
35+
#tend = -tau*np.log(0.05) # alternatively, set tend so that simulation stops at 95% thinning
36+
37+
Nt = 1000 # number of time steps taken (increase this until results are robust)
38+
ti = np.linspace(0, tend, Nt) # time points at which to evaluate the solution
39+
z = np.exp(-ti/tau) # relative height above bed at each point in time
40+
41+
L = 12 # CPO expansion series truncation
42+
kw_ivp = dict(method='RK45', vectorized=False) # kwargs for solve_ivp()
43+
44+
### CPO dynamics
45+
46+
# Lattice rotation
47+
iota, zeta = 1, 0 # "deck of cards" behavior
48+
49+
# DDRX
50+
A = 1.1e7 # rate prefactor (tunable parameter)
51+
Q = 3.36e4 # activation energy (see Richards et al. (2021) and Lilien et al. (2023))
52+
R = 8.314 # gas constant
53+
Gamma0 = lambda D, T: A*np.sqrt(np.einsum('ij,ji',D,D)/2)*np.exp(-Q/(R*(T+273.15))) # DDRX rate factor
54+
55+
### Temperature profile
56+
57+
df = pd.read_csv('../../../data/icecores/GRIP/temperature.csv') # fetch from github
58+
fz = interpolate.interp1d(df['zrel'].to_numpy(), df['T'].to_numpy(), kind='linear', fill_value='extrapolate')
59+
T = fz(z) # temperature profile
60+
61+
"""
62+
Solve CPO evolution
63+
"""
64+
65+
D = (ugrad+np.transpose(ugrad))/2 # symmetric part (strain rate tensor)
66+
W = (ugrad-np.transpose(ugrad))/2 # anti-symmetric part (spin tensor)
67+
S = D # stress tensor (assume coaxiality with strain-rate tensor; magnitude does not matter for our purpose)
68+
69+
#T[:] = -60 # no DDRX if ice is very cold
70+
71+
lm, nlm_len = sf.init(L) # initialize specfab
72+
lh_init = 0.25 # initial horizontal eigenvalues
73+
a2_init = np.diag([lh_init, lh_init, 1-2*lh_init]) # initial a2 (at surface)
74+
75+
nlm_init = np.zeros((nlm_len), dtype=np.complex64) # CPO expansion coefficients
76+
nlm_init[:sf.L2len] = sf.a2_to_nlm(a2_init) # initial state vector (at surface)
77+
78+
def ODE(t, nlm):
79+
# d/dt nlm_i = M_ij . nlm_j, where nlm_i is the state vector (aka s_i)
80+
I = np.argmin(np.abs(ti-t)) # index for closest point on trajectory at time t
81+
M = sf.M_LROT(nlm, D, W, iota, zeta) # lattice rotation always present
82+
M += Gamma0(D,T[I])*sf.M_DDRX(nlm, S) # DDRX active if sufficient warm
83+
#M += Lambda0*sf.M_CDRX(nlm) # CDRX (neglected in this example)
84+
M += sf.M_REG(nlm, D) # regularization
85+
return np.matmul(M, nlm)
86+
87+
nlm = solve_ivp(ODE, (0, tend), nlm_init, t_eval=ti, vectorized=False).y.T # CPO state along trajectory
88+
mi, lami = sfcom.eigenframe(nlm) # a2 eigenvectors and eigenvalues
89+
90+
"""
91+
Plot results
92+
"""
93+
94+
### Plot modeled eigenvalues
95+
96+
fig = plt.figure(figsize=(3,4))
97+
ax = plt.subplot(111)
98+
99+
c1,c2,c3 = 'tab:blue', 'tab:red', 'k'
100+
101+
ax.plot(lami[:,0], z, '-', c=c1, label=r'$\lambda_1$')
102+
ax.plot(lami[:,1], z, '-', c=c2, label=r'$\lambda_2$')
103+
ax.plot(lami[:,2], z, '--', c=c3, label=r'$\lambda_3$')
104+
105+
ax.legend(loc=1, fancybox=False, frameon=False)
106+
ax.set_title(r'GRIP ice core')
107+
108+
ax.set_xlabel(r'$\lambda_i$')
109+
ax.set_xticks(np.arange(0,1+.01,0.2))
110+
ax.set_xlim([0,1])
111+
112+
ax.set_ylabel(r'$z/H$')
113+
ax.set_yticks(np.arange(0,1+.01,0.1))
114+
ax.set_ylim([0,1])
115+
116+
### Plot CPOs
117+
118+
geo, prj = sfplt.getprojection(rotation=45, inclination=50)
119+
120+
def plotCPO(ax, nlm, p0, HW=0.2, cmap='Greys'):
121+
axtrans = ax.transData.transform(p0)
122+
trans = fig.transFigure.inverted().transform(axtrans)
123+
axin = plt.axes([trans[0]-HW/2, trans[1]-HW/2, HW,HW], projection=prj)
124+
axin.set_global()
125+
lvlset = [np.linspace(0.05, 0.45, 8), lambda x,p:'%.1f'%x]
126+
sfplt.plotODF(nlm, lm, axin, lvlset=lvlset, cmap=cmap, showcb=False, nchunk=None)
127+
sfplt.plotcoordaxes(axin, geo, negaxes=False, color=sfplt.c_dred, axislabels='xi')
128+
return axin
129+
130+
for zi in np.linspace(0.1, 0.9, 4):
131+
I = np.argmin(np.abs(z-zi))
132+
plotCPO(ax, nlm[I], (1.2,zi))
133+
134+
### Plot observations
135+
136+
df = pd.read_csv('../../../data/icecores/GRIP/orientations.csv') # fetch from github
137+
zobs = df['zrel'].to_numpy()
138+
kw = dict(marker='o', facecolor='none', zorder=1)
139+
ax.scatter(df['lam1'].to_numpy(), zobs, edgecolor=c1, **kw)
140+
ax.scatter(df['lam2'].to_numpy(), zobs, edgecolor=c2, **kw)
141+
ax.scatter(df['lam3'].to_numpy(), zobs, edgecolor=c3, **kw)
142+
143+
### Save plot
144+
145+
plt.savefig('GRIP-parcel.png', dpi=175, pad_inches=0.1, bbox_inches='tight')
-123 KB
Binary file not shown.

0 commit comments

Comments
 (0)