PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
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 
27 namespace pism {
28 namespace energy {
29 
30 tempSystemCtx::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 
68 void 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 
125 void 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.
Definition: ColumnSystem.hh:86
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 &coarse, int i, int j, double *fine) 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)
Definition: tempSystem.cc:125
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)
Definition: tempSystem.cc:103
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
double min(const array::Scalar &input)
Finds minimum over all the values in an array::Scalar object. Ignores ghosts.
Definition: Scalar.cc:193
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