PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
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 
28 namespace pism {
29 namespace stressbalance {
30 
31 ShallowStressBalance::ShallowStressBalance(std::shared_ptr<const Grid> g)
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 
63  delete m_basal_sliding_law;
64 }
65 
67  this->init_impl();
68 }
69 
71  // empty
72 }
73 
75  return "";
76 }
77 
78 std::shared_ptr<const rheology::FlowLaw> ShallowStressBalance::flow_law() const {
79  return m_flow_law;
80 }
81 
83  return m_e_factor;
84 }
85 
87  return m_EC;
88 }
89 
91  return m_basal_sliding_law;
92 }
93 
94 //! \brief Get the thickness-advective 2D velocity.
96  return m_velocity;
97 }
98 
99 //! \brief Get the basal frictional heating (for the adaptive energy time-stepping).
102 }
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 
122 ZeroSliding::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.
131 void 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 
173  : Diag<ShallowStressBalance>(m) {
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  */
191 std::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 
227 std::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 
249 std::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 
286 std::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  */
302 PrescribedSliding::PrescribedSliding(std::shared_ptr<const Grid> g) : ZeroSliding(g) {
303  // empty
304 }
305 
306 void 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 
330 std::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
Definition: Diagnostic.hh:172
A template derived from Diagnostic, adding a "Model".
Definition: Diagnostic.hh:166
const units::System::Ptr m_sys
the unit system
Definition: Diagnostic.hh:116
std::vector< SpatialVariableMetadata > m_vars
metadata corresponding to NetCDF variables
Definition: Diagnostic.hh:120
std::shared_ptr< Diagnostic > Ptr
Definition: Diagnostic.hh:65
std::shared_ptr< const Grid > m_grid
the grid
Definition: Diagnostic.hh:114
std::shared_ptr< array::Array > compute() const
Compute a diagnostic quantity and return a pointer to a newly-allocated Array.
Definition: Diagnostic.cc:131
const Config::ConstPtr m_config
Configuration flags and parameters.
Definition: Diagnostic.hh:118
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 & output_units(const std::string &input)
VariableMetadata & units(const std::string &input)
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition: Array.hh:65
void set(double c)
Result: v[j] <- c for all j.
Definition: Array.cc:707
void regrid(const std::string &filename, io::Default default_value)
Definition: Array.cc:814
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
Definition: Array.cc:553
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:97
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
double diff_x_p(const array::Scalar &array, int i, int j)
Returns the x-derivative at i,j approximated using centered finite differences. Respects grid periodi...
Definition: Scalar.cc:108
void compute_magnitude(const array::Vector &input, array::Scalar &result)
Definition: Scalar.cc:66
double diff_y_p(const array::Scalar &array, int i, int j)
Returns the y-derivative at i,j approximated using centered finite differences. Respects grid periodi...
Definition: Scalar.cc:129
static const double g
Definition: exactTestP.cc:36
std::map< std::string, Diagnostic::Ptr > DiagnosticList
Definition: Diagnostic.hh:125
const int C[]
Definition: ssafd_code.cc:44