Loading [MathJax]/extensions/tex2jax.js
PISM, A Parallel Ice Sheet Model 2.2.1-cd005eec8 committed by Constantine Khrulev on 2025-03-07
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ShallowStressBalance.cc
Go to the documentation of this file.
1// Copyright (C) 2010--2023 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
28namespace pism {
29namespace stressbalance {
30
32 : Component(g),
33 m_basal_sliding_law(NULL),
34 m_flow_law(NULL),
35 m_EC(g->ctx()->enthalpy_converter()),
36 m_velocity(m_grid, "bar"),
37 m_basal_frictional_heating(m_grid, "bfrict"),
38 m_e_factor(1.0)
39{
40
41 if (m_config->get_flag("basal_resistance.pseudo_plastic.enabled")) {
43 } else if (m_config->get_flag("basal_resistance.regularized_coulomb.enabled")) {
45 } else {
47 }
48
50 .long_name("thickness-advective ice velocity (x-component)")
51 .units("m s^-1");
53 .long_name("thickness-advective ice velocity (y-component)")
54 .units("m s^-1");
55
57 .long_name("basal frictional heating")
58 .units("W m^-2")
59 .output_units("mW m^-2");
60}
61
65
67 this->init_impl();
68}
69
71 // empty
72}
73
75 return "";
76}
77
78std::shared_ptr<const rheology::FlowLaw> ShallowStressBalance::flow_law() const {
79 return m_flow_law;
80}
81
85
89
93
94//! \brief Get the thickness-advective 2D velocity.
98
99//! \brief Get the basal frictional heating (for the adaptive energy time-stepping).
103
104
106 DiagnosticList result = {
107 {"beta", Diagnostic::Ptr(new SSB_beta(this))},
108 {"taub", Diagnostic::Ptr(new SSB_taub(this))},
109 {"taub_mag", Diagnostic::Ptr(new SSB_taub_mag(this))},
110 {"taud", Diagnostic::Ptr(new SSB_taud(this))},
111 {"taud_mag", Diagnostic::Ptr(new SSB_taud_mag(this))}
112 };
113
114 if(m_config->get_flag("output.ISMIP6")) {
115 result["strbasemag"] = Diagnostic::Ptr(new SSB_taub_mag(this));
116 }
117
118 return result;
119}
120
121
122ZeroSliding::ZeroSliding(std::shared_ptr<const Grid> g)
124
125 // Use the SIA flow law.
126 rheology::FlowLawFactory ice_factory("stress_balance.sia.", m_config, m_EC);
127 m_flow_law = ice_factory.create();
128}
129
130//! \brief Update the trivial shallow stress balance object.
131void ZeroSliding::update(const Inputs &inputs, bool full_update) {
132 (void) inputs;
133
134 if (full_update) {
135 m_velocity.set(0.0);
137 }
138}
139
140//! \brief Compute the basal frictional heating.
141/*!
142 Ice shelves have zero basal friction heating.
143
144 \param[in] V *basal* sliding velocity
145 \param[in] tauc basal yield stress
146 \param[in] mask (used to determine if floating or grounded)
147 \param[out] result
148 */
150 const array::Scalar &tauc,
151 const array::CellType &mask,
152 array::Scalar &result) const {
153
154 array::AccessScope list{&V, &result, &tauc, &mask};
155
156 for (auto p = m_grid->points(); p; p.next()) {
157 const int i = p.i(), j = p.j();
158
159 if (mask.ocean(i,j)) {
160 result(i,j) = 0.0;
161 } else {
162 const double
163 C = m_basal_sliding_law->drag(tauc(i,j), V(i,j).u, V(i,j).v),
164 basal_stress_x = - C * V(i,j).u,
165 basal_stress_y = - C * V(i,j).v;
166 result(i,j) = - basal_stress_x * V(i,j).u - basal_stress_y * V(i,j).v;
167 }
168 }
169}
170
171
174
175 // set metadata:
176 m_vars = { { m_sys, "taud_x" }, { m_sys, "taud_y" } };
177 m_vars[0].long_name("X-component of the driving shear stress at the base of ice");
178 m_vars[1].long_name("Y-component of the driving shear stress at the base of ice");
179
180 for (auto &v : m_vars) {
181 v.units("Pa");
182 v["comment"] = "this field is purely diagnostic (not used by the model)";
183 }
184}
185
186/*!
187 * The driving stress computed here is not used by the model, so this
188 * implementation intentionally does not use the eta-transformation or special
189 * cases at ice margins.
190 */
191std::shared_ptr<array::Array> SSB_taud::compute_impl() const {
192
193 auto result = allocate<array::Vector>("taud");
194
195 const array::Scalar *thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
196 const array::Scalar *surface = m_grid->variables().get_2d_scalar("surface_altitude");
197
198 double standard_gravity = m_config->get_number("constants.standard_gravity"),
199 ice_density = m_config->get_number("constants.ice.density");
200
201 array::AccessScope list{ surface, thickness, result.get() };
202
203 for (auto p = m_grid->points(); p; p.next()) {
204 const int i = p.i(), j = p.j();
205
206 double pressure = ice_density * standard_gravity * (*thickness)(i, j);
207 if (pressure <= 0.0) {
208 (*result)(i, j).u = 0.0;
209 (*result)(i, j).v = 0.0;
210 } else {
211 (*result)(i, j).u = -pressure * diff_x_p(*surface, i, j);
212 (*result)(i, j).v = -pressure * diff_y_p(*surface, i, j);
213 }
214 }
215
216 return result;
217}
218
220 m_vars = { { m_sys, "taud_mag" } };
221 m_vars[0]
222 .long_name("magnitude of the gravitational driving stress at the base of ice")
223 .units("Pa");
224 m_vars[0]["comment"] = "this field is purely diagnostic (not used by the model)";
225}
226
227std::shared_ptr<array::Array> SSB_taud_mag::compute_impl() const {
228 auto result = allocate<array::Scalar>("taud_mag");
229 auto taud = array::cast<array::Vector>(SSB_taud(model).compute());
230
231 compute_magnitude(*taud, *result);
232
233 return result;
234}
235
237 m_vars = { { m_sys, "taub_x" }, { m_sys, "taub_y" } };
238
239 m_vars[0].long_name("X-component of the shear stress at the base of ice");
240 m_vars[1].long_name("Y-component of the shear stress at the base of ice");
241
242 for (auto &v : m_vars) {
243 v.units("Pa");
244 v["comment"] = "this field is purely diagnostic (not used by the model)";
245 }
246}
247
248
249std::shared_ptr<array::Array> SSB_taub::compute_impl() const {
250
251 auto result = allocate<array::Vector>("taub");
252
253 const auto &velocity = model->velocity();
254 const auto *tauc = m_grid->variables().get_2d_scalar("tauc");
255 const auto &mask = *m_grid->variables().get_2d_cell_type("mask");
256
257 const IceBasalResistancePlasticLaw *basal_sliding_law = model->sliding_law();
258
259 array::AccessScope list{ tauc, &velocity, &mask, result.get() };
260 for (auto p = m_grid->points(); p; p.next()) {
261 const int i = p.i(), j = p.j();
262
263 if (mask.grounded_ice(i, j)) {
264 double beta = basal_sliding_law->drag((*tauc)(i, j), velocity(i, j).u, velocity(i, j).v);
265 (*result)(i, j) = -beta * velocity(i, j);
266 } else {
267 (*result)(i, j) = 0.0;
268 }
269 }
270
271 return result;
272}
273
275
276 auto ismip6 = m_config->get_flag("output.ISMIP6");
277
278 m_vars = { { m_sys, ismip6 ? "strbasemag" : "taub_mag" } };
279 m_vars[0]
280 .long_name("magnitude of the basal shear stress at the base of ice")
281 .standard_name("land_ice_basal_drag") // ISMIP6 "standard" name
282 .units("Pa");
283 m_vars[0]["comment"] = "this field is purely diagnostic (not used by the model)";
284}
285
286std::shared_ptr<array::Array> SSB_taub_mag::compute_impl() const {
287 auto result = allocate<array::Scalar>("taub_mag");
288
289 std::shared_ptr<array::Vector> taub = array::cast<array::Vector>(SSB_taub(model).compute());
290
291 compute_magnitude(*taub, *result);
292
293 return result;
294}
295
296/**
297 * Shallow stress balance class that reads `u` and `v` fields from a
298 * file and holds them constant.
299 *
300 * The only use I can think of right now is testing.
301 */
302PrescribedSliding::PrescribedSliding(std::shared_ptr<const Grid> g) : ZeroSliding(g) {
303 // empty
304}
305
306void PrescribedSliding::update(const Inputs &inputs, bool full_update) {
307 (void)inputs;
308 if (full_update) {
310 }
311}
312
315
316 auto input_filename = m_config->get_string("stress_balance.prescribed_sliding.file");
317
318 if (input_filename.empty()) {
319 throw RuntimeError(PISM_ERROR_LOCATION, "stress_balance.prescribed_sliding.file is required.");
320 }
321
322 m_velocity.regrid(input_filename, io::Default::Nil());
323}
324
326 m_vars = { { m_sys, "beta" } };
327 m_vars[0].long_name("basal drag coefficient").units("Pa s / m");
328}
329
330std::shared_ptr<array::Array> SSB_beta::compute_impl() const {
331 auto result = allocate<array::Scalar>("beta");
332
333 const array::Scalar *tauc = m_grid->variables().get_2d_scalar("tauc");
334
335 const IceBasalResistancePlasticLaw *basal_sliding_law = model->sliding_law();
336
337 const array::Vector &velocity = model->velocity();
338
339 array::AccessScope list{tauc, &velocity, result.get()};
340 for (auto p = m_grid->points(); p; p.next()) {
341 const int i = p.i(), j = p.j();
342
343 (*result)(i,j) = basal_sliding_law->drag((*tauc)(i,j), velocity(i,j).u, velocity(i,j).v);
344 }
345
346 return result;
347}
348
349} // end of namespace stressbalance
350} // end of namespace pism
const Config::ConstPtr m_config
configuration database used by this component
Definition Component.hh:158
const std::shared_ptr< const Grid > m_grid
grid used by this component
Definition Component.hh:156
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".
const units::System::Ptr m_sys
the unit system
std::vector< SpatialVariableMetadata > m_vars
metadata corresponding to NetCDF variables
std::shared_ptr< Diagnostic > Ptr
Definition Diagnostic.hh:65
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.
const Config::ConstPtr m_config
Configuration flags and parameters.
std::shared_ptr< EnthalpyConverter > Ptr
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:64
void set(double c)
Result: v[j] <- c for all j.
Definition Array.cc:629
void regrid(const std::string &filename, io::Default default_value)
Definition Array.cc:736
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
Definition Array.cc:476
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:93
std::shared_ptr< FlowLaw > create()
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
virtual DiagnosticList diagnostics_impl() const
ShallowStressBalance(std::shared_ptr< const Grid > g)
std::shared_ptr< rheology::FlowLaw > m_flow_law
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).
EnthalpyConverter::Ptr 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