20#include "pism/hydrology/EmptyingProblem.hh"
22#include "pism/geometry/Geometry.hh"
23#include "pism/util/Interpolation1D.hh"
24#include "pism/util/pism_utilities.hh"
25#include "pism/util/Logger.hh"
30namespace diagnostics {
42 auto grid = result.
grid();
46 for (
auto p : grid->points()) {
47 const int i = p.i(), j = p.j();
49 auto P = psi.
star(i, j);
57 if (domain_mask(i, j) > 0.5 and v_e <= 0.0 and v_w >= 0.0 and v_n <= 0.0 and v_s >= 0.0) {
69 auto grid = result.
grid();
71 const auto &cell_type = geometry.
cell_type;
77 {&ice_thickness, &bed_elevation, &cell_type, &sea_level_elevation,
78 &water_flux, &result};
81 grid_spacing = 0.5 * (grid->dx() + grid->dy()),
84 for (
auto p : grid->points()) {
85 const int i = p.i(), j = p.j();
87 if (cell_type.icy(i, j)) {
97 double water_depth = std::max(sea_level_elevation(i, j) - bed_elevation(i, j), 0.0),
98 submerged_front_area = water_depth * grid_spacing;
100 if (submerged_front_area > 0.0) {
101 auto Q_sg = water_flux(i, j) * grid_spacing;
102 auto q_sg = Q_sg / std::max(submerged_front_area, eps);
118 m_potential(grid,
"hydraulic_potential"),
119 m_tmp(grid,
"temporary_storage"),
120 m_bottom_surface(grid,
"ice_bottom_surface"),
121 m_W(grid,
"remaining_water_thickness"),
122 m_Vstag(grid,
"V_staggered"),
123 m_Qsum(grid,
"flux_total"),
124 m_domain_mask(grid,
"domain_mask"),
125 m_Q(grid,
"_water_flux"),
126 m_q_sg(grid,
"_effective_water_velocity"),
127 m_adjustment(grid,
"hydraulic_potential_adjustment"),
128 m_sinks(grid,
"sinks") {
134 .
long_name(
"estimate of the steady state hydraulic potential in the steady hydrology model")
141 "scaled water thickness in the steady state hydrology model (has no physical meaning)")
145 .
long_name(
"water velocity on the staggered grid")
153 .
long_name(
"x-component of the effective water velocity in the steady-state hydrology model")
157 .
long_name(
"y-component of the effective water velocity in the steady-state hydrology model")
162 .
long_name(
"map of sinks in the domain (for debugging)");
166 "potential adjustment needed to fill sinks when computing an estimate of the steady-state hydraulic potential")
174 m_tau =
m_config->get_number(
"hydrology.steady.input_rate_scaling");
187 bool recompute_potential) {
191 cell_area =
m_grid->cell_area(),
194 dt = 0.5 / (u_max /
m_dx + v_max /
m_dy),
195 volume_ratio =
m_config->get_number(
"hydrology.steady.volume_ratio");
197 const int n_iterations =
m_config->get_number(
"hydrology.steady.n_iterations");
199 if (recompute_potential) {
221 double volume_0 = 0.0;
225 for (
auto p :
m_grid->points()) {
226 const int i = p.i(), j = p.j();
229 m_W(i, j) =
m_tau * water_input_rate(i, j);
234 volume_0 +=
m_W(i, j);
246 if (volume_0 == 0.0) {
253 int step_counter = 0;
257 for (step_counter = 0; step_counter < n_iterations; ++step_counter) {
260 for (
auto p :
m_grid->points()) {
261 const int i = p.i(), j = p.j();
267 q_n = v.n * (v.n >= 0.0 ? w.c : w.n),
268 q_e = v.e * (v.e >= 0.0 ? w.c : w.e),
269 q_s = v.s * (v.s >= 0.0 ? w.s : w.c),
270 q_w = v.w * (v.w >= 0.0 ? w.w : w.c),
271 divQ = (q_e - q_w) /
m_dx + (q_n - q_s) /
m_dy;
275 m_tmp(i, j) = w.c + dt * (- divQ);
280 if (
m_tmp(i, j) < -eps) {
286 m_Qsum(i, j, 0) += dt * q_e;
287 m_Qsum(i, j, 1) += dt * q_n;
290 volume +=
m_tmp(i, j);
296 if (volume / volume_0 <= volume_ratio) {
299 m_log->message(3,
"%04d V = %f\n", step_counter, volume / volume_0);
302 m_log->message(3,
"Emptying problem: stopped after %d iterations. V = %f\n",
303 step_counter, volume / volume_0);
305 double epsilon = volume / volume_0;
326 g =
m_config->get_number(
"constants.standard_gravity"),
327 rho_i =
m_config->get_number(
"constants.ice.density"),
328 rho_w =
m_config->get_number(
"constants.fresh_water.density");
332 for (
auto p :
m_grid->points()) {
333 const int i = p.i(), j = p.j();
335 result(i, j) = rho_i *
g * H(i, j) + rho_w *
g * b(i, j);
350 double delta =
m_config->get_number(
"hydrology.steady.potential_delta");
352 int n_iterations =
m_config->get_number(
"hydrology.steady.potential_n_iterations");
353 int step_counter = 0;
355 int n_sinks_remaining = 0;
360 for (step_counter = 0; step_counter < n_iterations; ++step_counter) {
362 n_sinks_remaining = 0;
363 for (
auto p :
m_grid->points()) {
364 const int i = p.i(), j = p.j();
366 if (domain_mask(i, j) > 0.5) {
367 auto P = result.
star(i, j);
375 if (v_e <= 0.0 and v_w >= 0.0 and v_n <= 0.0 and v_s >= 0.0) {
378 psi_new(i, j) = 0.25 * (P.n + P.e + P.s + P.w) + delta;
380 psi_new(i, j) = result(i, j);
383 psi_new(i, j) = result(i, j);
392 if (step_counter == 0) {
393 n_sinks = n_sinks_remaining;
396 if (n_sinks_remaining == 0) {
397 m_log->message(3,
"Emptying problem: filled %d sinks after %d iterations.\n",
398 n_sinks - n_sinks_remaining, step_counter);
403 if (n_sinks_remaining > 0) {
404 m_log->message(2,
"WARNING: %d sinks left.\n", n_sinks_remaining);
409static double K(
double psi_x,
double psi_y,
double speed,
double epsilon) {
410 return speed / std::max(
Vector2d(psi_x, psi_y).magnitude(), epsilon);
422 for (
auto p :
m_grid->points()) {
423 const int i = p.i(), j = p.j();
425 for (
int o = 0; o < 2; ++o) {
428 psi_x = (psi(i + 1, j) - psi(i, j)) /
m_dx;
429 psi_y = (psi(i + 1, j + 1) + psi(i, j + 1) - psi(i + 1, j - 1) - psi(i, j - 1)) / (4.0 *
m_dy);
432 psi_x = (psi(i + 1, j + 1) + psi(i + 1, j) - psi(i - 1, j + 1) - psi(i - 1, j)) / (4.0 *
m_dx);
433 psi_y = (psi(i, j + 1) - psi(i, j)) /
m_dy;
437 auto M = domain_mask.
star(i, j);
439 if (M.c == 0 and M.e == 0) {
440 result(i, j, 0) = 0.0;
443 if (M.c == 0 and M.n == 0) {
444 result(i, j, 1) = 0.0;
460 if (no_model_mask !=
nullptr) {
461 list.
add(*no_model_mask);
464 for (
auto p :
m_grid->points()) {
465 const int i = p.i(), j = p.j();
473 if ((no_model_mask !=
nullptr) and no_model_mask->
as_int(i, j) == 1) {
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
std::shared_ptr< const Logger > m_log
logger (for easy access)
A class defining a common interface for most PISM sub-models.
static Ptr wrap(const T &input)
array::Scalar1 sea_level_elevation
array::CellType2 cell_type
array::Scalar2 ice_thickness
array::Scalar2 bed_elevation
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
This class represents a 2D vector field (such as ice velocity) at a certain grid point.
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 set_interpolation_type(InterpolationType type)
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 update_ghosts()
Updates ghost points.
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
bool ice_free_ocean(int i, int j) const
bool icy(int i, int j) const
"Cell type" mask. Adds convenience methods to array::Scalar.
int as_int(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....
void compute_velocity(const array::Scalar &hydraulic_potential, const array::Scalar1 &mask, array::Staggered &result) const
const array::Scalar & sinks() const
array::Scalar1 m_domain_mask
array::Scalar m_adjustment
const array::Vector & flux() const
const array::Scalar & adjustment() const
void compute_mask(const array::CellType &cell_type, const array::Scalar *no_model_mask, array::Scalar &result) const
DiagnosticList diagnostics() const
const array::Scalar & potential() const
void compute_potential(const array::Scalar &ice_thickness, const array::Scalar &ice_bottom_surface, const array::Scalar &domain_mask, array::Scalar1 &result)
EmptyingProblem(std::shared_ptr< const Grid > g)
const array::Scalar & remaining_water_thickness() const
virtual void compute_raw_potential(const array::Scalar &ice_thickness, const array::Scalar &ice_bottom_surface, array::Scalar &result) const
array::Staggered1 m_Vstag
void update(const Geometry &geometry, const array::Scalar *no_model_mask, const array::Scalar &water_input_rate, bool recompute_potential=true)
array::Scalar1 m_potential
array::Scalar m_bottom_surface
const array::Vector & effective_water_velocity() const
#define PISM_ERROR_LOCATION
static void compute_sinks(const array::Scalar &domain_mask, const array::Scalar1 &psi, array::Scalar &result)
static void effective_water_velocity(const Geometry &geometry, const array::Vector &water_flux, array::Vector &result)
static double K(double psi_x, double psi_y, double speed, double epsilon)
std::map< std::string, Diagnostic::Ptr > DiagnosticList
void ice_bottom_surface(const Geometry &geometry, array::Scalar &result)
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)