23#include "pism/hydrology/Routing.hh"
24#include "pism/util/array/CellType.hh"
26#include "pism/util/error_handling.hh"
28#include "pism/util/pism_utilities.hh"
29#include "pism/util/Vars.hh"
30#include "pism/geometry/Geometry.hh"
31#include "pism/util/Profiling.hh"
32#include "pism/util/Context.hh"
33#include "pism/util/Logger.hh"
34#include "pism/util/io/IO_Flags.hh"
39namespace diagnostics {
48 m_vars[0].long_name(
"pressure of transportable water in subglacial layer").units(
"Pa");
53 auto result = allocate<array::Scalar>(
"bwp");
55 result->copy_from(
model->subglacial_water_pressure());
72 "pressure of transportable water in subglacial layer as fraction of the overburden pressure")
81 auto result = allocate<array::Scalar>(
"bwprel");
84 &P =
model->subglacial_water_pressure(),
85 &Po =
model->overburden_pressure();
88 for (
auto p :
m_grid->points()) {
89 const int i = p.i(), j = p.j();
92 (*result)(i,j) = P(i, j) / Po(i,j);
94 (*result)(i,j) = fill_value;
112 .long_name(
"effective pressure of transportable water in subglacial layer"
113 " (overburden pressure minus water pressure)")
120 auto result = allocate<array::Scalar>(
"effbwp");
123 &P =
model->subglacial_water_pressure(),
124 &Po =
model->overburden_pressure();
128 for (
auto p :
m_grid->points()) {
129 const int i = p.i(), j = p.j();
131 (*result)(i, j) = Po(i, j) - P(i, j);
148 .long_name(
"wall melt into subglacial hydrology layer from (turbulent)"
149 " dissipation of energy in transportable water")
151 .output_units(
"m year^-1");
156 auto result = allocate<array::Scalar>(
"wallmelt");
158 const array::Scalar &bed_elevation = *
m_grid->variables().get_2d_scalar(
"bedrock_altitude");
173 m_vars[0].long_name(
"velocity of water in subglacial layer, i-offset").units(
"m s^-1");
174 m_vars[1].long_name(
"velocity of water in subglacial layer, j-offset").units(
"m s^-1");
178 auto result = allocate<array::Staggered>(
"bwatvel");
180 result->copy_from(
model->velocity_staggered());
197 auto grid = result.
grid();
199 auto config = grid->ctx()->config();
202 ice_density = config->get_number(
"constants.ice.density"),
203 sea_water_density = config->get_number(
"constants.sea_water.density"),
204 C = ice_density / sea_water_density,
205 rg = (config->get_number(
"constants.fresh_water.density") *
206 config->get_number(
"constants.standard_gravity"));
210 for (
auto p : grid->points()) {
211 const int i = p.i(), j = p.j();
213 double b = std::max(bed(i, j), sea_level(i, j) - C * ice_thickness(i, j));
215 result(i, j) = P(i, j) + rg * (b + W(i, j));
225 m_vars[0].long_name(
"hydraulic potential in the subglacial hydrology system").units(
"Pa");
231 auto result = allocate<array::Scalar>(
"hydraulic_potential");
233 const auto &sea_level = *
m_grid->variables().get_2d_scalar(
"sea_level");
234 const auto &bed_elevation = *
m_grid->variables().get_2d_scalar(
"bedrock_altitude");
235 const auto &ice_thickness = *
m_grid->variables().get_2d_scalar(
"land_ice_thickness");
238 model->subglacial_water_pressure(),
252 m_Qstag(grid,
"advection_flux"),
253 m_Qstag_average(grid,
"cumulative_advection_flux"),
254 m_Vstag(grid,
"water_velocity"),
255 m_Wstag(grid,
"W_staggered"),
256 m_Kstag(grid,
"K_staggered"),
257 m_Wnew(grid,
"W_new"),
258 m_Wtillnew(grid,
"Wtill_new"),
259 m_R(grid,
"potential_workspace"),
262 m_bottom_surface(grid,
"ice_bottom_surface_elevation") {
264 m_rg = (
m_config->get_number(
"constants.fresh_water.density") *
265 m_config->get_number(
"constants.standard_gravity"));
268 .
long_name(
"cell face-centered (staggered) components of advective subglacial water flux")
272 .
long_name(
"average (over time) advection flux on the staggered grid")
277 "cell face-centered (staggered) components of water velocity in subglacial water layer")
282 .
long_name(
"cell face-centered (staggered) values of water layer thickness")
287 .
long_name(
"cell face-centered (staggered) values of nonlinear conductivity");
291 .
long_name(
"work space for modeled subglacial water hydraulic potential")
296 .
long_name(
"new thickness of transportable subglacial water layer during update")
301 .
long_name(
"new thickness of till (subglacial) water layer during update")
309 "alpha = %f < 1 which is not allowed", alpha);
312 if (
m_config->get_number(
"hydrology.tillwat_max") < 0.0) {
314 "hydrology::Routing: hydrology.tillwat_max is negative.\n"
315 "This is not allowed.");
322 "* Initializing the routing subglacial hydrology model ...\n");
324 if (
m_config->get_flag(
"hydrology.routing.include_floating_ice")) {
325 m_log->message(2,
" ... routing subglacial water under grounded and floating ice.\n");
327 m_log->message(2,
" ... routing subglacial water under grounded ice only.\n");
343 double bwat_default =
m_config->get_number(
"bootstrapping.defaults.bwat");
384 bool include_floating =
m_config->get_flag(
"hydrology.routing.include_floating_ice");
388 for (
auto p :
m_grid->points()) {
389 const int i = p.i(), j = p.j();
391 if (include_floating) {
393 if (mask.
icy(i, j)) {
394 result(i, j, 0) = mask.
icy(i + 1, j) ? 0.5 * (W(i, j) + W(i + 1, j)) : W(i, j);
396 result(i, j, 0) = mask.
icy(i + 1, j) ? W(i + 1, j) : 0.0;
399 if (mask.
icy(i, j)) {
400 result(i, j, 1) = mask.
icy(i, j + 1) ? 0.5 * (W(i, j) + W(i, j + 1)) : W(i, j);
402 result(i, j, 1) = mask.
icy(i, j + 1) ? W(i, j + 1) : 0.0;
407 result(i, j, 0) = mask.
grounded_ice(i + 1, j) ? 0.5 * (W(i, j) + W(i + 1, j)) : W(i, j);
409 result(i, j, 0) = mask.
grounded_ice(i + 1, j) ? W(i + 1, j) : 0.0;
413 result(i, j, 1) = mask.
grounded_ice(i, j + 1) ? 0.5 * (W(i, j) + W(i, j + 1)) : W(i, j);
415 result(i, j, 1) = mask.
grounded_ice(i, j + 1) ? W(i, j + 1) : 0.0;
443 double &KW_max)
const {
445 k =
m_config->get_number(
"hydrology.hydraulic_conductivity"),
446 alpha =
m_config->get_number(
"hydrology.thickness_power_in_flux"),
447 beta =
m_config->get_number(
"hydrology.gradient_power_in_flux"),
448 betapow = (beta - 2.0) / 2.0;
466 for (
auto p :
m_grid->points()) {
467 const int i = p.i(), j = p.j();
471 dRdy = (
m_R(i + 1, j + 1) +
m_R(i, j + 1) -
m_R(i + 1, j - 1) -
m_R(i, j - 1)) / (4.0 *
m_dy);
472 result(i, j, 0) = dRdx * dRdx + dRdy * dRdy;
474 dRdx = (
m_R(i + 1, j + 1) +
m_R(i + 1, j) -
m_R(i - 1, j + 1) -
m_R(i - 1, j)) / (4.0 *
m_dx);
476 result(i, j, 1) = dRdx * dRdx + dRdy * dRdy;
482 const double eps = beta < 2.0 ? 1.0 : 0.0;
484 for (
auto p :
m_grid->points()) {
485 const int i = p.i(), j = p.j();
487 for (
int o = 0; o < 2; ++o) {
488 const double Pi = result(i, j, o);
492 double B = pow(Pi + eps * eps, betapow);
494 result(i, j, o) =
k * pow(W(i, j, o), alpha - 1.0) * B;
496 KW_max = std::max(KW_max, result(i, j, o) * W(i, j, o));
500 for (
auto p :
m_grid->points()) {
501 const int i = p.i(), j = p.j();
503 for (
int o = 0; o < 2; ++o) {
504 result(i, j, o) =
k * pow(W(i, j, o), alpha - 1.0);
506 KW_max = std::max(KW_max, result(i, j, o) * W(i, j, o));
534 auto grid = result.
grid();
536 auto config = grid->ctx()->config();
539 k = config->get_number(
"hydrology.hydraulic_conductivity"),
540 L = config->get_number(
"constants.fresh_water.latent_heat_of_fusion"),
541 alpha = config->get_number(
"hydrology.thickness_power_in_flux"),
542 beta = config->get_number(
"hydrology.gradient_power_in_flux"),
543 g = config->get_number(
"constants.standard_gravity"),
544 rhow = config->get_number(
"constants.fresh_water.density"),
551 "alpha = %f < 1 which is not allowed", alpha);
565 double dx = grid->dx();
566 double dy = grid->dy();
568 for (
auto p : grid->points()) {
569 const int i = p.i(), j = p.j();
574 if (W(i + 1, j) > 0.0) {
575 dRdx = (R(i + 1, j) - R(i, j)) / (2.0 * dx);
577 if (W(i - 1, j) > 0.0) {
578 dRdx += (R(i, j) - R(i - 1, j)) / (2.0 * dx);
581 if (W(i, j + 1) > 0.0) {
582 dRdy = (R(i, j + 1) - R(i, j)) / (2.0 * dy);
584 if (W(i, j - 1) > 0.0) {
585 dRdy += (R(i, j) - R(i, j - 1)) / (2.0 * dy);
587 result(i, j) = CC * pow(W(i, j), alpha) * pow(dRdx * dRdx + dRdy * dRdy, beta/2.0);
625 for (
auto p :
m_grid->points()) {
626 const int i = p.i(), j = p.j();
628 if (W(i, j, 0) > 0.0) {
630 P_x = (P(i + 1, j) - P(i, j)) /
m_dx,
631 b_x = (bed(i + 1, j) - bed(i, j)) /
m_dx;
632 result(i, j, 0) = -
K(i, j, 0) * (P_x +
m_rg * b_x);
634 result(i, j, 0) = 0.0;
637 if (W(i, j, 1) > 0.0) {
639 P_y = (P(i, j + 1) - P(i, j)) /
m_dy,
640 b_y = (bed(i, j + 1) - bed(i, j)) /
m_dy;
641 result(i, j, 1) = -
K(i, j, 1) * (P_y +
m_rg * b_y);
643 result(i, j, 1) = 0.0;
648 list.
add(*no_model_mask);
650 for (
auto p :
m_grid->points()) {
651 const int i = p.i(), j = p.j();
653 auto M = no_model_mask->
star(i, j);
656 result(i, j, 0) = 0.0;
660 result(i, j, 1) = 0.0;
680 for (
auto p :
m_grid->points()) {
681 const int i = p.i(), j = p.j();
683 result(i, j, 0) = V(i, j, 0) * (V(i, j, 0) >= 0.0 ? W(i, j) : W(i + 1, j));
684 result(i, j, 1) = V(i, j, 1) * (V(i, j, 1) >= 0.0 ? W(i, j) : W(i, j + 1));
695 double D_max =
m_rg * KW_max;
697 return 0.25 / (D_max * result);
699 return std::numeric_limits<double>::infinity();
713 return alpha * 0.5 / (tmp[0]/
m_dx + tmp[1]/
m_dy + eps);
742 tillwat_max =
m_config->get_number(
"hydrology.tillwat_max"),
743 C =
m_config->get_number(
"hydrology.tillwat_decay_rate",
"m / second");
747 bool add_surface_input =
m_config->get_flag(
"hydrology.add_water_input_to_till_storage");
748 if (add_surface_input) {
752 for (
auto p :
m_grid->points()) {
753 const int i = p.i(), j = p.j();
755 double input_rate = basal_melt_rate(i, j);
756 if (add_surface_input) {
760 Wtill_new(i, j) =
clip(Wtill(i, j) + dt * (input_rate - C),
777 for (
auto p :
m_grid->points()) {
778 const int i = p.i(), j = p.j();
780 auto q = Q.
star(i, j);
781 const double divQ = (q.e - q.w) /
m_dx + (q.n - q.s) /
m_dy;
783 auto k =
K.star(i, j);
784 auto ws = Wstag.
star(i, j);
787 De =
m_rg *
k.e * ws.e,
788 Dw =
m_rg *
k.w * ws.w,
789 Dn =
m_rg *
k.n * ws.n,
790 Ds =
m_rg *
k.s * ws.s;
792 auto w = W.
star(i, j);
793 const double diffW = (wux * (De * (w.e - w.c) - Dw * (w.c - w.w)) +
794 wuy * (Dn * (w.n - w.c) - Ds * (w.c - w.s)));
796 result(i, j) = dt * (- divQ + diffW);
818 for (
auto p :
m_grid->points()) {
819 const int i = p.i(), j = p.j();
823 double Wtill_change = Wtill_new(i, j) - Wtill(i, j);
851 dt_max =
m_config->get_number(
"hydrology.maximum_time_step",
"seconds"),
852 tillwat_max =
m_config->get_number(
"hydrology.tillwat_max");
859 unsigned int step_counter = 0;
860 for (; ht < t_final; ht += hdt) {
864 double huge_number = 1e6;
906 hdt = std::min(t_final - ht, dt_max);
907 hdt = std::min(hdt, dt_cfl);
908 hdt = std::min(hdt, dt_diff_w);
911 m_log->message(3,
" hydrology step %05d, dt = %f s\n", step_counter, hdt);
966 m_config->get_flag(
"hydrology.routing.include_floating_ice"),
971 " took %d hydrology sub-steps with average dt = %.6f years (%.3f s or %.3f hours)\n",
975 (dt / step_counter) / 3600.0);
979 using namespace diagnostics;
987 {
"hydraulic_potential",
Diagnostic::Ptr(
new HydraulicPotential(
this))},
993 std::map<std::string, TSDiagnostic::Ptr> result = {
const units::System::Ptr m_sys
unit system used by this component
std::shared_ptr< const Config > m_config
configuration database used by this component
const std::shared_ptr< const Grid > m_grid
grid used by this component
void regrid(const std::string &module_name, array::Array &variable, RegriddingFlag flag=NO_REGRID_WITHOUT_REGRID_VARS)
const Profiling & profiling() const
std::shared_ptr< const Logger > m_log
logger (for easy access)
A template derived from Diagnostic, adding a "Model".
std::vector< VariableMetadata > m_vars
metadata corresponding to NetCDF variables
double m_fill_value
fill value (used often enough to justify storing it)
const units::System::Ptr m_sys
the unit system
std::shared_ptr< Diagnostic > Ptr
std::shared_ptr< const Grid > m_grid
the grid
High-level PISM I/O class.
array::CellType2 cell_type
void begin(const char *name) const
void end(const char *name) const
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
void copy_from(const Array2D< T > &source)
stencils::Star< T > star(int i, int j) const
void add(double alpha, const Array2D< T > &x)
void read(const std::string &filename, unsigned int time)
void write(const OutputFile &file) const
void scale(double alpha)
Result: v <- v * alpha. Calls VecScale.
std::shared_ptr< const Grid > grid() const
void set(double c)
Result: v[j] <- c for all j.
void regrid(const std::string &filename, io::Default default_value)
void add(double alpha, const Array &x)
Result: v <- v + alpha * x. Calls VecAXPY.
void update_ghosts()
Updates ghost points.
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
unsigned int stencil_width() const
Get the stencil width of the current Array. Returns 0 if ghosts are not available.
bool grounded_ice(int i, int j) const
bool icy(int i, int j) const
stencils::Star< double > star(int i, int j) const
Returns the values at interfaces of the cell i,j using the staggered grid.
A class for storing and accessing internal staggered-grid 2D fields. Uses dof=2 storage....
array::Scalar m_flow_change
array::Scalar m_flow_change_incremental
virtual void bootstrap_impl(const File &input_file, const array::Scalar &ice_thickness)
virtual std::map< std::string, Diagnostic::Ptr > spatial_diagnostics_impl() const
array::Scalar m_surface_input_rate
array::Scalar m_grounding_line_change
virtual std::set< VariableMetadata > state_impl() const
const array::Scalar & surface_input_rate() const
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.
const array::Scalar & subglacial_water_thickness() const
Return the effective thickness of the transportable basal water layer.
array::Scalar m_basal_melt_rate
virtual void init_impl(const array::Scalar &W_till, const array::Scalar &W, const array::Scalar &P)
array::Scalar1 m_W
effective thickness of transportable basal water
virtual void restart_impl(const File &input_file, int record)
array::Scalar m_input_change
array::Scalar m_Wtill
effective thickness of basal water stored in till
array::Scalar m_Pover
overburden pressure
array::Scalar m_grounded_margin_change
virtual void write_state_impl(const OutputFile &output) const
The default (empty implementation).
array::Scalar m_no_model_mask_change
array::Scalar m_conservation_error_change
The PISM subglacial hydrology model interface.
virtual void init_impl(const array::Scalar &W_till, const array::Scalar &W, const array::Scalar &P)
array::Staggered1 m_Qstag_average
virtual void write_state_impl(const OutputFile &output) const
The default (empty implementation).
virtual void initialization_message() const
const array::Scalar & subglacial_water_pressure() const
array::Staggered1 m_Wstag
double max_timestep_W_diff(double KW_max) const
virtual void bootstrap_impl(const File &input_file, const array::Scalar &ice_thickness)
double max_timestep_W_cfl() const
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.
virtual std::map< std::string, Diagnostic::Ptr > spatial_diagnostics_impl() const
array::Staggered1 m_Kstag
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.
void W_change_due_to_flow(double dt, const array::Scalar1 &W, const array::Staggered1 &Wstag, const array::Staggered1 &K, const array::Staggered1 &Q, array::Scalar &result)
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().
virtual void update_impl(double t, double dt, const Inputs &inputs)
Update the model state variables W and Wtill by applying the subglacial hydrology model equations.
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.
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.
const array::Staggered & velocity_staggered() const
array::Staggered1 m_Qstag
virtual std::map< std::string, TSDiagnostic::Ptr > scalar_diagnostics_impl() const
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().
Routing(std::shared_ptr< const Grid > g)
virtual void restart_impl(const File &input_file, int record)
array::Scalar1 m_bottom_surface
virtual std::set< VariableMetadata > state_impl() const
A subglacial hydrology model which assumes water pressure equals overburden pressure.
BasalWaterPressure(const Routing *m)
virtual std::shared_ptr< array::Array > compute_impl() const
Reports the pressure of the transportable water in the subglacial layer.
BasalWaterVelocity(const Routing *m)
virtual std::shared_ptr< array::Array > compute_impl() const
Diagnostically reports the staggered-grid components of the velocity of the water in the subglacial l...
virtual std::shared_ptr< array::Array > compute_impl() const
EffectiveBasalWaterPressure(const Routing *m)
Reports the effective pressure of the transportable water in the subglacial layer,...
HydraulicPotential(const Routing *m)
std::shared_ptr< array::Array > compute_impl() const
Report hydraulic potential in the subglacial hydrology system.
virtual std::shared_ptr< array::Array > compute_impl() const
RelativeBasalWaterPressure(const Routing *m)
Reports the pressure of the transportable water in the subglacial layer as a fraction of the overburd...
virtual std::shared_ptr< array::Array > compute_impl() const
WallMelt(const Routing *m)
Report the wall melt rate from dissipation of the potential energy of the transportable water.
#define PISM_ERROR_LOCATION
std::set< VariableMetadata > metadata(std::initializer_list< const Array * > vecs)
void hydraulic_potential(const array::Scalar &W, const array::Scalar &P, const array::Scalar &sea_level, const array::Scalar &bed, const array::Scalar &ice_thickness, array::Scalar &result)
Compute the hydraulic potential.
static double K(double psi_x, double psi_y, double speed, double epsilon)
void wall_melt(const Routing &model, const array::Scalar &bed_elevation, array::Scalar &result)
Compute the wall melt rate which comes from (turbulent) dissipation of flow energy.
void check_bounds(const array::Scalar &W, double W_max)
double convert(System::Ptr system, double input, const std::string &spec1, const std::string &spec2)
Convert a quantity from unit1 to unit2.
void GlobalMax(MPI_Comm comm, double *local, double *result, int count)
std::map< std::string, Diagnostic::Ptr > DiagnosticList
void ice_bottom_surface(const Geometry &geometry, array::Scalar &result)
T combine(const T &a, const T &b)