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
tempSystem.cc
Go to the documentation of this file.
1// Copyright (C) 2004-2011, 2013, 2014, 2015, 2016, 2017, 2018, 2022, 2023 Jed Brown, 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 <cassert>
20#include <cmath>
21
22#include "pism/energy/tempSystem.hh"
23#include "pism/util/Mask.hh"
24
25#include "pism/util/error_handling.hh"
26
27namespace pism {
28namespace energy {
29
30tempSystemCtx::tempSystemCtx(const std::vector<double>& storage_grid,
31 const std::string &prefix,
32 double dx, double dy, double dt,
33 const Config &config,
34 const array::Array3D &T3,
35 const array::Array3D &u3,
36 const array::Array3D &v3,
37 const array::Array3D &w3,
38 const array::Array3D &strain_heating3)
39 : columnSystemCtx(storage_grid, prefix, dx, dy, dt, u3, v3, w3),
40 m_T3(T3),
41 m_strain_heating3(strain_heating3) {
42
43 // set flags to indicate nothing yet set
44 m_surfBCsValid = false;
45 m_basalBCsValid = false;
46
47 size_t Mz = m_z.size();
48 m_T.resize(Mz);
49 m_strain_heating.resize(Mz);
50
51 m_T_n.resize(Mz);
52 m_T_e.resize(Mz);
53 m_T_s.resize(Mz);
54 m_T_w.resize(Mz);
55
56 // set physical constants
57 m_ice_density = config.get_number("constants.ice.density");
58 m_ice_c = config.get_number("constants.ice.specific_heat_capacity");
59 m_ice_k = config.get_number("constants.ice.thermal_conductivity");
60
61 // set derived constants
62 m_nu = m_dt / m_dz;
65 m_iceR = m_iceK * m_dt / (m_dz*m_dz);
66}
67
68void tempSystemCtx::initThisColumn(int i, int j, bool is_marginal, MaskValue mask,
69 double ice_thickness) {
70
71 m_is_marginal = is_marginal;
72 m_mask = mask;
73
74 init_column(i, j, ice_thickness);
75
76 if (m_ks == 0) {
77 return;
78 }
79
80 coarse_to_fine(m_u3, m_i, m_j, m_u.data());
81 coarse_to_fine(m_v3, m_i, m_j, m_v.data());
82 coarse_to_fine(m_w3, m_i, m_j, m_w.data());
84 coarse_to_fine(m_T3, m_i, m_j, m_T.data());
85
86 coarse_to_fine(m_T3, m_i, m_j+1, m_T_n.data());
87 coarse_to_fine(m_T3, m_i+1, m_j, m_T_e.data());
88 coarse_to_fine(m_T3, m_i, m_j-1, m_T_s.data());
89 coarse_to_fine(m_T3, m_i-1, m_j, m_T_w.data());
90
92}
93
95 // allow setting surface BCs only once:
96 assert(not m_surfBCsValid);
97
98 m_Ts = my_Ts;
99 m_surfBCsValid = true;
100}
101
102
104 double my_Tshelfbase, double my_Rb) {
105 // allow setting basal BCs only once:
106 assert(not m_basalBCsValid);
107
108 m_G0 = my_G0;
109 m_Tshelfbase = my_Tshelfbase;
110 m_Rb = my_Rb;
111 m_basalBCsValid = true;
112}
113
115 double result = 1.0; // start with centered implicit for more accuracy
116 const double epsilon = 1e-6 / 3.15569259747e7;
117
118 for (unsigned int k = 0; k <= m_ks; k++) {
119 const double denom = (fabs(m_w[k]) + epsilon) * m_ice_density * m_ice_c * m_dz;
120 result = std::min(result, 2.0 * m_ice_k / denom);
121 }
122 return result;
123}
124
125void tempSystemCtx::solveThisColumn(std::vector<double> &x) {
126
128
129 assert(m_surfBCsValid == true);
130 assert(m_basalBCsValid == true);
131
132 // bottom of ice; k=0 eqn
133 if (m_ks == 0) { // no ice; set m_T[0] to surface temp if grounded
134 // note L[0] not allocated
135 S.D(0) = 1.0;
136 S.U(0) = 0.0;
137 // if floating and no ice then worry only about bedrock temps
138 if (mask::ocean(m_mask)) {
139 // essentially no ice but floating ... ask OceanCoupler
140 S.RHS(0) = m_Tshelfbase;
141 } else { // top of bedrock sees atmosphere
142 S.RHS(0) = m_Ts;
143 }
144 } else { // m_ks > 0; there is ice
145 // for w, always difference *up* from base, but make it implicit
146 if (mask::ocean(m_mask)) {
147 // just apply Dirichlet condition to base of column of ice in an ice shelf
148 // note that L[0] is not used
149 S.D(0) = 1.0;
150 S.U(0) = 0.0;
151 S.RHS(0) = m_Tshelfbase; // set by OceanCoupler
152 } else {
153 // there is *grounded* ice; from FV across interface
154 S.RHS(0) = m_T[0] + m_dt * (m_Rb / (m_rho_c_I * m_dz));
155
156 double Sigma = 0.0;
157 if (not m_is_marginal) {
158 Sigma = m_strain_heating[0];
159 }
160 S.RHS(0) += m_dt * 0.5 * Sigma / m_rho_c_I;
161
162 double UpTu = 0.0;
163 double UpTv = 0.0;
164 if (not m_is_marginal) {
165 UpTu = (m_u[0] < 0 ?
166 m_u[0] * (m_T_e[0] - m_T[0]) / m_dx :
167 m_u[0] * (m_T[0] - m_T_w[0]) / m_dx);
168 UpTv = (m_v[0] < 0 ?
169 m_v[0] * (m_T_n[0] - m_T[0]) / m_dy :
170 m_v[0] * (m_T[0] - m_T_s[0]) / m_dy);
171 }
172 S.RHS(0) -= m_dt * (0.5 * (UpTu + UpTv));
173
174 // vertical upwinding
175 // L[0] = 0.0; (is not used)
176 S.D(0) = 1.0 + 2.0 * m_iceR;
177 S.U(0) = - 2.0 * m_iceR;
178 if (m_w[0] < 0.0) { // velocity downward: add velocity contribution
179 const double AA = m_dt * m_w[0] / (2.0 * m_dz);
180 S.D(0) -= AA;
181 S.U(0) += AA;
182 }
183 // apply geothermal flux G0 here
184 S.RHS(0) += 2.0 * m_dt * m_G0 / (m_rho_c_I * m_dz);
185 }
186 }
187
188 // generic ice segment; build 1:m_ks-1 eqns
189 for (unsigned int k = 1; k < m_ks; k++) {
190 const double AA = m_nu * m_w[k];
191 if (m_w[k] >= 0.0) { // velocity upward
192 S.L(k) = - m_iceR - AA * (1.0 - m_lambda/2.0);
193 S.D(k) = 1.0 + 2.0 * m_iceR + AA * (1.0 - m_lambda);
194 S.U(k) = - m_iceR + AA * (m_lambda/2.0);
195 } else { // velocity downward
196 S.L(k) = - m_iceR - AA * (m_lambda/2.0);
197 S.D(k) = 1.0 + 2.0 * m_iceR - AA * (1.0 - m_lambda);
198 S.U(k) = - m_iceR + AA * (1.0 - m_lambda/2.0);
199 }
200 S.RHS(k) = m_T[k];
201
202 double Sigma = 0.0;
203 if (not m_is_marginal) {
204 Sigma = m_strain_heating[k];
205 }
206
207 double UpTu = 0.0;
208 double UpTv = 0.0;
209 if (not m_is_marginal) {
210 UpTu = (m_u[k] < 0 ?
211 m_u[k] * (m_T_e[k] - m_T[k]) / m_dx :
212 m_u[k] * (m_T[k] - m_T_w[k]) / m_dx);
213 UpTv = (m_v[k] < 0 ?
214 m_v[k] * (m_T_n[k] - m_T[k]) / m_dy :
215 m_v[k] * (m_T[k] - m_T_s[k]) / m_dy);
216 }
217
218 S.RHS(k) += m_dt * (Sigma / m_rho_c_I - UpTu - UpTv);
219 }
220
221 // surface b.c.
222 if (m_ks>0) {
223 S.L(m_ks) = 0.0;
224 S.D(m_ks) = 1.0;
225 // ignore U[m_ks]
226 S.RHS(m_ks) = m_Ts;
227 }
228
229 // mark column as done
230 m_surfBCsValid = false;
231 m_basalBCsValid = false;
232
233 // solve it; note melting not addressed yet
234 try {
235 S.solve(m_ks + 1, x);
236 }
237 catch (RuntimeError &e) {
238 e.add_context("solving the tri-diagonal system (tempSystemCtx) at (%d,%d)\n"
239 "saving system to m-file... ", m_i, m_j);
241 throw;
242 }
243}
244
245
246} // end of namespace energy
247} // end of namespace pism
double get_number(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
A class for storing and accessing PISM configuration flags and parameters.
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...
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.
const array::Array3D & m_T3
Definition tempSystem.hh:78
void initThisColumn(int i, int j, bool is_marginal, MaskValue new_mask, double ice_thickness)
Definition tempSystem.cc:68
void setSurfaceBoundaryValuesThisColumn(double my_Ts)
Definition tempSystem.cc:94
void solveThisColumn(std::vector< double > &x)
std::vector< double > m_T_n
Definition tempSystem.hh:81
std::vector< double > m_T_e
Definition tempSystem.hh:81
const array::Array3D & m_strain_heating3
Definition tempSystem.hh:78
std::vector< double > m_strain_heating
Definition tempSystem.hh:80
tempSystemCtx(const std::vector< double > &storage_grid, const std::string &prefix, double dx, double dy, double dt, const Config &config, const array::Array3D &T3, const array::Array3D &u3, const array::Array3D &v3, const array::Array3D &w3, const array::Array3D &strain_heating3)
Definition tempSystem.cc:30
void setBasalBoundaryValuesThisColumn(double my_G0, double my_Tshelfbase, double my_Rb)
std::vector< double > m_T_s
Definition tempSystem.hh:81
std::vector< double > m_T
Definition tempSystem.hh:80
std::vector< double > m_T_w
Definition tempSystem.hh:81
bool ocean(int M)
An ocean cell (floating ice or ice-free).
Definition Mask.hh:40
static const double k
Definition exactTestP.cc:42
MaskValue
Definition Mask.hh:30
static double S(unsigned n)
Definition test_cube.c:58