20 #include "pism/hydrology/EmptyingProblem.hh"
22 #include "pism/geometry/Geometry.hh"
23 #include "pism/util/interpolation.hh"
24 #include "pism/util/pism_utilities.hh"
29 namespace diagnostics {
41 auto grid = result.
grid();
45 for (
auto p = grid->points(); p; p.next()) {
46 const int i = p.i(), j = p.j();
48 auto P = psi.
star(i, j);
56 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) {
68 auto grid = result.
grid();
70 const auto &cell_type = geometry.
cell_type;
76 {&ice_thickness, &bed_elevation, &cell_type, &sea_level_elevation,
77 &water_flux, &result};
80 grid_spacing = 0.5 * (grid->dx() + grid->dy()),
83 for (
auto p = grid->points(); p; p.next()) {
84 const int i = p.i(), j = p.j();
86 if (cell_type.icy(i, j)) {
96 double water_depth =
std::max(sea_level_elevation(i, j) - bed_elevation(i, j), 0.0),
97 submerged_front_area = water_depth * grid_spacing;
99 if (submerged_front_area > 0.0) {
100 auto Q_sg = water_flux(i, j) * grid_spacing;
101 auto q_sg = Q_sg /
std::max(submerged_front_area, eps);
117 m_potential(grid,
"hydraulic_potential"),
118 m_tmp(grid,
"temporary_storage"),
119 m_bottom_surface(grid,
"ice_bottom_surface"),
120 m_W(grid,
"remaining_water_thickness"),
121 m_Vstag(grid,
"V_staggered"),
122 m_Qsum(grid,
"flux_total"),
123 m_domain_mask(grid,
"domain_mask"),
124 m_Q(grid,
"_water_flux"),
125 m_q_sg(grid,
"_effective_water_velocity"),
126 m_adjustment(grid,
"hydraulic_potential_adjustment"),
127 m_sinks(grid,
"sinks") {
133 .
long_name(
"estimate of the steady state hydraulic potential in the steady hydrology model")
140 "scaled water thickness in the steady state hydrology model (has no physical meaning)")
144 .
long_name(
"water velocity on the staggered grid")
152 .
long_name(
"x-component of the effective water velocity in the steady-state hydrology model")
156 .
long_name(
"y-component of the effective water velocity in the steady-state hydrology model")
161 .
long_name(
"map of sinks in the domain (for debugging)");
165 "potential adjustment needed to fill sinks when computing an estimate of the steady-state hydraulic potential")
173 m_tau =
m_config->get_number(
"hydrology.steady.input_rate_scaling");
186 bool recompute_potential) {
190 cell_area =
m_grid->cell_area(),
193 dt = 0.5 / (u_max /
m_dx + v_max /
m_dy),
194 volume_ratio =
m_config->get_number(
"hydrology.steady.volume_ratio");
196 const int n_iterations =
m_config->get_number(
"hydrology.steady.n_iterations");
198 if (recompute_potential) {
220 double volume_0 = 0.0;
224 for (
auto p =
m_grid->points(); p; p.next()) {
225 const int i = p.i(), j = p.j();
228 m_W(i, j) =
m_tau * water_input_rate(i, j);
233 volume_0 +=
m_W(i, j);
245 if (volume_0 == 0.0) {
252 int step_counter = 0;
256 for (step_counter = 0; step_counter < n_iterations; ++step_counter) {
259 for (
auto p =
m_grid->points(); p; p.next()) {
260 const int i = p.i(), j = p.j();
266 q_n = v.n * (v.n >= 0.0 ? w.c : w.n),
267 q_e = v.e * (v.e >= 0.0 ? w.c : w.e),
268 q_s = v.s * (v.s >= 0.0 ? w.s : w.c),
269 q_w = v.w * (v.w >= 0.0 ? w.w : w.c),
270 divQ = (q_e - q_w) /
m_dx + (q_n - q_s) /
m_dy;
274 m_tmp(i, j) = w.c + dt * (- divQ);
279 if (
m_tmp(i, j) < -eps) {
285 m_Qsum(i, j, 0) += dt * q_e;
286 m_Qsum(i, j, 1) += dt * q_n;
289 volume +=
m_tmp(i, j);
295 if (volume / volume_0 <= volume_ratio) {
298 m_log->message(3,
"%04d V = %f\n", step_counter, volume / volume_0);
301 m_log->message(3,
"Emptying problem: stopped after %d iterations. V = %f\n",
302 step_counter, volume / volume_0);
304 double epsilon = volume / volume_0;
325 g =
m_config->get_number(
"constants.standard_gravity"),
326 rho_i =
m_config->get_number(
"constants.ice.density"),
327 rho_w =
m_config->get_number(
"constants.fresh_water.density");
331 for (
auto p =
m_grid->points(); p; p.next()) {
332 const int i = p.i(), j = p.j();
334 result(i, j) = rho_i *
g * H(i, j) + rho_w *
g * b(i, j);
349 double delta =
m_config->get_number(
"hydrology.steady.potential_delta");
351 int n_iterations =
m_config->get_number(
"hydrology.steady.potential_n_iterations");
352 int step_counter = 0;
354 int n_sinks_remaining = 0;
359 for (step_counter = 0; step_counter < n_iterations; ++step_counter) {
361 n_sinks_remaining = 0;
362 for (
auto p =
m_grid->points(); p; p.next()) {
363 const int i = p.i(), j = p.j();
365 if (domain_mask(i, j) > 0.5) {
366 auto P = result.
star(i, j);
374 if (v_e <= 0.0 and v_w >= 0.0 and v_n <= 0.0 and v_s >= 0.0) {
377 psi_new(i, j) = 0.25 * (P.n + P.e + P.s + P.w) + delta;
379 psi_new(i, j) = result(i, j);
382 psi_new(i, j) = result(i, j);
391 if (step_counter == 0) {
392 n_sinks = n_sinks_remaining;
395 if (n_sinks_remaining == 0) {
396 m_log->message(3,
"Emptying problem: filled %d sinks after %d iterations.\n",
397 n_sinks - n_sinks_remaining, step_counter);
402 if (n_sinks_remaining > 0) {
403 m_log->message(2,
"WARNING: %d sinks left.\n", n_sinks_remaining);
408 static double K(
double psi_x,
double psi_y,
double speed,
double epsilon) {
421 for (
auto p =
m_grid->points(); p; p.next()) {
422 const int i = p.i(), j = p.j();
424 for (
int o = 0; o < 2; ++o) {
427 psi_x = (psi(i + 1, j) - psi(i, j)) /
m_dx;
428 psi_y = (psi(i + 1, j + 1) + psi(i, j + 1) - psi(i + 1, j - 1) - psi(i, j - 1)) / (4.0 *
m_dy);
431 psi_x = (psi(i + 1, j + 1) + psi(i + 1, j) - psi(i - 1, j + 1) - psi(i - 1, j)) / (4.0 *
m_dx);
432 psi_y = (psi(i, j + 1) - psi(i, j)) /
m_dy;
436 auto M = domain_mask.
star(i, j);
438 if (M.c == 0 and M.e == 0) {
439 result(i, j, 0) = 0.0;
442 if (M.c == 0 and M.n == 0) {
443 result(i, j, 1) = 0.0;
459 if (no_model_mask !=
nullptr) {
460 list.
add(*no_model_mask);
463 for (
auto p =
m_grid->points(); p; p.next()) {
464 const int i = p.i(), j = p.j();
472 if ((no_model_mask !=
nullptr) and no_model_mask->
as_int(i, j) == 1) {
const Config::ConstPtr m_config
configuration database used by this component
const Logger::ConstPtr m_log
logger (for easy access)
const std::shared_ptr< const Grid > m_grid
grid used by this component
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.
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata 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
void staggered_to_regular(const array::CellType1 &cell_type, const array::Staggered1 &input, bool include_floating_ice, array::Scalar &result)
double max(const array::Scalar &input)
Finds maximum over all the values in an array::Scalar object. Ignores ghosts.
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)