PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
ShallowStressBalance.cc
Go to the documentation of this file.
1// Copyright (C) 2010--2023, 2025 Constantine Khroulev and Ed Bueler
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/stressbalance/ShallowStressBalance.hh"
20#include "pism/basalstrength/basal_resistance.hh"
21#include "pism/rheology/FlowLawFactory.hh"
22#include "pism/stressbalance/SSB_diagnostics.hh"
23#include "pism/util/Context.hh"
24#include "pism/util/Vars.hh"
25#include "pism/util/array/CellType.hh"
26#include "pism/util/error_handling.hh"
27#include "pism/util/io/IO_Flags.hh"
28
29namespace pism {
30namespace stressbalance {
31
33 : Component(g),
34 m_basal_sliding_law(NULL),
35 m_flow_law(NULL),
36 m_EC(g->ctx()->enthalpy_converter()),
37 m_velocity(m_grid, "bar"),
38 m_basal_frictional_heating(m_grid, "bfrict"),
39 m_e_factor(1.0)
40{
41
42 if (m_config->get_flag("basal_resistance.pseudo_plastic.enabled")) {
44 } else if (m_config->get_flag("basal_resistance.regularized_coulomb.enabled")) {
46 } else {
48 }
49
51 .long_name("thickness-advective ice velocity (x-component)")
52 .units("m s^-1");
54 .long_name("thickness-advective ice velocity (y-component)")
55 .units("m s^-1");
56
58 .long_name("basal frictional heating")
59 .units("W m^-2")
60 .output_units("mW m^-2");
61}
62
66
68 this->init_impl();
69}
70
72 // empty
73}
74
76 return "";
77}
78
79std::shared_ptr<const rheology::FlowLaw> ShallowStressBalance::flow_law() const {
80 return m_flow_law;
81}
82
86
87std::shared_ptr<EnthalpyConverter> ShallowStressBalance::enthalpy_converter() const {
88 return m_EC;
89}
90
94
95//! \brief Get the thickness-advective 2D velocity.
99
100//! \brief Get the basal frictional heating (for the adaptive energy time-stepping).
104
105
107 DiagnosticList result = {
108 {"beta", Diagnostic::Ptr(new SSB_beta(this))},
109 {"taub", Diagnostic::Ptr(new SSB_taub(this))},
110 {"taub_mag", Diagnostic::Ptr(new SSB_taub_mag(this))},
111 {"taud", Diagnostic::Ptr(new SSB_taud(this))},
112 {"taud_mag", Diagnostic::Ptr(new SSB_taud_mag(this))}
113 };
114
115 if(m_config->get_flag("output.ISMIP6")) {
116 result["strbasemag"] = Diagnostic::Ptr(new SSB_taub_mag(this));
117 }
118
119 return result;
120}
121
122
123ZeroSliding::ZeroSliding(std::shared_ptr<const Grid> g)
125
127 // Use the SIA flow law.
128 m_flow_law = ice_factory.create(m_config->get_string("stress_balance.sia.flow_law"),
129 m_config->get_number("stress_balance.sia.Glen_exponent"));
130}
131
132//! \brief Update the trivial shallow stress balance object.
133void ZeroSliding::update(const Inputs &inputs, bool full_update) {
134 (void) inputs;
135
136 if (full_update) {
137 m_velocity.set(0.0);
139 }
140}
141
142//! \brief Compute the basal frictional heating.
143/*!
144 Ice shelves have zero basal friction heating.
145
146 \param[in] V *basal* sliding velocity
147 \param[in] tauc basal yield stress
148 \param[in] mask (used to determine if floating or grounded)
149 \param[out] result
150 */
152 const array::Scalar &tauc,
153 const array::CellType &mask,
154 array::Scalar &result) const {
155
156 array::AccessScope list{&V, &result, &tauc, &mask};
157
158 for (auto p : m_grid->points()) {
159 const int i = p.i(), j = p.j();
160
161 if (mask.ocean(i,j)) {
162 result(i,j) = 0.0;
163 } else {
164 const double
165 C = m_basal_sliding_law->drag(tauc(i,j), V(i,j).u, V(i,j).v),
166 basal_stress_x = - C * V(i,j).u,
167 basal_stress_y = - C * V(i,j).v;
168 result(i,j) = - basal_stress_x * V(i,j).u - basal_stress_y * V(i,j).v;
169 }
170 }
171}
172
173
176
177 // set metadata:
178 m_vars = { { m_sys, "taud_x", *m_grid }, { m_sys, "taud_y", *m_grid } };
179 m_vars[0].long_name("X-component of the driving shear stress at the base of ice");
180 m_vars[1].long_name("Y-component of the driving shear stress at the base of ice");
181
182 for (auto &v : m_vars) {
183 v.units("Pa");
184 v["comment"] = "this field is purely diagnostic (not used by the model)";
185 }
186}
187
188/*!
189 * The driving stress computed here is not used by the model, so this
190 * implementation intentionally does not use the eta-transformation or special
191 * cases at ice margins.
192 */
193std::shared_ptr<array::Array> SSB_taud::compute_impl() const {
194
195 auto result = allocate<array::Vector>("taud");
196
197 const array::Scalar *thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
198 const array::Scalar *surface = m_grid->variables().get_2d_scalar("surface_altitude");
199
200 double standard_gravity = m_config->get_number("constants.standard_gravity"),
201 ice_density = m_config->get_number("constants.ice.density");
202
203 array::AccessScope list{ surface, thickness, result.get() };
204
205 for (auto p : m_grid->points()) {
206 const int i = p.i(), j = p.j();
207
208 double pressure = ice_density * standard_gravity * (*thickness)(i, j);
209 if (pressure <= 0.0) {
210 (*result)(i, j).u = 0.0;
211 (*result)(i, j).v = 0.0;
212 } else {
213 (*result)(i, j).u = -pressure * diff_x_p(*surface, i, j);
214 (*result)(i, j).v = -pressure * diff_y_p(*surface, i, j);
215 }
216 }
217
218 return result;
219}
220
222 m_vars = { { m_sys, "taud_mag", *m_grid } };
223 m_vars[0]
224 .long_name("magnitude of the gravitational driving stress at the base of ice")
225 .units("Pa");
226 m_vars[0]["comment"] = "this field is purely diagnostic (not used by the model)";
227}
228
229std::shared_ptr<array::Array> SSB_taud_mag::compute_impl() const {
230 auto result = allocate<array::Scalar>("taud_mag");
231 auto taud = array::cast<array::Vector>(SSB_taud(model).compute());
232
233 compute_magnitude(*taud, *result);
234
235 return result;
236}
237
239 m_vars = { { m_sys, "taub_x", *m_grid }, { m_sys, "taub_y", *m_grid } };
240
241 m_vars[0].long_name("X-component of the shear stress at the base of ice");
242 m_vars[1].long_name("Y-component of the shear stress at the base of ice");
243
244 for (auto &v : m_vars) {
245 v.units("Pa");
246 v["comment"] = "this field is purely diagnostic (not used by the model)";
247 }
248}
249
250
251std::shared_ptr<array::Array> SSB_taub::compute_impl() const {
252
253 auto result = allocate<array::Vector>("taub");
254
255 const auto &velocity = model->velocity();
256 const auto *tauc = m_grid->variables().get_2d_scalar("tauc");
257 const auto &mask = *m_grid->variables().get_2d_cell_type("mask");
258
259 const IceBasalResistancePlasticLaw *basal_sliding_law = model->sliding_law();
260
261 array::AccessScope list{ tauc, &velocity, &mask, result.get() };
262 for (auto p : m_grid->points()) {
263 const int i = p.i(), j = p.j();
264
265 if (mask.grounded_ice(i, j)) {
266 double beta = basal_sliding_law->drag((*tauc)(i, j), velocity(i, j).u, velocity(i, j).v);
267 (*result)(i, j) = -beta * velocity(i, j);
268 } else {
269 (*result)(i, j) = 0.0;
270 }
271 }
272
273 return result;
274}
275
277
278 auto ismip6 = m_config->get_flag("output.ISMIP6");
279
280 m_vars = { { m_sys, ismip6 ? "strbasemag" : "taub_mag", *m_grid } };
281 m_vars[0]
282 .long_name("magnitude of the basal shear stress at the base of ice")
283 .standard_name("land_ice_basal_drag") // ISMIP6 "standard" name
284 .units("Pa");
285 m_vars[0]["comment"] = "this field is purely diagnostic (not used by the model)";
286}
287
288std::shared_ptr<array::Array> SSB_taub_mag::compute_impl() const {
289 auto result = allocate<array::Scalar>("taub_mag");
290
291 std::shared_ptr<array::Vector> taub = array::cast<array::Vector>(SSB_taub(model).compute());
292
293 compute_magnitude(*taub, *result);
294
295 return result;
296}
297
298/**
299 * Shallow stress balance class that reads `u` and `v` fields from a
300 * file and holds them constant.
301 *
302 * The only use I can think of right now is testing.
303 */
304PrescribedSliding::PrescribedSliding(std::shared_ptr<const Grid> g) : ZeroSliding(g) {
305 // empty
306}
307
308void PrescribedSliding::update(const Inputs &inputs, bool full_update) {
309 (void)inputs;
310 if (full_update) {
312 }
313}
314
317
318 auto input_filename = m_config->get_string("stress_balance.prescribed_sliding.file");
319
320 if (input_filename.empty()) {
321 throw RuntimeError(PISM_ERROR_LOCATION, "stress_balance.prescribed_sliding.file is required.");
322 }
323
324 m_velocity.regrid(input_filename, io::Default::Nil());
325}
326
328 m_vars = { { m_sys, "beta", *m_grid } };
329 m_vars[0].long_name("basal drag coefficient").units("Pa s / m");
330}
331
332std::shared_ptr<array::Array> SSB_beta::compute_impl() const {
333 auto result = allocate<array::Scalar>("beta");
334
335 const array::Scalar *tauc = m_grid->variables().get_2d_scalar("tauc");
336
337 const IceBasalResistancePlasticLaw *basal_sliding_law = model->sliding_law();
338
339 const array::Vector &velocity = model->velocity();
340
341 array::AccessScope list{tauc, &velocity, result.get()};
342 for (auto p : m_grid->points()) {
343 const int i = p.i(), j = p.j();
344
345 (*result)(i,j) = basal_sliding_law->drag((*tauc)(i,j), velocity(i,j).u, velocity(i,j).v);
346 }
347
348 return result;
349}
350
351} // end of namespace stressbalance
352} // end of namespace pism
std::shared_ptr< const Config > m_config
configuration database used by this component
Definition Component.hh:160
const std::shared_ptr< const Grid > m_grid
grid used by this component
Definition Component.hh:158
A class defining a common interface for most PISM sub-models.
Definition Component.hh:118
const ShallowStressBalance * model
A template derived from Diagnostic, adding a "Model".
std::vector< VariableMetadata > m_vars
metadata corresponding to NetCDF variables
const units::System::Ptr m_sys
the unit system
std::shared_ptr< const Config > m_config
Configuration flags and parameters.
std::shared_ptr< Diagnostic > Ptr
Definition Diagnostic.hh:67
std::shared_ptr< const Grid > m_grid
the grid
std::shared_ptr< array::Array > compute() const
Compute a diagnostic quantity and return a pointer to a newly-allocated Array.
virtual double drag(double tauc, double vx, double vy) const
Compute the drag coefficient for the basal shear stress.
Class containing physical constants and the constitutive relation describing till for SSA.
VariableMetadata & long_name(const std::string &input)
VariableMetadata & units(const std::string &input)
VariableMetadata & output_units(const std::string &input)
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition Array.hh:66
void set(double c)
Result: v[j] <- c for all j.
Definition Array.cc:659
void regrid(const std::string &filename, io::Default default_value)
Definition Array.cc:758
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
Definition Array.cc:467
bool ocean(int i, int j) const
Definition CellType.hh:34
"Cell type" mask. Adds convenience methods to array::Scalar.
Definition CellType.hh:30
static Default Nil()
Definition IO_Flags.hh:94
std::shared_ptr< FlowLaw > create(const std::string &type_name, double exponent)
PrescribedSliding(std::shared_ptr< const Grid > g)
virtual void update(const Inputs &inputs, bool full_update)
Update the trivial shallow stress balance object.
virtual std::shared_ptr< array::Array > compute_impl() const
SSB_beta(const ShallowStressBalance *m)
SSB_taub_mag(const ShallowStressBalance *m)
virtual std::shared_ptr< array::Array > compute_impl() const
Computes the magnitude of the basal shear stress (diagnostically).
SSB_taub(const ShallowStressBalance *m)
virtual std::shared_ptr< array::Array > compute_impl() const
Computes the basal shear stress .
virtual std::shared_ptr< array::Array > compute_impl() const
SSB_taud_mag(const ShallowStressBalance *m)
Computes the magnitude of the gravitational driving stress (diagnostically).
virtual std::shared_ptr< array::Array > compute_impl() const
SSB_taud(const ShallowStressBalance *m)
Computes the gravitational driving stress (diagnostically).
const array::Vector1 & velocity() const
Get the thickness-advective 2D velocity.
void compute_basal_frictional_heating(const array::Vector &velocity, const array::Scalar &tauc, const array::CellType &mask, array::Scalar &result) const
Compute the basal frictional heating.
std::shared_ptr< const rheology::FlowLaw > flow_law() const
ShallowStressBalance(std::shared_ptr< const Grid > g)
std::shared_ptr< rheology::FlowLaw > m_flow_law
virtual DiagnosticList spatial_diagnostics_impl() const
IceBasalResistancePlasticLaw * m_basal_sliding_law
const IceBasalResistancePlasticLaw * sliding_law() const
virtual std::string stdout_report() const
Produce a report string for the standard output.
const array::Scalar & basal_frictional_heating()
Get the basal frictional heating (for the adaptive energy time-stepping).
std::shared_ptr< EnthalpyConverter > m_EC
std::shared_ptr< EnthalpyConverter > enthalpy_converter() const
Shallow stress balance (such as the SSA).
virtual void update(const Inputs &inputs, bool full_update)
Update the trivial shallow stress balance object.
ZeroSliding(std::shared_ptr< const Grid > g)
Returns zero velocity field, zero friction heating, and zero for D^2.
#define PISM_ERROR_LOCATION
static const double g
Definition exactTestP.cc:36
std::map< std::string, Diagnostic::Ptr > DiagnosticList