PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
FlowLaw.cc
Go to the documentation of this file.
1 // Copyright (C) 2004-2018, 2020, 2021, 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 "pism/rheology/FlowLaw.hh"
20 
21 #include <petsc.h>
22 
23 #include "pism/util/EnthalpyConverter.hh"
24 #include "pism/util/array/Scalar.hh"
25 #include "pism/util/array/Array3D.hh"
26 
27 #include "pism/util/ConfigInterface.hh"
28 #include "pism/util/Grid.hh"
29 
30 #include "pism/util/error_handling.hh"
31 
32 namespace pism {
33 namespace rheology {
34 
35 FlowLaw::FlowLaw(const std::string &prefix, const Config &config,
37  : m_EC(ec) {
38 
39  if (not m_EC) {
40  throw RuntimeError(PISM_ERROR_LOCATION, "EC is NULL in FlowLaw::FlowLaw()");
41  }
42 
43  m_standard_gravity = config.get_number("constants.standard_gravity");
44  m_ideal_gas_constant = config.get_number("constants.ideal_gas_constant");
45 
46  m_rho = config.get_number("constants.ice.density");
47  m_beta_CC_grad = config.get_number("constants.ice.beta_Clausius_Clapeyron") * m_rho * m_standard_gravity;
48  m_melting_point_temp = config.get_number("constants.fresh_water.melting_point_temperature");
49  m_n = config.get_number(prefix + "Glen_exponent");
50  m_viscosity_power = (1.0 - m_n) / (2.0 * m_n);
51  m_hardness_power = -1.0 / m_n;
52 
53  m_A_cold = config.get_number("flow_law.Paterson_Budd.A_cold");
54  m_A_warm = config.get_number("flow_law.Paterson_Budd.A_warm");
55  m_Q_cold = config.get_number("flow_law.Paterson_Budd.Q_cold");
56  m_Q_warm = config.get_number("flow_law.Paterson_Budd.Q_warm");
57  m_crit_temp = config.get_number("flow_law.Paterson_Budd.T_critical");
58 
59  double
60  schoofLen = config.get_number("flow_law.Schoof_regularizing_length", "m"),
61  schoofVel = config.get_number("flow_law.Schoof_regularizing_velocity", "m second-1");
62 
63  m_schoofReg = PetscSqr(schoofVel / schoofLen);
64 }
65 
66 std::string FlowLaw::name() const {
67  return m_name;
68 }
69 
71  return m_EC;
72 }
73 
74 double FlowLaw::exponent() const {
75  return m_n;
76 }
77 
78 //! Return the softness parameter A(T) for a given temperature T.
79 /*! This is not a natural part of all FlowLaw instances. */
80 double FlowLaw::softness_paterson_budd(double T_pa) const {
81  const double A = T_pa < m_crit_temp ? m_A_cold : m_A_warm;
82  const double Q = T_pa < m_crit_temp ? m_Q_cold : m_Q_warm;
83 
84  return A * exp(-Q / (m_ideal_gas_constant * T_pa));
85 }
86 
87 //! The flow law itself.
88 double FlowLaw::flow(double stress, double enthalpy,
89  double pressure, double grain_size) const {
90  return this->flow_impl(stress, enthalpy, pressure, grain_size);
91 }
92 
93 double FlowLaw::flow_impl(double stress, double enthalpy,
94  double pressure, double /* gs */) const {
95  return softness(enthalpy, pressure) * pow(stress, m_n-1);
96 }
97 
98 void FlowLaw::flow_n(const double *stress, const double *enthalpy,
99  const double *pressure, const double *grainsize,
100  unsigned int n, double *result) const {
101  this->flow_n_impl(stress, enthalpy, pressure, grainsize, n, result);
102 }
103 
104 void FlowLaw::flow_n_impl(const double *stress, const double *enthalpy,
105  const double *pressure, const double *grainsize,
106  unsigned int n, double *result) const {
107  for (unsigned int k = 0; k < n; ++k) {
108  result[k] = this->flow(stress[k], enthalpy[k], pressure[k], grainsize[k]);
109  }
110 }
111 
112 
113 double FlowLaw::softness(double E, double p) const {
114  return this->softness_impl(E, p);
115 }
116 
117 double FlowLaw::hardness(double E, double p) const {
118  return this->hardness_impl(E, p);
119 }
120 
121 void FlowLaw::hardness_n(const double *enthalpy, const double *pressure,
122  unsigned int n, double *result) const {
123  this->hardness_n_impl(enthalpy, pressure, n, result);
124 }
125 
126 void FlowLaw::hardness_n_impl(const double *enthalpy, const double *pressure,
127  unsigned int n, double *result) const {
128  for (unsigned int k = 0; k < n; ++k) {
129  result[k] = this->hardness(enthalpy[k], pressure[k]);
130  }
131 }
132 
133 double FlowLaw::hardness_impl(double E, double p) const {
134  return pow(softness(E, p), m_hardness_power);
135 }
136 
137 //! \brief Computes the regularized effective viscosity and its derivative with respect to the
138 //! second invariant \f$ \gamma \f$.
139 /*!
140  *
141  * @f{align*}{
142  * \nu &= \frac{1}{2} B \left( \epsilon + \gamma \right)^{(1-n)/(2n)},\\
143  * \diff{\nu}{\gamma} &= \frac{1}{2} B \cdot \frac{1-n}{2n} \cdot \left(\epsilon + \gamma \right)^{(1-n)/(2n) - 1}, \\
144  * &= \frac{1-n}{2n} \cdot \frac{1}{2} B \left( \epsilon + \gamma \right)^{(1-n)/(2n)} \cdot \frac{1}{\epsilon + \gamma}, \\
145  * &= \frac{1-n}{2n} \cdot \frac{\nu}{\epsilon + \gamma}.
146  * @f}
147  * Here @f$ \gamma @f$ is the second invariant
148  * @f{align*}{
149  * \gamma &= \frac{1}{2} D_{ij} D_{ij}\\
150  * &= \frac{1}{2}\, ((u_x)^2 + (v_y)^2 + (u_x + v_y)^2 + \frac{1}{2}\, (u_y + v_x)^2) \\
151  * @f}
152  * and
153  * @f[ D_{ij}(\mathbf{u}) = \frac{1}{2}\left(\diff{u_{i}}{x_{j}} + \diff{u_{j}}{x_{i}}\right). @f]
154  *
155  * Either one of \c nu and \c dnu can be NULL if the corresponding output is not needed.
156  *
157  * \param[in] B ice hardness
158  * \param[in] gamma the second invariant
159  * \param[out] nu effective viscosity
160  * \param[out] dnu derivative of \f$ \nu \f$ with respect to \f$ \gamma \f$
161  */
162 void FlowLaw::effective_viscosity(double hardness, double gamma,
163  double *nu, double *dnu) const {
164  effective_viscosity(hardness, gamma, m_schoofReg, nu, dnu);
165 }
166 
167 void FlowLaw::effective_viscosity(double hardness, double gamma, double eps,
168  double *nu, double *dnu) const {
169  const double
170  my_nu = 0.5 * hardness * pow(eps + gamma, m_viscosity_power);
171 
172  if (PetscLikely(nu != NULL)) {
173  *nu = my_nu;
174  }
175 
176  if (PetscLikely(dnu != NULL)) {
177  *dnu = m_viscosity_power * my_nu / (eps + gamma);
178  }
179 }
180 
182  const array::Scalar &thickness,
183  const array::Array3D &enthalpy,
184  array::Scalar &result) {
185 
186  const Grid &grid = *thickness.grid();
187 
188  array::AccessScope list{&thickness, &result, &enthalpy};
189 
190  ParallelSection loop(grid.com);
191  try {
192  for (auto p = grid.points(); p; p.next()) {
193  const int i = p.i(), j = p.j();
194 
195  // Evaluate column integrals in flow law at every quadrature point's column
196  double H = thickness(i,j);
197  const double *enthColumn = enthalpy.get_column(i, j);
198  result(i,j) = averaged_hardness(ice, H, grid.kBelowHeight(H),
199  grid.z().data(), enthColumn);
200  }
201  } catch (...) {
202  loop.failed();
203  }
204  loop.check();
205 
206  result.update_ghosts();
207 }
208 
209 //! Computes vertical average of `B(E, p)` ice hardness, namely @f$\bar B(E, p)@f$.
210 /*!
211  * See comment for hardness(). Note `E[0], ..., E[kbelowH]` must be valid.
212  */
213 double averaged_hardness(const FlowLaw &ice,
214  double thickness,
215  unsigned int kbelowH,
216  const double *zlevels,
217  const double *enthalpy) {
218  double B = 0;
219 
220  const auto &EC = *ice.EC();
221 
222  // Use trapezoidal rule to integrate from 0 to zlevels[kbelowH]:
223  if (kbelowH > 0) {
224  double
225  p0 = EC.pressure(thickness),
226  E0 = enthalpy[0],
227  h0 = ice.hardness(E0, p0); // ice hardness at the left endpoint
228 
229  for (unsigned int i = 1; i <= kbelowH; ++i) { // note the "1" and the "<="
230  const double
231  p1 = EC.pressure(thickness - zlevels[i]), // pressure at the right endpoint
232  E1 = enthalpy[i], // enthalpy at the right endpoint
233  h1 = ice.hardness(E1, p1); // ice hardness at the right endpoint
234 
235  // The trapezoid rule sans the "1/2":
236  B += (zlevels[i] - zlevels[i-1]) * (h0 + h1);
237 
238  h0 = h1;
239  }
240  }
241 
242  // Add the "1/2":
243  B *= 0.5;
244 
245  // use the "rectangle method" to integrate from
246  // zlevels[kbelowH] to thickness:
247  double
248  depth = thickness - zlevels[kbelowH],
249  p = EC.pressure(depth);
250 
251  B += depth * ice.hardness(enthalpy[kbelowH], p);
252 
253  // Now B is an integral of ice hardness; next, compute the average:
254  if (thickness > 0) {
255  B = B / thickness;
256  } else {
257  B = 0;
258  }
259 
260  return B;
261 }
262 
263 bool FlowLawUsesGrainSize(const FlowLaw &flow_law) {
264  static const double gs[] = {1e-4, 1e-3, 1e-2, 1}, s=1e4, E=400000, p=1e6;
265  double ref = flow_law.flow(s, E, p, gs[0]);
266  for (int i=1; i<4; i++) {
267  if (flow_law.flow(s, E, p, gs[i]) != ref) {
268  return true;
269  }
270  }
271  return false;
272 }
273 
274 } // end of namespace rheology
275 } // 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.
std::shared_ptr< EnthalpyConverter > Ptr
unsigned int kBelowHeight(double height) const
Return the index k into zlevels[] so that zlevels[k] <= height < zlevels[k+1] and k < Mz.
Definition: Grid.cc:291
PointsWithGhosts points(unsigned int stencil_width=0) const
Definition: Grid.hh:362
const std::vector< double > & z() const
Z-coordinates within the ice.
Definition: Grid.cc:786
const MPI_Comm com
Definition: Grid.hh:355
Describes the PISM grid and the distribution of data across processors.
Definition: Grid.hh:282
void failed()
Indicates a failure of a parallel section.
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition: Array.hh:65
double * get_column(int i, int j)
Definition: Array3D.cc:120
A virtual class collecting methods common to ice and bedrock 3D fields.
Definition: Array3D.hh:33
std::shared_ptr< const Grid > grid() const
Definition: Array.cc:132
void update_ghosts()
Updates ghost points.
Definition: Array.cc:693
double m_crit_temp
critical temperature (cold – warm transition)
Definition: FlowLaw.hh:147
double softness_paterson_budd(double T_pa) const
Return the softness parameter A(T) for a given temperature T.
Definition: FlowLaw.cc:80
double m_schoofReg
regularization parameter for
Definition: FlowLaw.hh:131
virtual double hardness_impl(double E, double p) const
Definition: FlowLaw.cc:133
double m_A_warm
Paterson-Budd softness, warm case.
Definition: FlowLaw.hh:141
double m_A_cold
Paterson-Budd softness, cold case.
Definition: FlowLaw.hh:139
double m_Q_cold
Activation energy, cold case.
Definition: FlowLaw.hh:143
double m_standard_gravity
acceleration due to gravity
Definition: FlowLaw.hh:150
double m_viscosity_power
; used to compute viscosity
Definition: FlowLaw.hh:134
void flow_n(const double *stress, const double *E, const double *pressure, const double *grainsize, unsigned int n, double *result) const
Definition: FlowLaw.cc:98
virtual void hardness_n_impl(const double *enthalpy, const double *pressure, unsigned int n, double *result) const
Definition: FlowLaw.cc:126
void effective_viscosity(double hardness, double gamma, double *nu, double *dnu) const
Computes the regularized effective viscosity and its derivative with respect to the second invariant ...
Definition: FlowLaw.cc:162
void hardness_n(const double *enthalpy, const double *pressure, unsigned int n, double *result) const
Definition: FlowLaw.cc:121
std::string name() const
Definition: FlowLaw.cc:66
double exponent() const
Definition: FlowLaw.cc:74
FlowLaw(const std::string &prefix, const Config &config, EnthalpyConverter::Ptr EC)
Definition: FlowLaw.cc:35
std::string m_name
Definition: FlowLaw.hh:117
double softness(double E, double p) const
Definition: FlowLaw.cc:113
virtual double softness_impl(double E, double p) const =0
double m_rho
ice density
Definition: FlowLaw.hh:120
double m_hardness_power
; used to compute hardness
Definition: FlowLaw.hh:136
double m_melting_point_temp
melting point temperature (for water, 273.15 K)
Definition: FlowLaw.hh:124
EnthalpyConverter::Ptr EC() const
Definition: FlowLaw.cc:70
double m_beta_CC_grad
Clausius-Clapeyron gradient.
Definition: FlowLaw.hh:122
double flow(double stress, double enthalpy, double pressure, double grain_size) const
The flow law itself.
Definition: FlowLaw.cc:88
double m_ideal_gas_constant
ideal gas constant
Definition: FlowLaw.hh:152
virtual double flow_impl(double stress, double E, double pressure, double grainsize) const
Definition: FlowLaw.cc:93
double m_Q_warm
Activation energy, warm case.
Definition: FlowLaw.hh:145
double m_n
power law exponent
Definition: FlowLaw.hh:154
double hardness(double E, double p) const
Definition: FlowLaw.cc:117
EnthalpyConverter::Ptr m_EC
Definition: FlowLaw.hh:126
virtual void flow_n_impl(const double *stress, const double *E, const double *pressure, const double *grainsize, unsigned int n, double *result) const
Definition: FlowLaw.cc:104
#define PISM_ERROR_LOCATION
#define n
Definition: exactTestM.c:37
void averaged_hardness_vec(const FlowLaw &ice, const array::Scalar &thickness, const array::Array3D &enthalpy, array::Scalar &result)
Definition: FlowLaw.cc:181
double averaged_hardness(const FlowLaw &ice, double thickness, unsigned int kbelowH, const double *zlevels, const double *enthalpy)
Computes vertical average of B(E, p) ice hardness, namely .
Definition: FlowLaw.cc:213
bool FlowLawUsesGrainSize(const FlowLaw &flow_law)
Definition: FlowLaw.cc:263
static const double k
Definition: exactTestP.cc:42
static const double h0
Definition: exactTestP.cc:49