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
Distributed.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2019, 2021, 2022, 2023 PISM Authors
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 <algorithm> // std::min, std::max
20
21#include "pism/geometry/Geometry.hh"
22#include "pism/hydrology/Distributed.hh"
23#include "pism/util/array/CellType.hh"
24#include "pism/util/error_handling.hh"
25#include "pism/util/io/File.hh"
26#include "pism/util/pism_utilities.hh"
27
28namespace pism {
29namespace hydrology {
30
31Distributed::Distributed(std::shared_ptr<const Grid> g)
32 : Routing(g), m_P(m_grid, "bwp"), m_Pnew(m_grid, "Pnew_internal") {
33
34 // additional variables beyond hydrology::Routing
35 m_P.metadata(0)
36 .long_name("pressure of transportable water in subglacial layer")
37 .units("Pa");
38 m_P.metadata()["valid_min"] = { 0.0 };
39
41 .long_name("new transportable subglacial water pressure during update")
42 .units("Pa");
43 m_Pnew.metadata()["valid_min"] = { 0.0 };
44}
45
47 m_log->message(2,
48 "* Initializing the distributed, linked-cavities subglacial hydrology model...\n");
49}
50
51void Distributed::restart_impl(const File &input_file, int record) {
52 Routing::restart_impl(input_file, record);
53
54 m_P.read(input_file, record);
55
56 regrid("Hydrology", m_P);
57}
58
59void Distributed::bootstrap_impl(const File &input_file, const array::Scalar &ice_thickness) {
60 Routing::bootstrap_impl(input_file, ice_thickness);
61
62 double bwp_default = m_config->get_number("bootstrapping.defaults.bwp");
63 m_P.regrid(input_file, io::Default(bwp_default));
64
65 regrid("Hydrology", m_P);
66
67 bool init_P_from_steady = m_config->get_flag("hydrology.distributed.init_p_from_steady");
68
69 if (init_P_from_steady) { // if so, just overwrite -i or -bootstrap value of P=bwp
70 m_log->message(2, " initializing P from P(W) formula which applies in steady state\n");
71
73
74 array::Scalar sliding_speed(m_grid, "velbase_mag");
75 sliding_speed.metadata(0).long_name("basal sliding speed").units("m s^-1");
76
77 std::string filename = m_config->get_string("hydrology.distributed.sliding_speed_file");
78
79 if (filename.empty()) {
81 "hydrology.distributed.sliding_speed_file is not set");
82 }
83
84 sliding_speed.regrid(filename, io::Default::Nil());
85
86 P_from_W_steady(m_W, m_Pover, sliding_speed,
87 m_P);
88 }
89}
90
92 const array::Scalar &W,
93 const array::Scalar &P) {
94 Routing::init_impl(W_till, W, P);
95
96 m_P.copy_from(P);
97}
98
99void Distributed::define_model_state_impl(const File &output) const {
101 m_P.define(output, io::PISM_DOUBLE);
102}
103
104void Distributed::write_model_state_impl(const File &output) const {
106 m_P.write(output);
107}
108
109std::map<std::string, TSDiagnostic::Ptr> Distributed::ts_diagnostics_impl() const {
110 std::map<std::string, TSDiagnostic::Ptr> result = {
111 // FIXME: add mass-conservation time-series diagnostics
112 };
113 return result;
114}
115
116//! Copies the P state variable which is the modeled water pressure.
120
121//! Check bounds on P and fail with message if not satisfied. Optionally, enforces the
122//! upper bound instead of checking it.
123/*!
124 The bounds are \f$0 \le P \le P_o\f$ where \f$P_o\f$ is the overburden pressure.
125*/
127 const array::Scalar &P_o,
128 bool enforce_upper) {
129
130 array::AccessScope list{&P, &P_o};
131
132 ParallelSection loop(m_grid->com);
133 try {
134 for (auto p = m_grid->points(); p; p.next()) {
135 const int i = p.i(), j = p.j();
136
137 if (P(i,j) < 0.0) {
139 "negative subglacial water pressure\n"
140 "P(%d, %d) = %.6f Pa",
141 i, j, P(i, j));
142 }
143
144 if (enforce_upper) {
145 P(i,j) = std::min(P(i,j), P_o(i,j));
146 } else if (P(i,j) > P_o(i,j) + 0.001) {
148 "subglacial water pressure P = %.16f Pa exceeds\n"
149 "overburden pressure Po = %.16f Pa at (i,j)=(%d,%d)",
150 P(i, j), P_o(i, j), i, j);
151 }
152 }
153 } catch (...) {
154 loop.failed();
155 }
156 loop.check();
157
158}
159
160
161//! Compute functional relationship P(W) which applies only in steady state.
162/*!
163 In steady state in this model, water pressure is determined by a balance of
164 cavitation (opening) caused by sliding and creep closure.
165
166 This will be used in initialization when P is otherwise unknown, and
167 in verification and/or reporting. It is not used during time-dependent
168 model runs. To be more complete, \f$P = P(W,P_o,|v_b|)\f$.
169*/
171 const array::Scalar &P_overburden,
172 const array::Scalar &sliding_speed,
173 array::Scalar &result) {
174
175 const double
176 ice_softness = m_config->get_number("flow_law.isothermal_Glen.ice_softness"),
177 creep_closure_coefficient = m_config->get_number("hydrology.creep_closure_coefficient"),
178 cavitation_opening_coefficient = m_config->get_number("hydrology.cavitation_opening_coefficient"),
179 Glen_exponent = m_config->get_number("stress_balance.sia.Glen_exponent"),
180 Wr = m_config->get_number("hydrology.roughness_scale");
181
182 const double CC = cavitation_opening_coefficient / (creep_closure_coefficient * ice_softness);
183
184 array::AccessScope list{&W, &P_overburden, &sliding_speed, &result};
185
186 for (auto p = m_grid->points(); p; p.next()) {
187 const int i = p.i(), j = p.j();
188
189 double sb = pow(CC * sliding_speed(i, j), 1.0 / Glen_exponent);
190 if (W(i, j) == 0.0) {
191 // see P(W) formula in steady state; note P(W) is continuous (in steady
192 // state); these facts imply:
193 if (sb > 0.0) {
194 // no water + cavitation = underpressure
195 result(i, j) = 0.0;
196 } else {
197 // no water + no cavitation = creep repressurizes = overburden
198 result(i, j) = P_overburden(i, j);
199 }
200 } else {
201 double Wratio = std::max(0.0, Wr - W(i, j)) / W(i, j);
202 // in cases where steady state is actually possible this will come out positive, but
203 // otherwise we should get underpressure P=0, and that is what it yields
204 result(i, j) = std::max(0.0, P_overburden(i, j) - sb * pow(Wratio, 1.0 / Glen_exponent));
205 }
206 } // end of the loop over grid points
207}
208
209double Distributed::max_timestep_P_diff(double phi0, double dt_diff_w) const {
210 return 2.0 * phi0 * dt_diff_w;
211}
212
214 const array::CellType &cell_type,
215 const array::Scalar &sliding_speed,
216 const array::Scalar &surface_input_rate,
217 const array::Scalar &basal_melt_rate,
218 const array::Scalar &P_overburden,
219 const array::Scalar &Wtill,
220 const array::Scalar &Wtill_new,
221 const array::Scalar &P,
222 const array::Scalar1 &W,
223 const array::Staggered1 &Ws,
224 const array::Staggered1 &K,
225 const array::Staggered1 &Q,
226 array::Scalar &P_new) const {
227
228 const double
229 n = m_config->get_number("stress_balance.sia.Glen_exponent"),
230 A = m_config->get_number("flow_law.isothermal_Glen.ice_softness"),
231 c1 = m_config->get_number("hydrology.cavitation_opening_coefficient"),
232 c2 = m_config->get_number("hydrology.creep_closure_coefficient"),
233 Wr = m_config->get_number("hydrology.roughness_scale"),
234 phi0 = m_config->get_number("hydrology.regularizing_porosity");
235
236 // update Pnew from time step
237 const double
238 CC = (m_rg * dt) / phi0,
239 wux = 1.0 / (m_dx * m_dx),
240 wuy = 1.0 / (m_dy * m_dy);
241
242 array::AccessScope list{&P, &W, &Wtill, &Wtill_new, &sliding_speed, &Ws,
243 &K, &Q, &surface_input_rate, &basal_melt_rate,
244 &cell_type, &P_overburden, &P_new};
245
246 for (auto p = m_grid->points(); p; p.next()) {
247 const int i = p.i(), j = p.j();
248
249 auto w = W.star(i, j);
250 double P_o = P_overburden(i, j);
251
252 if (cell_type.ice_free_land(i, j)) {
253 P_new(i, j) = 0.0;
254 } else if (cell_type.ocean(i, j)) {
255 P_new(i, j) = P_o;
256 } else if (w.c <= 0.0) {
257 P_new(i, j) = P_o;
258 } else {
259 auto q = Q.star(i, j);
260 auto k = K.star(i, j);
261 auto ws = Ws.star(i, j);
262
263 double
264 Open = c1 * sliding_speed(i, j) * std::max(0.0, Wr - w.c),
265 Close = c2 * A * pow(P_o - P(i, j), n) * w.c;
266
267 // compute the flux divergence the same way as in update_W()
268 const double divadflux = (q.e - q.w) / m_dx + (q.n - q.s) / m_dy;
269 const double
270 De = m_rg * k.e * ws.e,
271 Dw = m_rg * k.w * ws.w,
272 Dn = m_rg * k.n * ws.n,
273 Ds = m_rg * k.s * ws.s;
274
275 double diffW = (wux * (De * (w.e - w.c) - Dw * (w.c - w.w)) +
276 wuy * (Dn * (w.n - w.c) - Ds * (w.c - w.s)));
277
278 double divflux = -divadflux + diffW;
279
280 // pressure update equation
281 double Wtill_change = Wtill_new(i, j) - Wtill(i, j);
282 double total_input = surface_input_rate(i, j) + basal_melt_rate(i, j);
283 double ZZ = Close - Open + total_input - Wtill_change / dt;
284
285 P_new(i, j) = P(i, j) + CC * (divflux + ZZ);
286
287 // projection to enforce 0 <= P <= P_o
288 P_new(i, j) = clip(P_new(i, j), 0.0, P_o);
289 }
290 } // end of the loop over grid points
291}
292
293
294//! Update the model state variables W,P by running the subglacial hydrology model.
295/*!
296 Runs the hydrology model from time t to time t + dt. Here [t,dt]
297 is generally on the order of months to years. This hydrology model will take its
298 own shorter time steps, perhaps hours to weeks.
299*/
300void Distributed::update_impl(double t, double dt, const Inputs& inputs) {
301
303
304 double
305 ht = t,
306 hdt = 0.0;
307
308 const double
309 t_final = t + dt,
310 dt_max = m_config->get_number("hydrology.maximum_time_step", "seconds"),
311 phi0 = m_config->get_number("hydrology.regularizing_porosity"),
312 tillwat_max = m_config->get_number("hydrology.tillwat_max");
313
314 m_Qstag_average.set(0.0);
315
316 // make sure W,P have valid ghosts before starting hydrology steps
319
320 unsigned int step_counter = 0;
321 for (; ht < t_final; ht += hdt) {
322 step_counter++;
323
324#if (Pism_DEBUG==1)
325 double huge_number = 1e6;
326 check_bounds(m_W, huge_number);
327 check_bounds(m_Wtill, tillwat_max);
328#endif
329
330 // note that ice dynamics can change overburden pressure, so we can only check P
331 // bounds if thk has not changed; if thk could have just changed, such as in the first
332 // time through the current loop, we enforce them
333 bool enforce_upper = (step_counter == 1);
334 check_P_bounds(m_P, m_Pover, enforce_upper);
335
337 inputs.geometry->cell_type,
338 m_Wstag);
339
340 double maxKW = 0.0;
344 m_Kstag, maxKW);
345
349 m_Kstag,
350 inputs.no_model_mask,
351 m_Vstag);
352
353 // to get Q, W needs valid ghosts
355
357
358 {
359 const double
360 dt_cfl = max_timestep_W_cfl(),
361 dt_diff_w = max_timestep_W_diff(maxKW),
362 dt_diff_p = max_timestep_P_diff(phi0, dt_diff_w);
363
364 hdt = std::min(t_final - ht, dt_max);
365 hdt = std::min(hdt, dt_cfl);
366 hdt = std::min(hdt, dt_diff_w);
367 hdt = std::min(hdt, dt_diff_p);
368 }
369
370 m_log->message(3, " hydrology step %05d, dt = %f s\n", step_counter, hdt);
371
372 // update Wtillnew from Wtill and input_rate
373 update_Wtill(hdt,
374 m_Wtill,
377 m_Wtillnew);
378 // remove water in ice-free areas and account for changes
380 inputs.no_model_mask,
381 0.0, // do not limit maximum thickness
382 tillwat_max, // till water thickness under the ocean
388
389 update_P(hdt,
390 inputs.geometry->cell_type,
391 *inputs.ice_sliding_speed,
394 m_Pover,
397 m_W, m_Wstag,
399 m_Pnew);
400
401 // update Wnew from W, Wtill, Wtillnew, Wstag, Q, input_rate
402 update_W(hdt,
405 m_W, m_Wstag,
408 m_Wnew);
409 // remove water in ice-free areas and account for changes
411 inputs.no_model_mask,
412 0.0, // do not limit maximum thickness
413 0.0, // transportable water layer thickness under the ocean
414 m_Wnew,
419
420 // transfer new into old
424 } // end of the time-stepping loop
425
426 staggered_to_regular(inputs.geometry->cell_type, m_Qstag_average,
427 m_config->get_flag("hydrology.routing.include_floating_ice"),
428 m_Q);
429 m_Q.scale(1.0 / dt);
430
431 m_log->message(2,
432 " took %d hydrology sub-steps with average dt = %.6f years (%.6f s)\n",
433 step_counter,
434 units::convert(m_sys, dt/step_counter, "seconds", "years"),
435 dt/step_counter);
436}
437
438} // end of namespace hydrology
439} // end of namespace pism
const units::System::Ptr m_sys
unit system used by this component
Definition Component.hh:160
const Config::ConstPtr m_config
configuration database used by this component
Definition Component.hh:158
const Logger::ConstPtr m_log
logger (for easy access)
Definition Component.hh:162
const std::shared_ptr< const Grid > m_grid
grid used by this component
Definition Component.hh:156
void regrid(const std::string &module_name, array::Array &variable, RegriddingFlag flag=NO_REGRID_WITHOUT_REGRID_VARS)
Definition Component.cc:159
High-level PISM I/O class.
Definition File.hh:55
array::CellType2 cell_type
Definition Geometry.hh:55
void failed()
Indicates a failure of a parallel section.
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
VariableMetadata & long_name(const std::string &input)
VariableMetadata & units(const std::string &input)
std::string get_string(const std::string &name) const
Get a string attribute.
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition Array.hh:64
void copy_from(const Array2D< T > &source)
Definition Array2D.hh:73
stencils::Star< T > star(int i, int j) const
Definition Array2D.hh:79
void read(const std::string &filename, unsigned int time)
Definition Array.cc:731
void define(const File &file, io::Type default_type) const
Define variables corresponding to an Array in a file opened using file.
Definition Array.cc:463
void write(const std::string &filename) const
Definition Array.cc:722
void scale(double alpha)
Result: v <- v * alpha. Calls VecScale.
Definition Array.cc:224
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
void add(double alpha, const Array &x)
Result: v <- v + alpha * x. Calls VecAXPY.
Definition Array.cc:206
void update_ghosts()
Updates ghost points.
Definition Array.cc:615
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
bool ice_free_land(int i, int j) const
Definition CellType.hh:62
"Cell type" mask. Adds convenience methods to array::Scalar.
Definition CellType.hh:30
stencils::Star< double > star(int i, int j) const
Returns the values at interfaces of the cell i,j using the staggered grid.
Definition Staggered.hh:75
void write_model_state_impl(const File &output) const
The default (empty implementation).
virtual void bootstrap_impl(const File &input_file, const array::Scalar &ice_thickness)
void define_model_state_impl(const File &output) const
The default (empty implementation).
void update_P(double dt, const array::CellType &cell_type, const array::Scalar &sliding_speed, const array::Scalar &surface_input_rate, const array::Scalar &basal_melt_rate, const array::Scalar &P_overburden, const array::Scalar &Wtill, const array::Scalar &Wtill_new, const array::Scalar &P, const array::Scalar1 &W, const array::Staggered1 &Ws, const array::Staggered1 &K, const array::Staggered1 &Q, array::Scalar &P_new) const
virtual void init_impl(const array::Scalar &W_till, const array::Scalar &W, const array::Scalar &P)
std::map< std::string, TSDiagnostic::Ptr > ts_diagnostics_impl() const
void P_from_W_steady(const array::Scalar &W, const array::Scalar &P_overburden, const array::Scalar &sliding_speed, array::Scalar &result)
Compute functional relationship P(W) which applies only in steady state.
const array::Scalar & subglacial_water_pressure() const
Copies the P state variable which is the modeled water pressure.
void initialization_message() const
Distributed(std::shared_ptr< const Grid > g)
void update_impl(double t, double dt, const Inputs &inputs)
Update the model state variables W,P by running the subglacial hydrology model.
virtual double max_timestep_P_diff(double phi0, double dt_diff_w) const
void check_P_bounds(array::Scalar &P, const array::Scalar &P_o, bool enforce_upper)
virtual void restart_impl(const File &input_file, int record)
array::Scalar m_surface_input_rate
Definition Hydrology.hh:179
array::Scalar m_grounding_line_change
Definition Hydrology.hh:192
const array::Scalar & surface_input_rate() const
Definition Hydrology.cc:518
void enforce_bounds(const array::CellType &cell_type, const array::Scalar *no_model_mask, double max_thickness, double ocean_water_thickness, array::Scalar &water_thickness, array::Scalar &grounded_margin_change, array::Scalar &grounding_line_change, array::Scalar &conservation_error_change, array::Scalar &no_model_mask_change)
Correct the new water thickness based on boundary requirements.
Definition Hydrology.cc:669
array::Scalar m_basal_melt_rate
Definition Hydrology.hh:182
array::Scalar1 m_W
effective thickness of transportable basal water
Definition Hydrology.hh:173
void compute_overburden_pressure(const array::Scalar &ice_thickness, array::Scalar &result) const
Update the overburden pressure from ice thickness.
Definition Hydrology.cc:480
array::Scalar m_Wtill
effective thickness of basal water stored in till
Definition Hydrology.hh:170
array::Scalar m_Pover
overburden pressure
Definition Hydrology.hh:176
array::Scalar m_grounded_margin_change
Definition Hydrology.hh:191
array::Scalar m_no_model_mask_change
Definition Hydrology.hh:194
array::Scalar m_conservation_error_change
Definition Hydrology.hh:190
const Geometry * geometry
Definition Hydrology.hh:37
const array::Scalar * ice_sliding_speed
Definition Hydrology.hh:41
const array::Scalar1 * no_model_mask
Definition Hydrology.hh:35
virtual void init_impl(const array::Scalar &W_till, const array::Scalar &W, const array::Scalar &P)
Definition Routing.cc:345
array::Staggered1 m_Qstag_average
Definition Routing.hh:115
array::Staggered m_Vstag
Definition Routing.hh:118
array::Staggered1 m_Wstag
Definition Routing.hh:121
double max_timestep_W_diff(double KW_max) const
Definition Routing.cc:690
virtual void bootstrap_impl(const File &input_file, const array::Scalar &ice_thickness)
Definition Routing.cc:335
double max_timestep_W_cfl() const
Definition Routing.cc:699
void compute_conductivity(const array::Staggered &W, const array::Scalar &P, const array::Scalar &bed, array::Staggered &result, double &maxKW) const
Compute the nonlinear conductivity at the center of cell edges.
Definition Routing.cc:436
array::Staggered1 m_Kstag
Definition Routing.hh:124
void advective_fluxes(const array::Staggered &V, const array::Scalar &W, array::Staggered &result) const
Compute Q = V W at edge-centers (staggered grid) by first-order upwinding.
Definition Routing.cc:670
void update_W(double dt, const array::Scalar &surface_input_rate, const array::Scalar &basal_melt_rate, const array::Scalar1 &W, const array::Staggered1 &Wstag, const array::Scalar &Wtill, const array::Scalar &Wtill_new, const array::Staggered1 &K, const array::Staggered1 &Q, array::Scalar &W_new)
The computation of Wnew, called by update().
Definition Routing.cc:796
void water_thickness_staggered(const array::Scalar &W, const array::CellType1 &mask, array::Staggered &result)
Average the regular grid water thickness to values at the center of cell edges.
Definition Routing.cc:377
void compute_velocity(const array::Staggered &W, const array::Scalar &P, const array::Scalar &bed, const array::Staggered &K, const array::Scalar1 *no_model_mask, array::Staggered &result) const
Get the advection velocity V at the center of cell edges.
Definition Routing.cc:611
array::Staggered1 m_Qstag
Definition Routing.hh:113
virtual void define_model_state_impl(const File &output) const
The default (empty implementation).
Definition Routing.cc:353
void update_Wtill(double dt, const array::Scalar &Wtill, const array::Scalar &surface_input_rate, const array::Scalar &basal_melt_rate, array::Scalar &Wtill_new)
The computation of Wtillnew, called by update().
Definition Routing.cc:730
array::Scalar m_Wtillnew
Definition Routing.hh:127
virtual void write_model_state_impl(const File &output) const
The default (empty implementation).
Definition Routing.cc:358
array::Scalar m_Wnew
Definition Routing.hh:127
virtual void restart_impl(const File &input_file, int record)
Definition Routing.cc:327
array::Scalar1 m_bottom_surface
Definition Routing.hh:135
A subglacial hydrology model which assumes water pressure equals overburden pressure.
Definition Routing.hh:81
static Default Nil()
Definition IO_Flags.hh:93
#define PISM_ERROR_LOCATION
#define n
Definition exactTestM.c:37
static double K(double psi_x, double psi_y, double speed, double epsilon)
void check_bounds(const array::Scalar &W, double W_max)
Definition Hydrology.cc:553
@ PISM_DOUBLE
Definition IO_Flags.hh:52
double convert(System::Ptr system, double input, const std::string &spec1, const std::string &spec2)
Convert a quantity from unit1 to unit2.
Definition Units.cc:70
static const double g
Definition exactTestP.cc:36
T clip(T x, T a, T b)
static const double c2
Definition exactTestP.cc:45
static const double k
Definition exactTestP.cc:42
static const double Wr
Definition exactTestP.cc:43
void ice_bottom_surface(const Geometry &geometry, array::Scalar &result)
Definition Geometry.cc:218
static const double c1
Definition exactTestP.cc:44