Loading [MathJax]/extensions/tex2jax.js
PISM, A Parallel Ice Sheet Model 2.2.2-d6b3a29ca committed by Constantine Khrulev on 2025-03-28
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
enthSystem.cc
Go to the documentation of this file.
1// Copyright (C) 2009-2018, 2020, 2021, 2022, 2023 Andreas Aschwanden and Ed Bueler and Constantine Khroulev
2//
3// This file is part of PISM.
4//
5// PISM is free software; you can redistribute it and/or modify it under the
6// terms of the GNU General Public License as published by the Free Software
7// Foundation; either version 3 of the License, or (at your option) any later
8// version.
9//
10// PISM is distributed in the hope that it will be useful, but WITHOUT ANY
11// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13// details.
14//
15// You should have received a copy of the GNU General Public License
16// along with PISM; if not, write to the Free Software
17// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19#include <cmath> // NAN, std::isnan, std::pow
20#include <algorithm> // std::min
21
22#include "pism/energy/enthSystem.hh"
23#include "pism/util/ConfigInterface.hh"
24#include "pism/util/EnthalpyConverter.hh"
25
26#include "pism/util/error_handling.hh"
27
28namespace pism {
29namespace energy {
30
31enthSystemCtx::enthSystemCtx(const std::vector<double>& storage_grid,
32 const std::string &prefix,
33 double dx, double dy, double dt,
34 const Config &config,
35 const array::Array3D &Enth3,
36 const array::Array3D &u3,
37 const array::Array3D &v3,
38 const array::Array3D &w3,
39 const array::Array3D &strain_heating3,
41: columnSystemCtx(storage_grid, prefix, dx, dy, dt, u3, v3, w3),
42 m_Enth3(Enth3),
43 m_strain_heating3(strain_heating3),
44 m_EC(EC) {
45
46 using std::pow;
47
48 // set some values so we can check if init was called
49 m_R_cold = -1.0;
50 m_R_temp = -1.0;
51 m_lambda = -1.0;
52 m_D0 = NAN;
53 m_U0 = NAN;
54 m_B0 = NAN;
55 m_L_ks = NAN;
56 m_D_ks = NAN;
57 m_U_ks = NAN;
58 m_B_ks = NAN;
59
60 m_ice_density = config.get_number("constants.ice.density");
61 m_ice_c = config.get_number("constants.ice.specific_heat_capacity");
62 m_ice_k = config.get_number("constants.ice.thermal_conductivity");
63 m_p_air = config.get_number("surface.pressure");
64
65 m_margin_exclude_horizontal_advection = config.get_flag("energy.margin_exclude_horizontal_advection");
66 m_margin_exclude_vertical_advection = config.get_flag("energy.margin_exclude_vertical_advection");
67 m_margin_exclude_strain_heat = config.get_flag("energy.margin_exclude_strain_heating");
68
69 size_t Mz = m_z.size();
70 m_Enth.resize(Mz);
71 m_Enth_s.resize(Mz);
72 m_strain_heating.resize(Mz);
73 m_R.resize(Mz);
74
75 m_E_n.resize(Mz);
76 m_E_e.resize(Mz);
77 m_E_s.resize(Mz);
78 m_E_w.resize(Mz);
79
80 m_nu = m_dt / m_dz;
81
82 double
83 ratio = config.get_number(prefix + ".temperate_ice_thermal_conductivity_ratio"),
84 K = m_ice_k / m_ice_c,
85 K0 = (ratio * m_ice_k) / m_ice_c;
86
87 m_R_factor = m_dt / (pow(m_dz, 2) * m_ice_density);
88 m_R_cold = K * m_R_factor;
89 m_R_temp = K0 * m_R_factor;
90
91 if (config.get_flag("energy.temperature_dependent_thermal_conductivity")) {
92 m_k_depends_on_T = true;
93 } else {
94 m_k_depends_on_T = false;
95 }
96}
97
98/*!
99 In this implementation \f$k\f$ does not depend on temperature.
100 */
101double enthSystemCtx::k_from_T(double T) const {
102
103 if (m_k_depends_on_T) {
104 return 9.828 * exp(-0.0057 * T);
105 }
106
107 return m_ice_k;
108}
109
110void enthSystemCtx::init(int i, int j, bool marginal, double ice_thickness) {
111 m_ice_thickness = ice_thickness;
112
114
116
117 if (m_ks == 0) {
118 return;
119 }
120
121 coarse_to_fine(m_u3, m_i, m_j, m_u.data());
122 coarse_to_fine(m_v3, m_i, m_j, m_v.data());
123
125 for (unsigned int k = 0; k < m_w.size(); ++k) {
126 m_w[k] = 0.0;
127 }
128 } else {
129 coarse_to_fine(m_w3, m_i, m_j, m_w.data());
130 }
131
134
135 coarse_to_fine(m_Enth3, m_i, m_j+1, m_E_n.data());
136 coarse_to_fine(m_Enth3, m_i+1, m_j, m_E_e.data());
137 coarse_to_fine(m_Enth3, m_i, m_j-1, m_E_s.data());
138 coarse_to_fine(m_Enth3, m_i-1, m_j, m_E_w.data());
139
141
143
144 assemble_R();
145}
146
147//! Compute the CTS value of enthalpy in an ice column.
148/*! m_Enth_s is set to the enthalpy value for the pressure-melting
149 temperature with zero water fraction at the corresponding z level.
150 */
152
153 for (unsigned int k = 0; k <= m_ks; k++) {
154 const double
155 depth = m_ice_thickness - k * m_dz,
156 p = m_EC->pressure(depth); // FIXME issue #15
157 m_Enth_s[k] = m_EC->enthalpy_cts(p);
158 }
159
160 const double Es_air = m_EC->enthalpy_cts(m_p_air);
161 for (unsigned int k = m_ks+1; k < m_Enth_s.size(); k++) {
162 m_Enth_s[k] = Es_air;
163 }
164}
165
166//! Compute the lambda for BOMBPROOF.
167/*!
168See page \ref bombproofenth.
169 */
171 double result = 1.0; // start with centered implicit for more accuracy
172 const double epsilon = 1e-6 / 3.15569259747e7;
173
174 for (unsigned int k = 0; k <= m_ks; k++) {
175 if (m_Enth[k] > m_Enth_s[k]) { // lambda = 0 if temperate ice present in column
176 result = 0.0;
177 } else {
178 const double denom = (fabs(m_w[k]) + epsilon) * m_ice_density * m_ice_c * m_dz;
179 result = std::min(result, 2.0 * m_ice_k / denom);
180 }
181 }
182 return result;
183}
184
185
187#if (Pism_DEBUG==1)
188 if ((m_nu < 0.0) || (m_R_cold < 0.0) || (m_R_temp < 0.0)) {
189 throw RuntimeError(PISM_ERROR_LOCATION, "setDirichletSurface() should only be called after\n"
190 "initAllColumns() in enthSystemCtx");
191 }
192#endif
193 m_L_ks = 0.0;
194 m_D_ks = 1.0;
195 m_U_ks = 0.0;
196 m_B_ks = E_surface;
197}
198
199static inline double upwind(double u, double E_m, double E, double E_p, double delta_inverse) {
200 return u * delta_inverse * (u < 0 ? (E_p - E) : (E - E_m));
201}
202
203
204//! Set the top surface heat flux *into* the ice.
205/** @param[in] heat_flux prescribed heat flux (positive means flux into the ice)
206 */
208 using std::pow;
209 // extract K from R[ks], so this code works even if K=K(T)
210 // recall: R = (ice_K / ice_density) * dt / PetscSqr(dz)
211 const double
212 K = (m_ice_density * pow(m_dz, 2) * m_R[m_ks]) / m_dt,
213 G = heat_flux / K;
214
216}
217
218//! Set enthalpy flux at the surface.
219/*! This method should probably be used for debugging only. Its purpose is to allow setting the
220 enthalpy flux even if K == 0, i.e. in a "pure advection" setup.
221 */
223 const bool include_horizontal_advection =
225 const bool include_strain_heating = not(m_marginal and m_margin_exclude_strain_heat);
226
227 const double Rminus = 0.5 * (m_R[m_ks - 1] + m_R[m_ks]), // R_{ks-1/2}
228 Rplus = m_R[m_ks], // R_{ks+1/2}
229 mu_w = 0.5 * m_nu * m_w[m_ks];
230
231 const double A_l = m_w[m_ks] < 0.0 ? 1.0 - m_lambda : m_lambda - 1.0;
232 const double A_d = m_w[m_ks] < 0.0 ? m_lambda - 1.0 : 1.0 - m_lambda;
233 const double A_b = m_w[m_ks] < 0.0 ? m_lambda - 2.0 : -m_lambda;
234
235 // modified lower-diagonal entry:
236 m_L_ks = -Rminus - Rplus + 2.0 * mu_w * A_l;
237 // diagonal entry
238 m_D_ks = 1.0 + Rminus + Rplus + 2.0 * mu_w * A_d;
239 // upper-diagonal entry (not used)
240 m_U_ks = 0.0;
241 // m_Enth[m_ks] (below) is there due to the fully-implicit discretization in time, the second term is
242 // the modification of the right-hand side implementing the Neumann B.C. (similar to
243 // set_basal_heat_flux(); see that method for details)
244 m_B_ks = m_Enth[m_ks] + 2.0 * dE * m_dz * (Rplus + mu_w * A_b);
245
246 // treat horizontal velocity using first-order upwinding:
247 double upwind_u = 0.0;
248 double upwind_v = 0.0;
249 if (include_horizontal_advection) {
250 upwind_u = upwind(m_u[m_ks], m_E_w[m_ks], m_Enth[m_ks], m_E_e[m_ks], 1.0 / m_dx);
251 upwind_v = upwind(m_v[m_ks], m_E_s[m_ks], m_Enth[m_ks], m_E_n[m_ks], 1.0 / m_dy);
252 }
253 double Sigma = 0.0;
254 if (include_strain_heating) {
255 Sigma = m_strain_heating[m_ks];
256 }
257
258 m_B_ks += m_dt * ((Sigma / m_ice_density) - upwind_u - upwind_v); // = rhs[m_ks]
259}
260
262 if (m_nu < 0.0 || m_R_cold < 0.0 || m_R_temp < 0.0) {
264 "not ready to solve: need initAllColumns() in enthSystemCtx");
265 }
266 if (m_lambda < 0.0) {
268 "not ready to solve: need setSchemeParamsThisColumn() in enthSystemCtx");
269 }
270}
271
272
273//! Set coefficients in discrete equation for \f$E = Y\f$ at base of ice.
274/*!
275This method should only be called if everything but the basal boundary condition
276is already set.
277 */
279#if (Pism_DEBUG == 1)
281 if (not std::isnan(m_D0) || not std::isnan(m_U0) || not std::isnan(m_B0)) {
283 "setting basal boundary conditions twice in enthSystemCtx");
284 }
285#endif
286 m_D0 = 1.0;
287 m_U0 = 0.0;
288 m_B0 = E_basal;
289}
290
291//! Set coefficients in discrete equation for Neumann condition at base of ice.
292/*!
293This method generates the Neumann boundary condition for the linear system.
294
295The Neumann boundary condition is
296 @f[ \frac{\partial E}{\partial z} = - \frac{\phi}{K} @f]
297where \f$\phi\f$ is the heat flux. Here \f$K\f$ is allowed to vary, and takes
298its value from the value computed in assemble_R().
299
300The boundary condition is combined with the partial differential equation by the
301technique of introducing an imaginary point at \f$z=-\Delta z\f$ and then
302eliminating it.
303
304In other words, we combine the centered finite difference approximation
305@f[ \frac{ E_{1} - E_{-1} }{2\dz} = -\frac{\phi}{K} @f]
306with
307
308@f[ -R_{k-\frac12} E_{k-1} + \left( 1 + R_{k-\frac12} + R_{k+\frac12} \right) E_{k} - R_{k+\frac12} E_{k+1} + \text{advective terms} = \dots @f]
309
310to get
311
312@f{align*}{
313 \frac{E_{1}-E_{-1}}{2\,\Delta z} & = -\frac{\phi}{K_{0}}, \\
314 E_{1}-E_{-1} & = -\frac{2\,\Delta z\,\phi}{K_{0}}, \\
315 E_{-1}\,R_{-\frac12}-R_{-\frac12}\,E_{1} & = \frac{2\,R_{-\frac12}\,\Delta z\,\phi}{K_{0}}, \\
316 -R_{\frac12}\,E_{1}+E_{0}\,\left(R_{\frac12}+R_{-\frac12}+1\right)-E_{-1}\,R_{-\frac12} + \text{advective terms} & = \dots, \\
317 \left(-R_{\frac12}-R_{-\frac12}\right)\,E_{1}+E_{0}\,\left(R_{\frac12}+R_{-\frac12}+1\right) + \text{advective terms} & = \frac{2\,R_{-\frac12}\,\Delta z\,\phi}{K_{0}}+\dots.
318@f}
319
320The error in the pure conductive and smooth conductivity case is @f$ O(\dz^2) @f$.
321
322This method should only be called if everything but the basal boundary condition
323is already set.
324
325@param[in] heat_flux prescribed heat flux (positive means flux into the ice)
326
327 */
329 using std::pow;
330 // extract K from R[0], so this code works even if K=K(T)
331 // recall: R = (ice_K / ice_density) * dt / PetscSqr(dz)
332 const double
333 K = (m_ice_density * pow(m_dz, 2) * m_R[0]) / m_dt,
334 G = - heat_flux / K;
335
336 this->set_basal_neumann_bc(G);
337}
338
339//! Set enthalpy flux at the base.
340/*! This method should probably be used for debugging only. Its purpose is to allow setting the
341 enthalpy flux even if K == 0, i.e. in a "pure advection" setup.
342 */
344 const bool include_horizontal_advection = not (m_marginal and m_margin_exclude_horizontal_advection);
345 const bool include_strain_heating = not (m_marginal and m_margin_exclude_strain_heat);
346
347 const double
348 Rminus = m_R[0], // R_{-1/2}
349 Rplus = 0.5 * (m_R[0] + m_R[1]), // R_{+1/2}
350 mu_w = 0.5 * m_nu * m_w[0];
351
352 const double A_d = m_w[0] < 0.0 ? m_lambda - 1.0 : 1.0 - m_lambda;
353 const double A_u = m_w[0] < 0.0 ? 1.0 - m_lambda : m_lambda - 1.0;
354 const double A_b = m_w[0] < 0.0 ? -m_lambda : m_lambda - 2.0;
355
356 // diagonal entry
357 m_D0 = 1.0 + Rminus + Rplus + 2.0 * mu_w * A_d;
358 // upper-diagonal entry
359 m_U0 = - Rminus - Rplus + 2.0 * mu_w * A_u;
360 // right-hand side, excluding the strain heating term and the horizontal advection
361 m_B0 = m_Enth[0] + 2.0 * dE * m_dz * (-Rminus + mu_w * A_b);
362
363 // treat horizontal velocity using first-order upwinding:
364 double upwind_u = 0.0;
365 double upwind_v = 0.0;
366 if (include_horizontal_advection) {
367 upwind_u = upwind(m_u[0], m_E_w[0], m_Enth[0], m_E_e[0], 1.0 / m_dx);
368 upwind_v = upwind(m_v[0], m_E_s[0], m_Enth[0], m_E_n[0], 1.0 / m_dy);
369 }
370 double Sigma = 0.0;
371 if (include_strain_heating) {
372 Sigma = m_strain_heating[0];
373 }
374
375 m_B0 += m_dt * ((Sigma / m_ice_density) - upwind_u - upwind_v); // = rhs[m_ks]
376}
377
378
379//! \brief Assemble the R array. The R value switches at the CTS.
380/*! In a simple abstract diffusion
381 \f[ \frac{\partial u}{\partial t} = D \frac{\partial^2 u}{\partial z^2}, \f]
382with time steps \f$\Delta t\f$ and spatial steps \f$\Delta z\f$ we define
383 \f[ R = \frac{D \Delta t}{\Delta z^2}. \f]
384This is used in an implicit method to write each line in the linear system, for
385example [\ref MortonMayers]:
386 \f[ -R U_{j-1}^{n+1} + (1+2R) U_j^{n+1} - R U_{j+1}^{n+1} = U_j^n. \f]
387
388In the case of conservation of energy [\ref AschwandenBuelerKhroulevBlatter],
389 \f[ u=E \qquad \text{ and } \qquad D = \frac{K}{\rho} \qquad \text{ and } \qquad K = \frac{k}{c}. \f]
390Thus
391 \f[ R = \frac{k \Delta t}{\rho c \Delta z^2}. \f]
392 */
394 if (not m_k_depends_on_T) {
395
396 for (unsigned int k = 1; k <= m_ks; k++) {
397 m_R[k] = (m_Enth[k] < m_Enth_s[k]) ? m_R_cold : m_R_temp;
398 }
399 //still the cold ice value, if no temperate layer above
400 m_R[0] = (m_Enth[1] < m_Enth_s[1]) ? m_R_cold : m_R_temp;
401
402 } else {
403
404 for (unsigned int k = 1; k <= m_ks; k++) {
405 if (m_Enth[k] < m_Enth_s[k]) {
406 // cold case
407 const double depth = m_ice_thickness - k * m_dz;
408 double T = m_EC->temperature(m_Enth[k],
409 m_EC->pressure(depth)); // FIXME: issue #15
410
411 m_R[k] = ((m_k_depends_on_T ? k_from_T(T) : m_ice_k) / m_EC->c()) * m_R_factor;
412 } else {
413 // temperate case
414 m_R[k] = m_R_temp;
415 }
416 }
417 // still the cold ice value, if no temperate layer above
418 if (m_Enth[1] < m_Enth_s[1]) {
419 double T = m_EC->temperature(m_Enth[0],
420 m_EC->pressure(m_ice_thickness)); // FIXME: issue #15
421 m_R[0] = ((m_k_depends_on_T ? k_from_T(T) : m_ice_k) / m_EC->c()) * m_R_factor;
422 } else {
423 // temperate layer case
424 m_R[0] = m_R_temp;
425 }
426
427 }
428
429 // R[k] for k > m_ks are never used
430#if (Pism_DEBUG==1)
431 for (unsigned int k = m_ks + 1; k < m_R.size(); ++k) {
432 m_R[k] = NAN;
433 }
434#endif
435}
436
437
438/*! \brief Solve the tridiagonal system, in a single column, which
439 * determines the new values of the ice enthalpy.
440 *
441 * We are solving a convection-diffusion equation, treating the @f$ z @f$ direction implicitly and
442 * @f$ x, y @f$ directions explicitly. See @ref bombproofenth for the documentation of the treatment
443 * of convection terms. The notes below document the way we treat diffusion using a simplified PDE.
444 *
445 * To discretize
446 * @f[ \diff{}{z} \left( K(E) \diff{E}{z}\right) = \diff{E}{t} @f]
447 *
448 * at a location @f$ k @f$ of the vertical grid, we use centered finite differences in space,
449 * backward differences in time, and evaluate @f$ K(E) @f$ at staggered-grid locations:
450 *
451 * @f[ \frac{K_{k+\frac12}\frac{E_{k+1} - E_{k}}{\dz} - K_{k-\frac12}\frac{E_{k} - E_{k-1}}{\dz}}{\dz} = \frac{E_{k} - E^{n-1}_{k}}{\dt}, @f]
452 *
453 * where @f$ E = E^{n} @f$ for clarity and @f$ K_{k\pm \frac12} = K(E^{n-1}_{k\pm \frac12}) @f$,
454 * %i.e. we linearize this PDE by evaluating @f$ K(E) @f$ at the _previous_ time-step.
455 *
456 * We define
457 *
458 * @f[ R_i = \frac{\dt\, K_i}{\dz^2}, @f]
459 *
460 * and the discretization takes form
461 *
462 * @f[ -R_{k-\frac12} E_{k-1} + \left( 1 + R_{k-\frac12} + R_{k+\frac12} \right) E_{k} - R_{k+\frac12} E_{k+1} = E^{n-1}_{k}. @f]
463 *
464 * In the assembly of the tridiagonal system this corresponds to
465 *
466 * @f{align*}{
467 * L_i &= - \frac12 (R_{i} + R_{i-1}),\\
468 * D_i &= 1 + \frac12 (R_{i} + R_{i-1}) + \frac12 (R_{i} + R_{i+1}),\\
469 * U_i &= - \frac12 (R_{i} + R_{i+1}),\\
470 * b_i &= E^{n-1}_{i},
471 * @f}
472 *
473 * where @f$ L_i, D_i, U_i @f$ are lower-diagonal, diagonal, and upper-diagonal entries
474 * corresponding to an equation @f$ i @f$ and @f$ b_i @f$ is the corresponding right-hand side.
475 * (Staggered-grid values are approximated by interpolating from the regular grid).
476 *
477 * This method is _unconditionally stable_ and has a maximum principle (see [@ref MortonMayers,
478 * section 2.11]).
479 */
480void enthSystemCtx::solve(std::vector<double> &result) {
481
483
484#if (Pism_DEBUG==1)
486 if (std::isnan(m_D0) || std::isnan(m_U0) || std::isnan(m_B0)) {
488 "solveThisColumn() should only be called after\n"
489 " setting basal boundary condition in enthSystemCtx");
490 }
491#endif
492
493 // k=0 equation is already established
494 // L[0] = 0.0; // not used
495 S.D(0) = m_D0;
496 S.U(0) = m_U0;
497 S.RHS(0) = m_B0;
498
499 const double
500 one_over_rho = 1.0 / m_ice_density,
501 Dx = 1.0 / m_dx,
502 Dy = 1.0 / m_dy;
503
504 const bool include_horizontal_advection = not (m_marginal and m_margin_exclude_horizontal_advection);
505 const bool include_strain_heating = not (m_marginal and m_margin_exclude_strain_heat);
506
507 // generic ice segment in k location (if any; only runs if m_ks >= 2)
508 for (unsigned int k = 1; k < m_ks; k++) {
509 const double
510 Rminus = 0.5 * (m_R[k-1] + m_R[k]), // R_{k-1/2}
511 Rplus = 0.5 * (m_R[k] + m_R[k+1]), // R_{k+1/2}
512 nu_w = m_nu * m_w[k];
513
514 const double
515 A_l = m_w[k] >= 0.0 ? 0.5 * m_lambda - 1.0 : -0.5 * m_lambda,
516 A_d = m_w[k] >= 0.0 ? 1.0 - m_lambda : m_lambda - 1.0,
517 A_u = m_w[k] >= 0.0 ? 0.5 * m_lambda : 1.0 - 0.5 * m_lambda;
518
519 S.L(k) = - Rminus + nu_w * A_l;
520 S.D(k) = 1.0 + Rminus + Rplus + nu_w * A_d;
521 S.U(k) = - Rplus + nu_w * A_u;
522
523 // horizontal velocity and strain heating
524 double upwind_u = 0.0;
525 double upwind_v = 0.0;
526 if (include_horizontal_advection) {
527 upwind_u = upwind(m_u[k], m_E_w[k], m_Enth[k], m_E_e[k], Dx);
528 upwind_v = upwind(m_v[k], m_E_s[k], m_Enth[k], m_E_n[k], Dy);
529 }
530 double Sigma = 0.0;
531 if (include_strain_heating) {
532 Sigma = m_strain_heating[k];
533 }
534
535 S.RHS(k) = m_Enth[k] + m_dt * (one_over_rho * Sigma - upwind_u - upwind_v);
536 }
537
538 // Assemble the top surface equation. Values m_{L,D,U,B}_ks are set using set_surface_dirichlet()
539 // or set_surface_heat_flux().
540 if (m_ks > 0) {
541 S.L(m_ks) = m_L_ks;
542 }
543 S.D(m_ks) = m_D_ks;
544 if (m_ks < m_z.size() - 1) {
545 S.U(m_ks) = m_U_ks;
546 }
547 S.RHS(m_ks) = m_B_ks;
548
549 // Solve it; note drainage is not addressed yet and post-processing may occur
550 try {
551 S.solve(m_ks + 1, result);
552 }
553 catch (RuntimeError &e) {
554 e.add_context("solving the tri-diagonal system (enthSystemCtx) at (%d,%d)\n"
555 "saving system to m-file... ", m_i, m_j);
557 throw;
558 }
559
560 // air above
561 for (unsigned int k = m_ks+1; k < result.size(); k++) {
562 result[k] = m_B_ks;
563 }
564
565#if (Pism_DEBUG==1)
566 // if success, mark column as done by making scheme params and b.c. coeffs invalid
567 m_lambda = -1.0;
568 m_D0 = NAN;
569 m_U0 = NAN;
570 m_B0 = NAN;
571 m_L_ks = NAN;
572 m_D_ks = NAN;
573 m_U_ks = NAN;
574 m_B_ks = NAN;
575#endif
576}
577
578void enthSystemCtx::save_system(std::ostream &output, unsigned int system_size) const {
579 m_solver->save_system(output, system_size);
580 pism::TridiagonalSystem::save_vector(output, m_R, system_size, m_solver->prefix() + "_R");
581}
582
583} // end of namespace energy
584} // end of namespace pism
double get_number(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
bool get_flag(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
A class for storing and accessing PISM configuration flags and parameters.
std::shared_ptr< EnthalpyConverter > Ptr
void add_context(const std::string &message)
Add a message providing some context. This way we can (sort of) get a stack trace even though C++ exc...
void save_system(std::ostream &output, unsigned int system_size) const
View the tridiagonal system A x = b to an output stream, both A as a full matrix and b as a vector.
std::string prefix() const
static void save_vector(std::ostream &output, const std::vector< double > &v, unsigned int system_size, const std::string &variable)
Utility for simple ascii view of a vector (one-dimensional column) quantity.
Virtual base class. Abstracts a tridiagonal system to solve in a column of ice and/or bedrock.
A virtual class collecting methods common to ice and bedrock 3D fields.
Definition Array3D.hh:33
const array::Array3D & m_w3
void coarse_to_fine(const array::Array3D &input, int i, int j, double *output) const
void reportColumnZeroPivotErrorMFile(unsigned int M)
Write system matrix and right-hand-side into an Python script. The file name contains ZERO_PIVOT_ERRO...
std::vector< double > m_z
levels of the fine vertical grid
unsigned int m_ks
current system size; corresponds to the highest vertical level within the ice
std::vector< double > m_u
u-component of the ice velocity
const array::Array3D & m_u3
pointers to 3D velocity components
void init_column(int i, int j, double ice_thickness)
const array::Array3D & m_v3
int m_i
current column indexes
TridiagonalSystem * m_solver
std::vector< double > m_w
w-component of the ice velocity
std::vector< double > m_v
v-component of the ice velocity
Base class for tridiagonal systems in the ice.
void assemble_R()
Assemble the R array. The R value switches at the CTS.
std::vector< double > m_Enth_s
Definition enthSystem.hh:84
const array::Array3D & m_Enth3
std::vector< double > m_E_n
Definition enthSystem.hh:88
std::vector< double > m_E_w
Definition enthSystem.hh:88
std::vector< double > m_R
values of
Definition enthSystem.hh:94
const array::Array3D & m_strain_heating3
std::vector< double > m_Enth
Definition enthSystem.hh:82
void set_surface_neumann_bc(double dE)
Set enthalpy flux at the surface.
void compute_enthalpy_CTS()
Compute the CTS value of enthalpy in an ice column.
EnthalpyConverter::Ptr m_EC
void set_surface_heat_flux(double heat_flux)
Set the top surface heat flux into the ice.
enthSystemCtx(const std::vector< double > &storage_grid, const std::string &prefix, double dx, double dy, double dt, const Config &config, const array::Array3D &Enth3, const array::Array3D &u3, const array::Array3D &v3, const array::Array3D &w3, const array::Array3D &strain_heating3, EnthalpyConverter::Ptr EC)
Definition enthSystem.cc:31
void init(int i, int j, bool ismarginal, double ice_thickness)
void set_basal_neumann_bc(double dE)
Set enthalpy flux at the base.
std::vector< double > m_E_e
Definition enthSystem.hh:88
double k_from_T(double T) const
std::vector< double > m_strain_heating
strain heating in the ice column
Definition enthSystem.hh:91
virtual void save_system(std::ostream &output, unsigned int M) const
void set_basal_heat_flux(double heat_flux)
Set coefficients in discrete equation for Neumann condition at base of ice.
double m_D0
implicit FD method parameter
std::vector< double > m_E_s
Definition enthSystem.hh:88
void solve(std::vector< double > &result)
Solve the tridiagonal system, in a single column, which determines the new values of the ice enthalpy...
double compute_lambda()
Compute the lambda for BOMBPROOF.
void set_basal_dirichlet_bc(double E_basal)
Set coefficients in discrete equation for at base of ice.
void set_surface_dirichlet_bc(double E_surface)
#define PISM_ERROR_LOCATION
const double G
Definition exactTestK.c:40
bool marginal(const array::Scalar1 &thickness, int i, int j, double threshold)
static double upwind(double u, double E_m, double E, double E_p, double delta_inverse)
static const double k
Definition exactTestP.cc:42
static double S(unsigned n)
Definition test_cube.c:58