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
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
32namespace pism {
33namespace rheology {
34
35FlowLaw::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
66std::string FlowLaw::name() const {
67 return m_name;
68}
69
71 return m_EC;
72}
73
74double 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. */
80double 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.
88double 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
93double 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
98void 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
104void 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
113double FlowLaw::softness(double E, double p) const {
114 return this->softness_impl(E, p);
115}
116
117double FlowLaw::hardness(double E, double p) const {
118 return this->hardness_impl(E, p);
119}
120
121void 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
126void 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
133double 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 */
162void FlowLaw::effective_viscosity(double hardness, double gamma,
163 double *nu, double *dnu) const {
164 effective_viscosity(hardness, gamma, m_schoofReg, nu, dnu);
165}
166
167void 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 */
213double 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
263bool 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
Describes the PISM grid and the distribution of data across processors.
Definition Grid.hh:290
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:64
double * get_column(int i, int j)
Definition Array3D.cc:121
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:131
void update_ghosts()
Updates ghost points.
Definition Array.cc:615
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
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