20#include "pism/stressbalance/ssa/SSAFDBase.hh"
22#include "pism/basalstrength/basal_resistance.hh"
23#include "pism/geometry/Geometry.hh"
24#include "pism/rheology/FlowLaw.hh"
25#include "pism/stressbalance/StressBalance.hh"
27#include "pism/util/Mask.hh"
29#include "pism/util/pism_utilities.hh"
33namespace stressbalance {
37 m_work(grid,
"work_vector", array::WITH_GHOSTS, 1 ),
38 m_hardness(grid,
"ice_hardness"),
40 m_cell_type(m_grid,
"ssafd_cell_type"),
41 m_rhs(grid,
"right_hand_side"),
42 m_taud(m_grid,
"taud"),
44 m_regional_mode(regional_mode) {
46 m_work.metadata(0).long_name(
"temporary storage used to compute nuH");
49 .
long_name(
"vertically-averaged ice hardness")
53 .
long_name(
"ice thickness times effective viscosity")
58 .
long_name(
"ice-type (ice-free/grounded/floating/ocean) integer mask");
61 m_cell_type.
metadata()[
"flag_meanings"] =
"ice_free_bedrock grounded_ice floating_ice ice_free_ocean";
64 .
long_name(
"X-component of the driving shear stress at the base of ice")
67 .
long_name(
"Y-component of the driving shear stress at the base of ice")
83static int weight(
bool margin_bc,
int M_ij,
int M_n,
double h_ij,
double h_n,
int N_ij,
int N_n) {
91 if ((grounded(M_ij) and floating_ice(M_n)) or (floating_ice(M_ij) and grounded(M_n)) or
92 (floating_ice(M_ij) and ice_free_ocean(M_n))) {
97 if ((icy(M_ij) and ice_free(M_n) and h_n > h_ij) or
98 (ice_free(M_ij) and icy(M_n) and h_ij > h_n)) {
104 if (margin_bc and ((icy(M_ij) and ice_free(M_n)) or (ice_free(M_ij) and icy(M_n)))) {
109 if ((N_ij == 0 and N_n == 1) or (N_ij == 1 and N_n == 0)) {
83static int weight(
bool margin_bc,
int M_ij,
int M_n,
double h_ij,
double h_n,
int N_ij,
int N_n) {
…}
119 double dL = C -
L, dR = R - C;
127 return dL < 0.0 ? dL : dR;
131 return 0.5 * (dL + dR);
135 return 0.5 * (R -
L);
152 bool cfbc =
m_config->get_flag(
"stress_balance.calving_front_stress_bc");
153 bool surface_gradient_inward =
154 m_config->get_flag(
"stress_balance.ssa.compute_surface_gradient_inward");
157 if (
m_config->get_flag(
"stress_balance.ssa.fd.upstream_surface_slope_approximation")) {
165 if (no_model_mask !=
nullptr) {
166 list.
add(*no_model_mask);
169 for (
auto p =
m_grid->points(); p; p.next()) {
170 const int i = p.i(), j = p.j();
172 const double pressure = EC.
pressure(ice_thickness(i, j));
173 if (pressure <= 0.0) {
179 if (surface_gradient_inward) {
180 double h_x = diff_x_p(surface_elevation, i, j), h_y = diff_y_p(surface_elevation, i, j);
181 result(i, j) = -pressure *
Vector2d(h_x, h_y);
203 auto h = surface_elevation.
star(i, j);
206 if (no_model_mask !=
nullptr) {
213 int west =
weight(cfbc, M.c, M.w, h.c, h.w, N.
c, N.
w),
214 east =
weight(cfbc, M.c, M.e, h.c, h.e, N.
c, N.
e);
218 h_x = diff_grounded(h.w, h.c, h.e) / dx;
219 }
else if (east + west > 0) {
220 h_x = 1.0 / ((west + east) * dx) * (west * (h.c - h.w) + east * (h.e - h.c));
221 if (floating_ice(M.c) and (ice_free_ocean(M.e) or ice_free_ocean(M.w))) {
234 int south =
weight(cfbc, M.c, M.s, h.c, h.s, N.
c, N.
s),
235 north =
weight(cfbc, M.c, M.n, h.c, h.n, N.
c, N.
n);
239 h_y = diff_grounded(h.s, h.c, h.n) / dy;
240 }
else if (north + south > 0) {
241 h_y = 1.0 / ((south + north) * dy) * (south * (h.c - h.s) + north * (h.n - h.c));
242 if (floating_ice(M.c) and (ice_free_ocean(M.s) or ice_free_ocean(M.n))) {
252 result(i, j) = -pressure *
Vector2d(h_x, h_y);
272 auto M = cell_type.
box_int(i, j);
278 if (ssa_dirichlet_bc) {
279 return icy(M.c) && (ice_free(M.e) || ice_free(M.w) || ice_free(M.n) || ice_free(M.s) ||
280 ice_free(M.ne) || ice_free(M.se) || ice_free(M.nw) || ice_free(M.sw));
283 return icy(M.c) && (ice_free_ocean(M.e) || ice_free_ocean(M.w) || ice_free_ocean(M.n) ||
284 ice_free_ocean(M.s) || ice_free_ocean(M.ne) || ice_free_ocean(M.se) ||
285 ice_free_ocean(M.nw) || ice_free_ocean(M.sw));
319 standard_gravity =
m_config->get_number(
"constants.standard_gravity"),
320 rho_ocean =
m_config->get_number(
"constants.sea_water.density"),
325 const Vector2d ice_free_velocity(0.0, 0.0);
327 const bool use_cfbc =
m_config->get_flag(
"stress_balance.calving_front_stress_bc"),
328 flow_line_mode =
m_config->get_flag(
"stress_balance.ssa.fd.flow_line_mode");
331 bool bedrock_boundary =
m_config->get_flag(
"stress_balance.ssa.dirichlet_bc");
342 list.add({ &thickness, &bed, &surface, &cell_type, &sea_level });
345 if (use_cfbc and (water_column_pressure !=
nullptr)) {
346 list.add(*water_column_pressure);
351 for (
auto p =
m_grid->points(); p; p.next()) {
352 const int i = p.i(), j = p.j();
356 if (flow_line_mode) {
362 result(i, j).u = bc_scaling * (*inputs.
bc_values)(i, j).u;
363 result(i, j).v = bc_scaling * (*inputs.
bc_values)(i, j).v;
368 double H_ij = thickness(i, j);
377 result(i, j) = bc_scaling * ice_free_velocity;
381 if (
is_marginal(i, j, cell_type, bedrock_boundary)) {
383 int W = 0, E = 0,
S = 0, N = 0;
386 if (bedrock_boundary) {
387 if (ice_free_ocean(M.e))
389 if (ice_free_ocean(M.w))
391 if (ice_free_ocean(M.n))
393 if (ice_free_ocean(M.s))
407 double P_ice = 0.5 *
rho_ice * standard_gravity * H_ij, P_water = 0.0;
409 if (water_column_pressure !=
nullptr) {
410 P_water = (*water_column_pressure)(i, j);
413 rho_ocean, standard_gravity);
416 double delta_p = H_ij * (P_ice - P_water);
433 auto b = bed.
star(i, j);
434 double h = surface(i, j);
436 if (ice_free(M.n) and b.n > h) {
439 if (ice_free(M.e) and b.e > h) {
442 if (ice_free(M.s) and b.s > h) {
445 if (ice_free(M.w) and b.w > h) {
456 result(i, j).u = taud.
u + (E - W) * delta_p / dx;
457 result(i, j).v = taud.
v + (N -
S) * delta_p / dy;
562 const int diag_u = 4;
563 const int diag_v = 13;
565 PetscErrorCode ierr = 0;
573 beta_lateral_margin =
m_config->get_number(
"basal_resistance.beta_lateral_margin"),
574 beta_ice_free_bedrock =
575 m_config->get_number(
"basal_resistance.beta_ice_free_bedrock");
579 bedrock_boundary =
m_config->get_flag(
"stress_balance.ssa.dirichlet_bc"),
580 flow_line_mode =
m_config->get_flag(
"stress_balance.ssa.fd.flow_line_mode"),
581 use_cfbc =
m_config->get_flag(
"stress_balance.calving_front_stress_bc"),
582 replace_zero_diagonal_entries =
583 m_config->get_flag(
"stress_balance.ssa.fd.replace_zero_diagonal_entries");
586 ierr = MatZeroEntries(*A);
592 auto velocity = [&input_velocity](
int i,
int j) {
return input_velocity[j][i]; };
594 if (bc_mask !=
nullptr) {
598 const bool sub_gl =
m_config->get_flag(
"geometry.grounded_cell_fraction");
600 list.add(grounded_fraction);
605 bool lateral_drag_enabled =
m_config->get_flag(
"stress_balance.ssa.fd.lateral_drag.enabled");
606 if (lateral_drag_enabled) {
607 list.add({ &thickness, &bed, &surface });
609 double lateral_drag_viscosity =
610 m_config->get_number(
"stress_balance.ssa.fd.lateral_drag.viscosity");
611 double HminFrozen = 0.0;
616 for (
auto p =
m_grid->points(); p; p.next()) {
617 const int i = p.i(), j = p.j();
622 bool bc_location = bc_mask !=
nullptr and bc_mask->
as_int(i, j) == 1;
627 bool ice_free_with_cfbc = use_cfbc and cell_type.
ice_free(i, j);
629 if (bc_location or ice_free_with_cfbc) {
631 Ax[j][i] = bc_scaling *
velocity(i, j);
636 MatStencil row[2] = { { -1, j, i, 0 }, { -1, j, i, 1 } };
637 double identity[4] = { bc_scaling, 0.0, 0.0, bc_scaling };
638 ierr = MatSetValuesStencil(*A, 2, row, 2, row, identity, INSERT_VALUES);
639 PISM_CHK(ierr,
"MatSetValuesStencil");
652 if (lateral_drag_enabled) {
658 auto H = thickness.
star(i, j);
659 auto b = bed.star(i, j);
660 double h = surface(i, j);
662 if (H.c > HminFrozen) {
663 if (b.w > h and ice_free_land(M.w)) {
664 c.
w = lateral_drag_viscosity * 0.5 * (H.c + H.w);
666 if (b.e > h and ice_free_land(M.e)) {
667 c.
e = lateral_drag_viscosity * 0.5 * (H.c + H.e);
669 if (b.n > h and ice_free_land(M.n)) {
670 c.
n = lateral_drag_viscosity * 0.5 * (H.c + H.n);
672 if (b.s > h and ice_free_land(M.s)) {
673 c.
s = lateral_drag_viscosity * 0.5 * (H.c + H.s);
682 const int n_nonzeros = 18;
695 int N = 1, E = 1,
S = 1, W = 1;
700 int NNW = 1, NNE = 1, SSW = 1, SSE = 1;
701 int WNW = 1, ENE = 1, WSW = 1, ESE = 1;
703 int M_ij = cell_type.
as_int(i, j);
706 auto M = cell_type.
box_int(i, j);
708 if (
is_marginal(i, j, cell_type, bedrock_boundary)) {
712 if (bedrock_boundary) {
714 if (ice_free_ocean(M.e))
716 if (ice_free_ocean(M.w))
718 if (ice_free_ocean(M.n))
720 if (ice_free_ocean(M.s))
724 if (ice_free_ocean(M.n) || ice_free_ocean(M.ne))
726 if (ice_free_ocean(M.e) || ice_free_ocean(M.ne))
728 if (ice_free_ocean(M.e) || ice_free_ocean(M.se))
730 if (ice_free_ocean(M.s) || ice_free_ocean(M.se))
732 if (ice_free_ocean(M.s) || ice_free_ocean(M.sw))
734 if (ice_free_ocean(M.w) || ice_free_ocean(M.sw))
736 if (ice_free_ocean(M.w) || ice_free_ocean(M.nw))
738 if (ice_free_ocean(M.n) || ice_free_ocean(M.nw))
753 if (ice_free(M.n) || ice_free(M.ne))
755 if (ice_free(M.e) || ice_free(M.ne))
757 if (ice_free(M.e) || ice_free(M.se))
759 if (ice_free(M.s) || ice_free(M.se))
761 if (ice_free(M.s) || ice_free(M.sw))
763 if (ice_free(M.w) || ice_free(M.sw))
765 if (ice_free(M.w) || ice_free(M.nw))
767 if (ice_free(M.n) || ice_free(M.nw))
776 const double dx2 = dx * dx, dy2 = dy * dy, d4 = 4 * dx * dy, d2 = 2 * dx * dy;
784 (c.
n * N + c.
s *
S) / dy2 + (4 * c.
e * E + 4 * c.
w * W) / dx2,
789 c.
w * W * WNW / d2 + c.
n * NNW * N / d4,
790 (c.
n * NNE * N - c.
n * NNW * N) / d4 + (c.
w * W * N - c.
e * E * N) / d2,
791 -c.
e * E * ENE / d2 - c.
n * NNE * N / d4,
792 (c.
w * W * WSW - c.
w * W * WNW) / d2 + (c.
n * W * N - c.
s * W *
S) / d4,
793 (c.
n * E * N - c.
n * W * N - c.
s * E *
S + c.
s * W *
S) / d4 +
794 (c.
e * E * N - c.
w * W * N - c.
e * E *
S + c.
w * W *
S) / d2,
795 (c.
e * E * ENE - c.
e * E * ESE) / d2 + (c.
s * E *
S - c.
n * E * N) / d4,
796 -c.
w * W * WSW / d2 - c.
s * SSW *
S / d4,
797 (c.
s * SSW *
S - c.
s * SSE *
S) / d4 + (c.
e * E *
S - c.
w * W *
S) / d2,
798 c.
e * E * ESE / d2 + c.
s * SSE *
S / d4,
803 c.
w * W * WNW / d4 + c.
n * NNW * N / d2,
804 (c.
n * NNE * N - c.
n * NNW * N) / d2 + (c.
w * W * N - c.
e * E * N) / d4,
805 -c.
e * E * ENE / d4 - c.
n * NNE * N / d2,
806 (c.
w * W * WSW - c.
w * W * WNW) / d4 + (c.
n * W * N - c.
s * W *
S) / d2,
807 (c.
n * E * N - c.
n * W * N - c.
s * E *
S + c.
s * W *
S) / d2 +
808 (c.
e * E * N - c.
w * W * N - c.
e * E *
S + c.
w * W *
S) / d4,
809 (c.
e * E * ENE - c.
e * E * ESE) / d4 + (c.
s * E *
S - c.
n * E * N) / d2,
810 -c.
w * W * WSW / d4 - c.
s * SSW *
S / d2,
811 (c.
s * SSW *
S - c.
s * SSE *
S) / d2 + (c.
e * E *
S - c.
w * W *
S) / d4,
812 c.
e * E * ESE / d4 + c.
s * SSE *
S / d2,
817 (4 * c.
n * N + 4 * c.
s *
S) / dy2 + (c.
e * E + c.
w * W) / dx2,
826 i - 1, i, i + 1, i - 1, i, i + 1, i - 1, i, i + 1,
827 i - 1, i, i + 1, i - 1, i, i + 1, i - 1, i, i + 1,
832 j + 1, j + 1, j + 1, j, j, j, j - 1, j - 1, j - 1,
833 j + 1, j + 1, j + 1, j, j, j, j - 1, j - 1, j - 1,
838 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
846 double beta_u = 0.0, beta_v = 0.0;
853 beta = beta_ice_free_bedrock;
858 double scaling = sub_gl ? grounded_fraction(i, j) : 0.0;
859 beta = scaling * basal_sliding_law->
drag(basal_yield_stress(i, j), v.
u, v.
v);
864 double scaling = sub_gl ? grounded_fraction(i, j) : 1.0;
865 beta = scaling * basal_sliding_law->
drag(basal_yield_stress(i, j), v.
u, v.
v);
882 auto b = bed.star(i, j);
883 double h = surface(i, j);
885 if ((ice_free(M.n) and b.n > h) or (ice_free(M.s) and b.s > h)) {
886 beta_u += beta_lateral_margin;
889 if ((ice_free(M.e) and b.e > h) or (ice_free(M.w) and b.w > h)) {
890 beta_v += beta_lateral_margin;
895 eq1[diag_u] += beta_u;
896 eq2[diag_v] += beta_v;
898 if (flow_line_mode) {
900 for (
int k = 0;
k < n_nonzeros; ++
k) {
903 eq2[diag_v] = bc_scaling;
907 const double eps = 1e-16;
908 if (fabs(eq1[diag_u]) < eps) {
909 if (replace_zero_diagonal_entries) {
910 eq1[diag_u] = beta_ice_free_bedrock;
913 "first (X) equation in the SSAFD system:"
914 " zero diagonal entry at a regular (not Dirichlet B.C.)"
915 " location: i = %d, j = %d\n",
919 if (fabs(eq2[diag_v]) < eps) {
920 if (replace_zero_diagonal_entries) {
921 eq2[diag_v] = beta_ice_free_bedrock;
924 "second (Y) equation in the SSAFD system:"
925 " zero diagonal entry at a regular (not Dirichlet B.C.)"
926 " location: i = %d, j = %d\n",
934 for (
int k = 0;
k < n_nonzeros; ++
k) {
936 double u_or_v = v.
u * (1 - C[
k]) + v.
v * C[
k];
944 MatStencil row, col[n_nonzeros];
947 for (
int m = 0; m < n_nonzeros; m++) {
955 ierr = MatSetValuesStencil(*A, 1, &row, n_nonzeros, col, eq1, INSERT_VALUES);
956 PISM_CHK(ierr,
"MatSetValuesStencil");
960 ierr = MatSetValuesStencil(*A, 1, &row, n_nonzeros, col, eq2, INSERT_VALUES);
961 PISM_CHK(ierr,
"MatSetValuesStencil");
970 ierr = MatAssemblyBegin(*A, MAT_FINAL_ASSEMBLY);
973 ierr = MatAssemblyEnd(*A, MAT_FINAL_ASSEMBLY);
976 ierr = MatSetOption(*A, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE);
990 const double *E_ij =
nullptr, *E_offset =
nullptr;
993 std::vector<double> E(Mz);
999 for (
auto p =
m_grid->points(); p; p.next()) {
1000 const int i = p.i(), j = p.j();
1003 for (
int o = 0; o < 2; o++) {
1004 const int oi = 1 - o, oj = o;
1007 if (cell_type.
icy(i, j) && cell_type.
icy(i + oi, j + oj)) {
1008 H = 0.5 * (ice_thickness(i, j) + ice_thickness(i + oi, j + oj));
1009 }
else if (cell_type.
icy(i, j)) {
1010 H = ice_thickness(i, j);
1012 H = ice_thickness(i + oi, j + oj);
1016 result(i, j, o) = -1e6;
1020 E_offset = enthalpy.
get_column(i + oi, j + oj);
1022 for (
unsigned int k = 0;
k < Mz; ++
k) {
1023 E[
k] = 0.5 * (E_ij[
k] + E_offset[
k]);
1027 m_grid->z().data(), E.data());
1042 auto weight = [](
int M_ij,
int M_n,
double h_ij,
double h_n) {
1064 for (
auto p =
m_grid->points(); p; p.next()) {
1065 const int i = p.i(), j = p.j();
1067 auto M = no_model_mask->
star_int(i, j);
1075 double pressure =
m_EC->pressure(ice_thickness(i, j));
1076 if (pressure <= 0) {
1081 auto h = surface_elevation.
star(i, j);
1082 auto CT = cell_type.
star_int(i, j);
1088 west =
static_cast<double>(M.w == 1 and i > 0),
1089 east =
static_cast<double>(M.e == 1 and i < Mx - 1);
1092 west *=
weight(CT.c, CT.w, h.c, h.w);
1093 east *=
weight(CT.c, CT.e, h.c, h.e);
1095 if (east + west > 0) {
1096 h_x = 1.0 / ((west + east) * dx) * (west * (h.c - h.w) + east * (h.e - h.c));
1106 south =
static_cast<double>(M.s == 1 and j > 0),
1107 north =
static_cast<double>(M.n == 1 and j < My - 1);
1110 south *=
weight(CT.c, CT.s, h.c, h.s);
1111 north *=
weight(CT.c, CT.n, h.c, h.n);
1113 if (north + south > 0) {
1114 h_y = 1.0 / ((south + north) * dy) * (south * (h.c - h.s) + north * (h.n - h.c));
1133 const double H_threshold =
m_config->get_number(
"stress_balance.ice_free_thickness_standard");
1199 const double epsilon =
m_config->get_number(
"fracture_density.softening_lower_limit");
1203 for (
auto p =
m_grid->points(); p; p.next()) {
1204 const int i = p.i(), j = p.j();
1206 for (
int o = 0; o < 2; o++) {
1207 const int oi = 1 - o, oj = o;
1211 phi = 0.5 * (fracture_density(i, j) + fracture_density(i + oi, j + oj)),
1213 softening = pow((1.0 - (1.0 - epsilon) *
phi), -n_glen);
1215 ice_hardness(i, j, o) *= pow(softening, -1.0 / n_glen);
1277 nu_enhancement_scaling = 1.0 / pow(
m_e_factor, 1.0 / n_glen);
1281 for (
auto p =
m_grid->points(); p; p.next()) {
1282 const int i = p.i(), j = p.j();
1290 stencils::Box<Vector2d> V{ uv(i, j), uv(i, N), uv(W, N), uv(W, j), uv(W,
S),
1291 uv(i,
S), uv(E,
S), uv(E, j), uv(E, N) };
1293 for (
int o = 0; o < 2; ++o) {
1294 const int oi = 1 - o, oj = o;
1296 const double H = 0.5 * (ice_thickness(i, j) + ice_thickness(i + oi, j + oj));
1298 if (H < strength_extension->get_min_thickness()) {
1303 double u_x, u_y, v_x, v_y;
1306 u_x = (V.e.u - V.c.u) / dx;
1307 v_x = (V.e.v - V.c.v) / dx;
1308 u_y = (V.n.u + V.ne.u - V.s.u - V.se.u) / (4 * dy);
1309 v_y = (V.n.v + V.ne.v - V.s.v - V.se.v) / (4 * dy);
1311 u_x = (V.e.u + V.ne.u - V.w.u - V.nw.u) / (4 * dx);
1312 v_x = (V.e.v + V.ne.v - V.w.v - V.nw.v) / (4 * dx);
1313 u_y = (V.n.u - V.c.u) / dy;
1314 v_y = (V.n.v - V.c.v) / dy;
1318 m_flow_law->effective_viscosity(hardness(i, j, o),
1321 result(i, j, o) = nu * H;
1324 result(i, j, o) *= nu_enhancement_scaling;
1327 result(i, j, o) += nuH_regularization;
1358 nu_enhancement_scaling = 1.0 / pow(
m_e_factor, 1.0 / n_glen);
1364 assert(
m_work.stencil_width() >= 1);
1369 for (
auto p =
m_grid->points(1); p; p.next()) {
1370 const int i = p.i(), j = p.j();
1374 if (cell_type.
icy(i, j) && cell_type.
icy(i + 1, j)) {
1375 m_work(i, j).u_x = (U(i + 1, j) - U(i, j)) / dx;
1376 m_work(i, j).v_x = (V(i + 1, j) - V(i, j)) / dx;
1387 if (cell_type.
icy(i, j) && cell_type.
icy(i, j + 1)) {
1388 m_work(i, j).u_y = (U(i, j + 1) - U(i, j)) / dy;
1389 m_work(i, j).v_y = (V(i, j + 1) - V(i, j)) / dy;
1399 list.add({ &result, &hardness, &ice_thickness });
1401 for (
auto p =
m_grid->points(); p; p.next()) {
1402 const int i = p.i(), j = p.j();
1404 double u_x, u_y, v_x, v_y, H, nu, W;
1407 if (cell_type.
icy(i, j) && cell_type.
icy(i + 1, j)) {
1408 H = 0.5 * (ice_thickness(i, j) + ice_thickness(i + 1, j));
1409 }
else if (cell_type.
icy(i, j)) {
1410 H = ice_thickness(i, j);
1412 H = ice_thickness(i + 1, j);
1435 result(i, j, 0) = nu * H;
1443 if (cell_type.
icy(i, j) && cell_type.
icy(i, j + 1)) {
1444 H = 0.5 * (ice_thickness(i, j) + ice_thickness(i, j + 1));
1445 }
else if (cell_type.
icy(i, j)) {
1446 H = ice_thickness(i, j);
1448 H = ice_thickness(i, j + 1);
1469 m_flow_law->effective_viscosity(hardness(i, j, 1),
1471 result(i, j, 1) = nu * H;
1478 for (
int o = 0; o < 2; ++o) {
1480 result(i, j, o) *= nu_enhancement_scaling;
1483 result(i, j, o) += nuH_regularization;
1491 if (
m_config->get_flag(
"stress_balance.calving_front_stress_bc")) {
1520 for (
auto p =
m_grid->points(); p; p.next()) {
1521 const int i = p.i(), j = p.j();
1523 result[j][i] -=
m_rhs(i, j);
1554 .long_name(
"ice thickness times effective viscosity, i-offset")
1556 .output_units(
"kPa s m");
1558 .long_name(
"ice thickness times effective viscosity, j-offset")
1560 .output_units(
"kPa s m");
1565 auto result = allocate<array::Staggered>(
"nuH");
1567 result->copy_from(
model->integrated_viscosity());
1585 m_vars[0].long_name(
"X-component of the driving shear stress at the base of ice");
1586 m_vars[1].long_name(
"Y-component of the driving shear stress at the base of ice");
1590 v[
"comment"] =
"this is the driving stress used by the SSAFD solver";
1596 auto result = allocate<array::Vector>(
"taud");
1598 result->copy_from(
model->driving_stress());
1613 m_vars[0].long_name(
"magnitude of the driving shear stress at the base of ice").units(
"Pa");
1614 m_vars[0][
"comment"] =
"this is the magnitude of the driving stress used by the SSAFD solver";
1619 auto result = allocate<array::Scalar>(
"taud_mag");
1620 result->metadata(0) =
m_vars[0];
1622 compute_magnitude(
model->driving_stress(), *result);
const Config::ConstPtr m_config
configuration database used by this component
const std::shared_ptr< const Grid > m_grid
grid used by this component
A template derived from Diagnostic, adding a "Model".
const units::System::Ptr m_sys
the unit system
std::vector< SpatialVariableMetadata > m_vars
metadata corresponding to NetCDF variables
std::shared_ptr< Diagnostic > Ptr
double pressure(double depth) const
Get pressure in ice from depth below surface using the hydrostatic assumption.
Converts between specific enthalpy and temperature or liquid content.
void compute_mask(const array::Scalar &sea_level, const array::Scalar &bed, const array::Scalar &thickness, array::Scalar &result) const
void set_icefree_thickness(double threshold)
array::Scalar1 sea_level_elevation
array::Scalar cell_grounded_fraction
array::Scalar2 ice_surface_elevation
array::Scalar2 ice_thickness
array::Scalar2 bed_elevation
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.
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
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)
double * get_column(int i, int j)
A virtual class collecting methods common to ice and bedrock 3D fields.
void set(double c)
Result: v[j] <- c for all j.
void update_ghosts()
Updates ghost points.
unsigned int stencil_width() const
Get the stencil width of the current Array. Returns 0 if ghosts are not available.
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
stencils::Box< int > box_int(int i, int j) const
stencils::Star< int > star_int(int i, int j) const
bool ice_free(int i, int j) const
bool icy(int i, int j) const
stencils::Star< int > star_int(int i, int j) const
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_driving_stress(const array::Scalar &ice_thickness, const array::Scalar1 &surface_elevation, const array::CellType1 &cell_type, const array::Scalar1 *no_model_mask, const EnthalpyConverter &EC, array::Vector &result) const
Compute the gravitational driving stress.
void assemble_rhs(const Inputs &inputs, const array::CellType1 &cell_type, const array::Vector &driving_stress, double bc_scaling, array::Vector &result) const
Computes the right-hand side ("rhs") of the linear problem for the Picard iteration and finite-differ...
array::Vector m_taud
driving stress
const array::Staggered & integrated_viscosity() const
void compute_nuH_cfbc(const array::Scalar1 &ice_thickness, const array::CellType2 &cell_type, const pism::Vector2d *const *velocity, const array::Staggered &hardness, double nuH_regularization, array::Staggered &result)
Compute the product of ice viscosity and thickness on the staggered grid. Used when CFBC is enabled.
array::Staggered m_hardness
ice hardness
void fd_operator(const Geometry &geometry, const array::Scalar *bc_mask, double bc_scaling, const array::Scalar &basal_yield_stress, IceBasalResistancePlasticLaw *basal_sliding_law, const pism::Vector2d *const *velocity, const array::Staggered1 &nuH, const array::CellType1 &cell_type, Mat *A, Vector2d **Ax) const
Assemble the left-hand side matrix for the KSP-based, Picard iteration, and finite difference impleme...
void initialize_iterations(const Inputs &inputs)
void fracture_induced_softening(const array::Scalar1 &fracture_density, double n_glen, array::Staggered &ice_hardness)
Correct vertically-averaged hardness using a parameterization of the fracture-induced softening.
array::Staggered1 m_nuH
viscosity times thickness
array::CellType2 m_cell_type
const double m_bc_scaling
scaling used for diagonal matrix elements at Dirichlet BC locations
void adjust_driving_stress(const array::Scalar &ice_thickness, const array::Scalar1 &surface_elevation, const array::CellType1 &cell_type, const array::Scalar1 *no_model_mask, array::Vector &driving_stress) const
const bool m_regional_mode
void compute_average_ice_hardness(const array::Scalar1 &thickness, const array::Array3D &enthalpy, const array::CellType1 &cell_type, array::Staggered &result) const
Computes vertically-averaged ice hardness on the staggered grid.
DiagnosticList diagnostics_impl() const
SSAFDBase(std::shared_ptr< const Grid > g, bool regional_mode)
array::Vector m_rhs
right hand side
void compute_nuH(const array::Scalar1 &ice_thickness, const array::CellType2 &cell_type, const pism::Vector2d *const *velocity, const array::Staggered &hardness, double nuH_regularization, array::Staggered1 &result)
array::Array2D< Work > m_work
void compute_nuH_everywhere(const array::Scalar1 &ice_thickness, const pism::Vector2d *const *velocity, const array::Staggered &hardness, double nuH_regularization, array::Staggered &result)
Compute the product of ice thickness and effective viscosity (on the staggered grid).
void compute_residual(const Inputs &inputs, const array::Vector2 &velocity, array::Vector &result)
const array::Vector & driving_stress() const
virtual std::shared_ptr< array::Array > compute_impl() const
SSAFD_nuH(const SSAFDBase *m)
Reports the nuH (viscosity times thickness) product on the staggered grid.
SSAFD_taud_mag(const SSAFDBase *m)
virtual std::shared_ptr< array::Array > compute_impl() const
Computes the magnitude of the driving shear stress at the base of ice (diagnostically).
std::shared_ptr< array::Array > compute_impl() const
SSAFD_taud(const SSAFDBase *m)
Computes the driving shear stress at the base of ice (diagnostically).
double get_notional_strength() const
Returns strength = (viscosity times thickness).
double get_min_thickness() const
Returns minimum thickness to trigger use of extension.
SSAStrengthExtension * strength_extension
const array::Vector1 & velocity() const
Get the thickness-advective 2D velocity.
virtual DiagnosticList diagnostics_impl() const
double m_e_factor
flow enhancement factor
std::shared_ptr< rheology::FlowLaw > m_flow_law
IceBasalResistancePlasticLaw * m_basal_sliding_law
EnthalpyConverter::Ptr m_EC
array::Vector2 m_velocity
#define PISM_CHK(errcode, name)
#define PISM_ERROR_LOCATION
bool domain_edge(const Grid &grid, int i, int j)
bool icy(int M)
Ice-filled cell (grounded or floating).
bool ice_free_land(int M)
bool ice_free_ocean(int M)
bool grounded(int M)
Grounded cell (grounded ice or ice-free).
bool ice_free(int M)
Ice-free cell (grounded or ocean).
double averaged_hardness(const FlowLaw &ice, double thickness, unsigned int kbelowH, const double *zlevels, const double *enthalpy)
Computes vertical average of B(E, p) ice hardness, namely .
static int weight(bool margin_bc, int M_ij, int M_n, double h_ij, double h_n, int N_ij, int N_n)
static double diff_centered(double L, double, double R)
static bool is_marginal(int i, int j, const array::CellType1 &cell_type, bool ssa_dirichlet_bc)
Checks if a cell is near or at the ice front.
static double diff_uphill(double L, double C, double R)
static double secondInvariant_2D(const Vector2d &U_x, const Vector2d &U_y)
double average_water_column_pressure(double ice_thickness, double bed, double floatation_level, double rho_ice, double rho_water, double g)
std::string printf(const char *format,...)
std::map< std::string, Diagnostic::Ptr > DiagnosticList
Star stencil points (in the map-plane).
static double S(unsigned n)