tMISMIP.py - pism-exp-gsw - ice stream and sediment transport experiments
(HTM) git clone git://src.adamsgaard.dk/pism-exp-gsw
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
tMISMIP.py (9438B)
---
1 #!/usr/bin/env python3
2 import numpy as np
3
4 """This module contains MISMIP constants and parameters, as well as functions
5 computing theoretical steady state profiles corresponding to various MISMIP
6 experiments.
7
8 It should not be cluttered with plotting or NetCDF output code.
9 """
10
11
12 def secpera():
13 "Number of seconds per year."
14 return 3.15569259747e7
15
16
17 def L():
18 "The length of the MISMIP domain."
19 return 1800e3
20
21
22 def N(mode):
23 "Number of grid spaces corresponding to a MISMIP 'mode.'"
24 if mode == 1:
25 return 150
26
27 if mode == 2:
28 return 1500
29
30 raise ValueError("invalid mode (%s)" % mode)
31
32
33 def A(experiment, step):
34 """Ice softness parameter for given experiment and step."""
35 A1 = np.array([4.6416e-24, 2.1544e-24, 1.0e-24,
36 4.6416e-25, 2.1544e-25, 1.0e-25,
37 4.6416e-26, 2.1544e-26, 1.0e-26])
38 # Values of A to be used in experiments 1 and 2.
39
40 A3a = np.array([3.0e-25, 2.5e-25, 2.0e-25,
41 1.5e-25, 1.0e-25, 5.0e-26,
42 2.5e-26, 5.0e-26, 1.0e-25,
43 1.5e-25, 2.0e-25, 2.5e-25,
44 3.0e-25])
45 # Values of A to be used in experiment 3a.
46
47 A3b = np.array([1.6e-24, 1.4e-24, 1.2e-24,
48 1.0e-24, 8.0e-25, 6.0e-25,
49 4.0e-25, 2.0e-25, 4.0e-25,
50 6.0e-25, 8.0e-25, 1.0e-24,
51 1.2e-24, 1.4e-24, 1.6e-24])
52 # Values of A to be used in experiment 3b.
53
54 try:
55 if experiment in ("1a", "1b", "2a", "2b"):
56 return A1[step - 1]
57
58 if experiment == "3a":
59 return A3a[step - 1]
60
61 if experiment == "3b":
62 return A3b[step - 1]
63 except:
64 raise ValueError("invalid step (%s) for experiment %s" % (step, experiment))
65
66 raise ValueError("invalid experiment (%s)" % experiment)
67
68
69 def run_length(experiment, step):
70 """Returns the time interval for an experiment 3 step."""
71 T3a = np.array([3.0e4, 1.5e4, 1.5e4,
72 1.5e4, 1.5e4, 3.0e4,
73 3.0e4, 1.5e4, 1.5e4,
74 3.0e4, 3.0e4, 3.0e4,
75 1.5e4])
76 # Time intervals to be used in experiment 3a.
77
78 T3b = np.array([3.0e4, 1.5e4, 1.5e4,
79 1.5e4, 1.5e4, 1.5e4,
80 1.5e4, 3.0e4, 1.5e4,
81 1.5e4, 1.5e4, 1.5e4,
82 1.5e4, 3.0e4, 1.5e4])
83 # Time intervals to be used in experiment 3b.
84
85 try:
86 if experiment == "3a":
87 return T3a[step - 1]
88
89 if experiment == "3b":
90 return T3b[step - 1]
91 except:
92 raise ValueError("invalid step (%s) for experiment %s" % (step, experiment))
93
94 return 3e4
95
96
97 def rho_i():
98 "Ice density"
99 return 900.0
100
101
102 def rho_w():
103 "Water density"
104 return 1000.0
105
106
107 def g():
108 """Acceleration due to gravity. (Table 2 on page 19 of mismip_4.pdf
109 uses this value, i.e. g = 9.8 m s-2.)"""
110 return 9.8
111
112
113 def n():
114 "Glen exponent"
115 return 3.0
116
117
118 def a():
119 "Accumulation rate (m/s)"
120 return 0.3 / secpera()
121
122
123 def m(experiment):
124 "Sliding law exponent"
125 if experiment in ("1a", "2a", "3a"):
126 return 1 / 3.0
127
128 if experiment in ("1b", "2b", "3b"):
129 return 1.0
130
131 raise ValueError("invalid experiment (%s)" % experiment)
132
133
134 def C(experiment):
135 "Sliding law coefficient"
136 if experiment in ("1a", "2a", "3a"):
137 return 7.624e6
138
139 if experiment in ("1b", "2b", "3b"):
140 return 7.2082e10
141
142 raise ValueError("invalid experiment (%s)" % experiment)
143
144
145 def b(experiment, x):
146 "Bed depth below sea level. (-b(x) = topg(x))"
147
148 if experiment in ("1a", "1b", "2a", "2b"):
149 return -720. + 778.5 * (x / 7.5e5)
150
151 if experiment in ("3a", "3b"):
152 xx = x / 7.5e5
153 return -(729. - 2184.8 * xx ** 2. + 1031.72 * xx ** 4. - 151.72 * xx ** 6.)
154
155 raise ValueError("invalid experiment (%s)" % experiment)
156
157
158 def b_slope(experiment, x):
159 """The x-derivative of b(experiment, x)."""
160
161 if experiment in ("1a", "1b", "2a", "2b"):
162 return 778.5 / 7.5e5
163
164 if experiment in ("3a", "3b"):
165 xx = x / 7.5e5
166 return -(- 2184.8 * (2. / 7.5e5) * xx
167 + 1031.72 * (4. / 7.5e5) * xx ** 3.
168 - 151.72 * (6. / 7.5e5) * xx ** 5.)
169
170 raise ValueError("invalid experiment (%s)" % experiment)
171
172
173 def cold_function(experiment, step, x, theta=0.0):
174 """Evaluates function whose zeros define x_g in 'cold' steady marine sheet problem."""
175 r = rho_i() / rho_w()
176 h_f = r ** (-1.) * b(experiment, x)
177 b_x = b_slope(experiment, x)
178 s = a() * x
179 rho_g = rho_i() * g()
180 return (theta * a()
181 + C(experiment) * s ** (m(experiment) + 1.0) / (rho_g * h_f ** (m(experiment) + 2.))
182 - theta * s * b_x / h_f
183 - A(experiment, step) * (rho_g * (1.0 - r) / 4.0) ** n() * h_f ** (n() + 1.0))
184
185
186 def x_g(experiment, step, theta=0.0):
187 """Computes the theoretical grounding line location using Newton's method."""
188
189 # set the initial guess
190 if experiment in ("3a", "3b"):
191 x = 800.0e3
192 else:
193 x = 1270.0e3
194
195 delta_x = 10. # Finite difference step size (metres) for gradient calculation
196 tolf = 1.e-4 # Tolerance for finding zeros
197 eps = np.finfo(float).eps
198 normf = tolf + eps
199 toldelta = 1.e1 # Newton step size tolerance
200 dx = toldelta + 1.0
201
202 # this is just a shortcut
203 def F(x):
204 return cold_function(experiment, step, x, theta)
205
206 while (normf > tolf) or (abs(dx) > toldelta):
207 f = F(x)
208 normf = abs(f)
209 grad = (F(x + delta_x) - f) / delta_x
210 dx = -f / grad
211 x = x + dx
212
213 return x
214
215
216 def thickness(experiment, step, x, theta=0.0):
217 """Compute ice thickness for x > 0.
218 """
219 # compute the grounding line position
220 xg = x_g(experiment, step, theta)
221
222 def surface(h, x):
223 b_x = b_slope(experiment, x)
224 rho_g = rho_i() * g()
225 s = a() * np.abs(x)
226 return b_x - (C(experiment) / rho_g) * s ** m(experiment) / h ** (m(experiment) + 1)
227
228 # extract the grounded part of the grid
229 x_grounded = x[x < xg]
230
231 # We will integrate from the grounding line inland. odeint requires that
232 # the first point in x_grid be the one corresponding to the initial
233 # condition; append it and reverse the order.
234 x_grid = np.append(xg, x_grounded[::-1])
235
236 # use thickness at the grounding line as the initial condition
237 h_f = b(experiment, xg) * rho_w() / rho_i()
238
239 import scipy.integrate
240 thk_grounded = scipy.integrate.odeint(surface, [h_f], x_grid, atol=1.e-9, rtol=1.e-9)
241
242 # now 'result' contains thickness in reverse order, including the grounding
243 # line point (which is not on the grid); discard it and reverse the order.
244 thk_grounded = np.squeeze(thk_grounded)[:0:-1]
245
246 # extract the floating part of the grid
247 x_floating = x[x >= xg]
248
249 # compute the flux through the grounding line
250 q_0 = a() * xg
251
252 # Calculate ice thickness for shelf from van der Veen (1986)
253 r = rho_i() / rho_w()
254 rho_g = rho_i() * g()
255 numer = h_f * (q_0 + a() * (x_floating - xg))
256 base = q_0 ** (n() + 1) + h_f ** (n() + 1) * ((1 - r) * rho_g / 4) ** n() * A(experiment, step) \
257 * ((q_0 + a() * (x_floating - xg)) ** (n() + 1) - q_0 ** (n() + 1)) / a()
258 thk_floating = numer / (base ** (1.0 / (n() + 1)))
259
260 return np.r_[thk_grounded, thk_floating]
261
262
263 def plot_profile(experiment, step, out_file):
264 from pylab import figure, subplot, hold, plot, xlabel, ylabel, text, title, axis, vlines, savefig
265
266 if out_file is None:
267 out_file = "MISMIP_%s_A%d.pdf" % (experiment, step)
268
269 xg = x_g(experiment, step)
270
271 x = np.linspace(0, L(), N(2) + 1)
272 thk = thickness(experiment, step, x)
273 x_grounded, thk_grounded = x[x < xg], thk[x < xg]
274 x_floating, thk_floating = x[x >= xg], thk[x >= xg]
275
276 figure(1)
277 ax = subplot(111)
278 hold(True)
279 plot(x / 1e3, np.zeros_like(x), ls='dotted', color='red')
280 plot(x / 1e3, -b(experiment, x), color='black')
281 plot(x / 1e3, np.r_[thk_grounded - b(experiment, x_grounded),
282 thk_floating * (1 - rho_i() / rho_w())],
283 color='blue')
284 plot(x_floating / 1e3, -thk_floating * (rho_i() / rho_w()), color='blue')
285 _, _, ymin, ymax = axis(xmin=0, xmax=x.max() / 1e3)
286 vlines(xg / 1e3, ymin, ymax, linestyles='dashed', color='black')
287
288 xlabel('distance from the summit, km')
289 ylabel('elevation, m')
290 text(0.6, 0.9, "$x_g$ (theory) = %4.0f km" % (xg / 1e3),
291 color='black', transform=ax.transAxes)
292 title("MISMIP experiment %s, step %d" % (experiment, step))
293 savefig(out_file)
294
295
296 if __name__ == "__main__":
297 from optparse import OptionParser
298
299 parser = OptionParser()
300
301 parser.usage = "%prog [options]"
302 parser.description = "Plots the theoretical geometry profile corresponding to MISMIP experiment and step."
303 parser.add_option("-e", "--experiment", dest="experiment", type="string",
304 default='1a',
305 help="MISMIP experiments (one of '1a', '1b', '2a', '2b', '3a', '3b')")
306 parser.add_option("-s", "--step", dest="step", type="int", default=1,
307 help="MISMIP step number")
308 parser.add_option("-o", dest="out_file", help="output file name")
309
310 (opts, args) = parser.parse_args()
311
312 plot_profile(opts.experiment, opts.step, opts.out_file)