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"
26 #include "pism/stressbalance/ssa/SSAFD.hh"
27 #include "pism/stressbalance/ssa/SSAFD_diagnostics.hh"
28 #include "pism/util/Grid.hh"
29 #include "pism/util/Mask.hh"
30 #include "pism/util/array/CellType.hh"
31 #include "pism/util/petscwrappers/DM.hh"
32 #include "pism/util/petscwrappers/Vec.hh"
33 #include "pism/util/pism_options.hh"
34 #include "pism/util/pism_utilities.hh"
37 namespace stressbalance {
74 .
long_name(
"old SSA velocity field; used for re-trying with a different epsilon")
78 .
long_name(
"vertically-averaged ice hardness")
82 .
long_name(
"ice thickness times effective viscosity")
86 .
long_name(
"ice thickness times effective viscosity (before an update)")
89 m_work.metadata(0).long_name(
"temporary storage used to compute nuH");
98 ierr = DMSetMatType(*
m_da, MATAIJ);
107 ierr = KSPSetOptionsPrefix(
m_KSP,
"ssafd_");
108 PISM_CHK(ierr,
"KSPSetOptionsPrefix");
112 ierr = KSPSetInitialGuessNonzero(
m_KSP, PETSC_TRUE);
113 PISM_CHK(ierr,
"KSPSetInitialGuessNonzero");
116 ierr = KSPConvergedDefaultSetUIRNorm(
m_KSP);
117 PISM_CHK(ierr,
"KSPConvergedDefaultSetUIRNorm");
126 ierr = KSPSetType(
m_KSP, KSPGMRES);
133 ierr = KSPGetPC(
m_KSP, &pc);
137 ierr = PCSetType(pc, PCBJACOBI);
141 ierr = KSPSetFromOptions(
m_KSP);
142 PISM_CHK(ierr,
"KSPSetFromOptions");
153 ierr = KSPSetType(
m_KSP, KSPGMRES);
160 ierr = KSPSetNormType(
m_KSP, KSP_NORM_UNPRECONDITIONED);
164 ierr = KSPSetPCSide(
m_KSP, PC_RIGHT);
168 ierr = KSPGetPC(
m_KSP, &pc);
172 ierr = PCSetType(pc, PCASM);
180 ierr = PCASMGetSubKSP(pc, NULL, NULL, &sub_ksp);
183 ierr = KSPSetType(*sub_ksp, KSPPREONLY);
187 ierr = KSPGetPC(*sub_ksp, &sub_pc);
190 ierr = PCSetType(sub_pc, PCLU);
195 ierr = KSPSetFromOptions(
m_KSP);
196 PISM_CHK(ierr,
"KSPSetFromOptions");
202 m_log->message(2,
" [using the KSP-based finite difference implementation]\n");
209 if (
m_config->get_flag(
"stress_balance.calving_front_stress_bc")) {
210 m_log->message(2,
" using PISM-PIK calving-front stress boundary condition ...\n");
245 standard_gravity =
m_config->get_number(
"constants.standard_gravity"),
246 rho_ocean =
m_config->get_number(
"constants.sea_water.density"),
251 const Vector2d ice_free_velocity(0.0, 0.0);
253 const bool use_cfbc =
m_config->get_flag(
"stress_balance.calving_front_stress_bc"),
254 flow_line_mode =
m_config->get_flag(
"stress_balance.ssa.fd.flow_line_mode");
257 bool bedrock_boundary =
m_config->get_flag(
"stress_balance.ssa.dirichlet_bc");
269 list.add({ &thickness, &bed, &surface, &
m_mask, &sea_level });
272 if (use_cfbc and (water_column_pressure !=
nullptr)) {
273 list.add(*water_column_pressure);
278 for (
auto p =
m_grid->points(); p; p.next()) {
279 const int i = p.i(), j = p.j();
283 if (flow_line_mode) {
295 double H_ij = thickness(i, j);
310 int W = 0, E = 0,
S = 0, N = 0;
313 if (bedrock_boundary) {
334 double P_ice = 0.5 *
rho_ice * standard_gravity * H_ij, P_water = 0.0;
336 if (water_column_pressure !=
nullptr) {
337 P_water = (*water_column_pressure)(i, j);
340 rho_ocean, standard_gravity);
343 double delta_p = H_ij * (P_ice - P_water);
360 auto b = bed.
star(i, j);
361 double h = surface(i, j);
383 m_b(i, j).u = taud.
u + (E - W) * delta_p / dx;
384 m_b(i, j).v = taud.
v + (N -
S) * delta_p / dy;
410 PetscErrorCode ierr = MatSetValuesStencil(A, 1, &
row, 1, &col, &value, INSERT_VALUES);
411 PISM_CHK(ierr,
"MatSetValuesStencil");
498 const int diag_u = 4;
499 const int diag_v = 13;
501 PetscErrorCode ierr = 0;
513 beta_lateral_margin =
m_config->get_number(
"basal_resistance.beta_lateral_margin"),
514 beta_ice_free_bedrock =
515 m_config->get_number(
"basal_resistance.beta_ice_free_bedrock");
519 bedrock_boundary =
m_config->get_flag(
"stress_balance.ssa.dirichlet_bc"),
520 flow_line_mode =
m_config->get_flag(
"stress_balance.ssa.fd.flow_line_mode"),
521 use_cfbc =
m_config->get_flag(
"stress_balance.calving_front_stress_bc"),
522 replace_zero_diagonal_entries =
523 m_config->get_flag(
"stress_balance.ssa.fd.replace_zero_diagonal_entries");
525 ierr = MatZeroEntries(A);
534 const bool sub_gl =
m_config->get_flag(
"geometry.grounded_cell_fraction");
536 list.add(grounded_fraction);
541 bool lateral_drag_enabled =
m_config->get_flag(
"stress_balance.ssa.fd.lateral_drag.enabled");
542 if (lateral_drag_enabled) {
543 list.add({ &thickness, &bed, &surface });
545 double lateral_drag_viscosity =
546 m_config->get_number(
"stress_balance.ssa.fd.lateral_drag.viscosity");
547 double HminFrozen = 0.0;
552 for (
auto p =
m_grid->points(); p; p.next()) {
553 const int i = p.i(), j = p.j();
570 double c_w =
m_nuH(i - 1, j, 0);
571 double c_e =
m_nuH(i, j, 0);
572 double c_s =
m_nuH(i, j - 1, 1);
573 double c_n =
m_nuH(i, j, 1);
575 if (lateral_drag_enabled) {
581 auto H = thickness.
star(i, j);
582 auto b = bed.star(i, j);
583 double h = surface(i, j);
585 if (H.c > HminFrozen) {
587 c_w = lateral_drag_viscosity * 0.5 * (H.c + H.w);
590 c_e = lateral_drag_viscosity * 0.5 * (H.c + H.e);
593 c_n = lateral_drag_viscosity * 0.5 * (H.c + H.n);
596 c_s = lateral_drag_viscosity * 0.5 * (H.c + H.s);
605 const int n_nonzeros = 18;
606 MatStencil
row, col[n_nonzeros];
619 int N = 1, E = 1,
S = 1, W = 1;
624 int NNW = 1, NNE = 1, SSW = 1, SSE = 1;
625 int WNW = 1, ENE = 1, WSW = 1, ESE = 1;
646 if (bedrock_boundary) {
710 const double dx2 = dx*dx,
dy2 = dy*dy,
d4 = 4*dx*dy,
d2 = 2*dx*dy;
715 -4*c_w*W/
dx2, (c_n*N+c_s*
S)/
dy2+(4*c_e*E+4*c_w*W)/
dx2, -4*c_e*E/
dx2,
717 c_w*W*WNW/
d2+c_n*NNW*N/
d4, (c_n*NNE*N-c_n*NNW*N)/
d4+(c_w*W*N-c_e*E*N)/
d2, -c_e*E*ENE/
d2-c_n*NNE*N/
d4,
718 (c_w*W*WSW-c_w*W*WNW)/
d2+(c_n*W*N-c_s*W*
S)/
d4, (c_n*E*N-c_n*W*N-c_s*E*
S+c_s*W*
S)/
d4+(c_e*E*N-c_w*W*N-c_e*E*
S+c_w*W*
S)/
d2, (c_e*E*ENE-c_e*E*ESE)/
d2+(c_s*E*
S-c_n*E*N)/
d4,
719 -c_w*W*WSW/
d2-c_s*SSW*
S/
d4, (c_s*SSW*
S-c_s*SSE*
S)/
d4+(c_e*E*
S-c_w*W*
S)/
d2, c_e*E*ESE/
d2+c_s*SSE*
S/
d4,
724 c_w*W*WNW/
d4+c_n*NNW*N/
d2, (c_n*NNE*N-c_n*NNW*N)/
d2+(c_w*W*N-c_e*E*N)/
d4, -c_e*E*ENE/
d4-c_n*NNE*N/
d2,
725 (c_w*W*WSW-c_w*W*WNW)/
d4+(c_n*W*N-c_s*W*
S)/
d2, (c_n*E*N-c_n*W*N-c_s*E*
S+c_s*W*
S)/
d2+(c_e*E*N-c_w*W*N-c_e*E*
S+c_w*W*
S)/
d4, (c_e*E*ENE-c_e*E*ESE)/
d4+(c_s*E*
S-c_n*E*N)/
d2,
726 -c_w*W*WSW/
d4-c_s*SSW*
S/
d2, (c_s*SSW*
S-c_s*SSE*
S)/
d2+(c_e*E*
S-c_w*W*
S)/
d4, c_e*E*ESE/
d4+c_s*SSE*
S/
d2,
728 -c_w*W/
dx2, (4*c_n*N+4*c_s*
S)/
dy2+(c_e*E+c_w*W)/
dx2, -c_e*E/
dx2,
767 double beta_u = 0.0, beta_v = 0.0;
768 if (include_basal_shear) {
774 beta = beta_ice_free_bedrock;
778 double scaling = sub_gl ? grounded_fraction(i, j) : 0.0;
783 double scaling = sub_gl ? grounded_fraction(i, j) : 1.0;
801 auto b = bed.star(i, j);
802 double h = surface(i, j);
805 beta_u += beta_lateral_margin;
809 beta_v += beta_lateral_margin;
814 eq1[diag_u] += beta_u;
815 eq2[diag_v] += beta_v;
817 if (flow_line_mode) {
819 for (
int k = 0;
k < n_nonzeros; ++
k) {
826 const double eps = 1e-16;
827 if (fabs(
eq1[diag_u]) < eps) {
828 if (replace_zero_diagonal_entries) {
829 eq1[diag_u] = beta_ice_free_bedrock;
832 "first (X) equation in the SSAFD system:"
833 " zero diagonal entry at a regular (not Dirichlet B.C.)"
834 " location: i = %d, j = %d\n",
838 if (fabs(
eq2[diag_v]) < eps) {
839 if (replace_zero_diagonal_entries) {
840 eq2[diag_v] = beta_ice_free_bedrock;
843 "second (Y) equation in the SSAFD system:"
844 " zero diagonal entry at a regular (not Dirichlet B.C.)"
845 " location: i = %d, j = %d\n",
852 for (
int m = 0; m < n_nonzeros; m++) {
860 ierr = MatSetValuesStencil(A, 1, &
row, n_nonzeros, col,
eq1, INSERT_VALUES);
861 PISM_CHK(ierr,
"MatSetValuesStencil");
865 ierr = MatSetValuesStencil(A, 1, &
row, n_nonzeros, col,
eq2, INSERT_VALUES);
866 PISM_CHK(ierr,
"MatSetValuesStencil");
873 ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);
876 ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);
878 #if (Pism_DEBUG == 1)
879 ierr = MatSetOption(A, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE);
953 for (
unsigned int k = 0;
k < 3; ++
k) {
963 const double underrelax =
964 m_config->get_number(
"stress_balance.ssa.fd.nuH_iter_failure_underrelaxation");
966 1,
" re-trying with effective viscosity under-relaxation (parameter = %.2f) ...\n",
987 if (
m_config->get_flag(
"stress_balance.ssa.fd.extrapolate_at_margins")) {
992 if (
m_config->get_flag(
"stress_balance.ssa.fd.brutal_sliding")) {
993 const double brutal_sliding_scaleFactor =
994 m_config->get_number(
"stress_balance.ssa.fd.brutal_sliding_scale");
1002 double nuH_iter_failure_underrelax) {
1009 picard_manager(inputs, nuH_regularization, nuH_iter_failure_underrelax);
1015 m_log->message(1,
" re-trying using the Additive Schwarz preconditioner...\n");
1021 picard_manager(inputs, nuH_regularization, nuH_iter_failure_underrelax);
1028 picard_manager(inputs, nuH_regularization, nuH_iter_failure_underrelax);
1034 double nuH_iter_failure_underrelax) {
1035 PetscErrorCode ierr;
1036 double nuH_norm, nuH_norm_change;
1039 PetscInt ksp_iterations, ksp_iterations_total = 0, outer_iterations;
1040 KSPConvergedReason reason;
1042 int max_iterations =
1043 static_cast<int>(
m_config->get_number(
"stress_balance.ssa.fd.max_iterations"));
1044 double ssa_relative_tolerance =
1045 m_config->get_number(
"stress_balance.ssa.fd.relative_convergence");
1046 bool verbose =
m_log->get_threshold() >= 2, very_verbose =
m_log->get_threshold() > 2;
1053 bool use_cfbc =
m_config->get_flag(
"stress_balance.calving_front_stress_bc");
1057 nuH_regularization,
m_nuH);
1060 nuH_regularization,
m_nuH);
1065 for (
int k = 0;
k < max_iterations; ++
k) {
1090 ierr = KSPGetConvergedReason(
m_KSP, &reason);
1091 PISM_CHK(ierr,
"KSPGetConvergedReason");
1095 m_log->message(1,
"PISM WARNING: KSPSolve() reports 'diverged'; reason = %d = '%s'\n",
1096 reason, KSPConvergedReasons[reason]);
1102 throw KSPFailure(KSPConvergedReasons[reason]);
1106 ierr = KSPGetIterationNumber(
m_KSP, &ksp_iterations);
1107 PISM_CHK(ierr,
"KSPGetIterationNumber");
1109 ksp_iterations_total += ksp_iterations;
1117 auto max_speed =
m_config->get_number(
"stress_balance.ssa.fd.max_speed",
"m second-1");
1118 int high_speed_counter = 0;
1122 for (
auto p =
m_grid->points(); p; p.next()) {
1123 const int i = p.i(), j = p.j();
1127 if (speed > max_speed) {
1129 high_speed_counter += 1;
1135 if (high_speed_counter > 0) {
1136 m_log->message(2,
" SSA speed was capped at %d locations\n", high_speed_counter);
1148 nuH_regularization,
m_nuH);
1151 nuH_regularization,
m_nuH);
1154 if (nuH_iter_failure_underrelax != 1.0) {
1164 nuH_norm_change / nuH_norm);
1173 outer_iterations =
k + 1;
1175 if (nuH_norm == 0 || nuH_norm_change / nuH_norm < ssa_relative_tolerance) {
1185 "with nuH_regularization=%8.2e.",
1186 max_iterations, nuH_regularization));
1192 pism::printf(
"... =%5d outer iterations, ~%3.1f KSP iterations each\n",
1193 (
int)outer_iterations, ((
double)ksp_iterations_total) / outer_iterations);
1195 }
else if (verbose) {
1198 pism::printf(
"%5d outer iterations, ~%3.1f KSP iterations each\n", (
int)outer_iterations,
1199 ((
double)ksp_iterations_total) / outer_iterations);
1212 const double DEFAULT_EPSILON_MULTIPLIER_SSA = 4.0;
1213 double nuH_regularization =
m_config->get_number(
"stress_balance.ssa.epsilon");
1214 unsigned int k = 0, max_tries = 5;
1216 if (nuH_regularization <= 0.0) {
1217 throw PicardFailure(
"will not attempt over-regularization of nuH\n"
1218 "because nuH_regularization == 0.0.");
1221 while (
k < max_tries) {
1223 m_log->message(1,
" re-trying with nuH_regularization multiplied by %8.2f...\n",
1224 DEFAULT_EPSILON_MULTIPLIER_SSA);
1226 nuH_regularization *= DEFAULT_EPSILON_MULTIPLIER_SSA;
1236 if (
k == max_tries) {
1237 throw PicardFailure(
"exceeded the max. number of nuH over-regularization attempts");
1258 const double area =
m_grid->cell_area();
1259 const NormType MY_NORM = NORM_1;
1266 nuChange[0] *= area;
1267 nuChange[1] *= area;
1271 norm_change = sqrt(PetscSqr(nuChange[0]) + PetscSqr(nuChange[1]));
1272 norm = sqrt(PetscSqr(nuNorm[0]) + PetscSqr(nuNorm[1]));
1281 const double *E_ij = NULL, *E_offset = NULL;
1284 std::vector<double> E(Mz);
1290 for (
auto p =
m_grid->points(); p; p.next()) {
1291 const int i = p.i(), j = p.j();
1294 for (
int o = 0; o < 2; o++) {
1295 const int oi = 1 - o, oj = o;
1299 H = 0.5 * (thickness(i, j) + thickness(i + oi, j + oj));
1301 H = thickness(i, j);
1303 H = thickness(i + oi, j + oj);
1311 E_offset = enthalpy.
get_column(i + oi, j + oj);
1313 for (
unsigned int k = 0;
k < Mz; ++
k) {
1314 E[
k] = 0.5 * (E_ij[
k] + E_offset[
k]);
1318 m_grid->z().data(), E.data());
1364 if (fracture_density ==
nullptr) {
1368 const double epsilon =
m_config->get_number(
"fracture_density.softening_lower_limit"),
1373 for (
auto p =
m_grid->points(); p; p.next()) {
1374 const int i = p.i(), j = p.j();
1376 for (
int o = 0; o < 2; o++) {
1377 const int oi = 1 - o, oj = o;
1381 phi = 0.5 * ((*fracture_density)(i, j) + (*fracture_density)(i + oi, j + oj)),
1383 softening = pow((1.0 - (1.0 - epsilon) *
phi), -n_glen);
1385 m_hardness(i, j, o) *= pow(softening, -1.0 / n_glen);
1446 nu_enhancement_scaling = 1.0 / pow(
m_e_factor, 1.0 / n_glen);
1450 for (
int o = 0; o < 2; ++o) {
1451 const int oi = 1 - o, oj = o;
1452 for (
auto p =
m_grid->points(); p; p.next()) {
1453 const int i = p.i(), j = p.j();
1455 const double H = 0.5 * (ice_thickness(i, j) + ice_thickness(i + oi, j + oj));
1457 if (H < strength_extension->get_min_thickness()) {
1462 double u_x, u_y, v_x, v_y;
1465 u_x = (uv(i + 1, j).u - uv(i, j).u) / dx;
1467 (uv(i, j + 1).u + uv(i + 1, j + 1).u - uv(i, j - 1).u - uv(i + 1, j - 1).u) / (4 * dy);
1468 v_x = (uv(i + 1, j).v - uv(i, j).v) / dx;
1470 (uv(i, j + 1).v + uv(i + 1, j + 1).v - uv(i, j - 1).v - uv(i + 1, j - 1).v) / (4 * dy);
1473 (uv(i + 1, j).u + uv(i + 1, j + 1).u - uv(i - 1, j).u - uv(i - 1, j + 1).u) / (4 * dx);
1474 u_y = (uv(i, j + 1).u - uv(i, j).u) / dy;
1476 (uv(i + 1, j).v + uv(i + 1, j + 1).v - uv(i - 1, j).v - uv(i - 1, j + 1).v) / (4 * dx);
1477 v_y = (uv(i, j + 1).v - uv(i, j).v) / dy;
1481 m_flow_law->effective_viscosity(hardness(i, j, o),
1484 result(i, j, o) = nu * H;
1487 result(i, j, o) *= nu_enhancement_scaling;
1490 result(i, j, o) += nuH_regularization;
1514 const auto &thickness = ice_thickness;
1519 nu_enhancement_scaling = 1.0 / pow(
m_e_factor, 1.0 / n_glen);
1527 assert(
m_work.stencil_width() >= 1);
1529 for (
auto p =
m_grid->points(1); p; p.next()) {
1530 const int i = p.i(), j = p.j();
1534 if (mask.
icy(i, j) && mask.
icy(i + 1, j)) {
1535 m_work(i, j).u_x = (uv(i + 1, j).u - uv(i, j).u) / dx;
1536 m_work(i, j).v_x = (uv(i + 1, j).v - uv(i, j).v) / dx;
1547 if (mask.
icy(i, j) && mask.
icy(i, j + 1)) {
1548 m_work(i, j).u_y = (uv(i, j + 1).u - uv(i, j).u) / dy;
1549 m_work(i, j).v_y = (uv(i, j + 1).v - uv(i, j).v) / dy;
1559 list.add({ &result, &hardness, &thickness });
1561 for (
auto p =
m_grid->points(); p; p.next()) {
1562 const int i = p.i(), j = p.j();
1564 double u_x, u_y, v_x, v_y, H, nu, W;
1567 if (mask.
icy(i, j) && mask.
icy(i + 1, j)) {
1568 H = 0.5 * (thickness(i, j) + thickness(i + 1, j));
1569 }
else if (mask.
icy(i, j)) {
1570 H = thickness(i, j);
1572 H = thickness(i + 1, j);
1593 m_flow_law->effective_viscosity(hardness(i, j, 0),
1595 result(i, j, 0) = nu * H;
1603 if (mask.
icy(i, j) && mask.
icy(i, j + 1)) {
1604 H = 0.5 * (thickness(i, j) + thickness(i, j + 1));
1605 }
else if (mask.
icy(i, j)) {
1606 H = thickness(i, j);
1608 H = thickness(i, j + 1);
1629 m_flow_law->effective_viscosity(hardness(i, j, 1),
1631 result(i, j, 1) = nu * H;
1638 for (
int o = 0; o < 2; ++o) {
1640 result(i, j, o) *= nu_enhancement_scaling;
1643 result(i, j, o) += nuH_regularization;
1660 .
long_name(
"log10 of (viscosity * thickness)")
1665 for (
auto p =
m_grid->points(); p; p.next()) {
1666 const int i = p.i(), j = p.j();
1668 double avg_nuH = 0.5 * (
m_nuH(i,j,0) +
m_nuH(i,j,1));
1669 if (avg_nuH > 1.0e14) {
1670 tmp(i,j) = log10(avg_nuH);
1706 if (ssa_dirichlet_bc) {
1720 PetscErrorCode ierr;
1723 std::string filename =
"SSAFD_" + namepart +
".petsc";
1725 " writing linear system to PETSc binary file %s ...\n", filename.c_str());
1728 ierr = PetscViewerBinaryOpen(
m_grid->com, filename.c_str(), FILE_MODE_WRITE,
1730 PISM_CHK(ierr,
"PetscViewerBinaryOpen");
1732 ierr = MatView(
m_A, viewer);
1735 ierr = VecView(
m_b.
vec(), viewer);
1742 .long_name(
"ice thickness times effective viscosity, i-offset")
1744 .output_units(
"kPa s m");
1746 .long_name(
"ice thickness times effective viscosity, j-offset")
1748 .output_units(
"kPa s m");
1752 auto result = allocate<array::Staggered>(
"nuH");
1754 result->copy_from(
model->integrated_viscosity());
std::shared_ptr< const Grid > grid() const
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 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
array::Scalar1 sea_level_elevation
array::Scalar cell_grounded_fraction
array::Scalar2 ice_surface_elevation
array::CellType2 cell_type
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.
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 scale(double alpha)
Result: v <- v * alpha. Calls VecScale.
void view(std::vector< std::shared_ptr< petsc::Viewer > > viewers) const
View a 2D vector field using existing PETSc viewers.
void set(double c)
Result: v[j] <- c for all j.
void add(double alpha, const Array &x)
Result: v <- v + alpha * x. Calls VecAXPY.
std::vector< double > norm(int n) const
Computes the norm of all the components of an Array.
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 icy(int i, int j) const
int as_int(int i, int j) const
void copy_from(const array::Staggered &input)
A class for storing and accessing internal staggered-grid 2D fields. Uses dof=2 storage....
KSPFailure(const char *reason)
PicardFailure(const std::string &message)
virtual std::shared_ptr< array::Array > compute_impl() const
SSAFD_nuH(const SSAFD *m)
Reports the nuH (viscosity times thickness) product on the staggered grid.
virtual void compute_nuH_norm(double &norm, double &norm_change)
Compute the norm of nu H and the change in nu H.
SSAFD(std::shared_ptr< const Grid > g)
const array::Staggered & integrated_viscosity() const
virtual void init_impl()
Initialize a generic regular-grid SSA solver.
virtual void picard_strategy_regularization(const Inputs &inputs)
Old SSAFD recovery strategy: increase the SSA regularization parameter.
array::Array2D< Work > m_work
virtual void fracture_induced_softening(const array::Scalar *fracture_density)
Correct vertically-averaged hardness using a parameterization of the fracture-induced softening.
std::shared_ptr< petsc::Viewer > m_nuh_viewer
array::Staggered m_hardness
array::Vector1 m_velocity_old
virtual void update_nuH_viewers()
Update the nuH viewer, which shows log10(nu H).
virtual void compute_nuH_staggered_cfbc(const array::Scalar1 &ice_thickness, const array::CellType2 &mask, const array::Vector1 &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.
virtual void compute_nuH_staggered(const array::Scalar1 &ice_thickness, const array::Vector1 &velocity, const array::Staggered &hardness, double nuH_regularization, array::Staggered &result)
Compute the product of ice thickness and effective viscosity (on the staggered grid).
virtual void solve(const Inputs &inputs)
Compute the vertically-averaged horizontal velocity from the shallow shelf approximation.
virtual void write_system_petsc(const std::string &namepart)
virtual DiagnosticList diagnostics_impl() const
unsigned int m_default_pc_failure_max_count
virtual void assemble_matrix(const Inputs &inputs, bool include_basal_shear, Mat A)
Assemble the left-hand side matrix for the KSP-based, Picard iteration, and finite difference impleme...
virtual void pc_setup_asm()
virtual bool is_marginal(int i, int j, bool ssa_dirichlet_bc)
Checks if a cell is near or at the ice front.
virtual void compute_hardav_staggered(const Inputs &inputs)
Computes vertically-averaged ice hardness on the staggered grid.
virtual void picard_iteration(const Inputs &inputs, double nuH_regularization, double nuH_iter_failure_underrelax)
virtual void picard_manager(const Inputs &inputs, double nuH_regularization, double nuH_iter_failure_underrelax)
Manages the Picard iteration loop.
virtual void pc_setup_bjacobi()
unsigned int m_default_pc_failure_count
array::Staggered1 m_nuH_old
virtual void assemble_rhs(const Inputs &inputs)
Computes the right-hand side ("rhs") of the linear problem for the Picard iteration and finite-differ...
PISM's SSA solver: the finite difference implementation.
double get_notional_strength() const
Returns strength = (viscosity times thickness).
double get_min_thickness() const
Returns minimum thickness to trigger use of extension.
virtual DiagnosticList diagnostics_impl() const
virtual 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, array::Vector &result) const
Compute the gravitational driving stress.
array::Vector m_velocity_global
void extrapolate_velocity(const array::CellType1 &cell_type, array::Vector1 &velocity) const
SSAStrengthExtension * strength_extension
std::shared_ptr< petsc::DM > m_da
virtual void init_impl()
Initialize a generic regular-grid SSA solver.
const array::Vector1 & velocity() const
Get the thickness-advective 2D velocity.
double m_e_factor
flow enhancement factor
std::shared_ptr< rheology::FlowLaw > m_flow_law
IceBasalResistancePlasticLaw * m_basal_sliding_law
array::Vector2 m_velocity
#define PISM_CHK(errcode, name)
#define PISM_ERROR_LOCATION
static Vector3 row(const double A[3][3], size_t k)
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).
bool Bool(const std::string &option, const std::string &description)
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 .
SSA * SSAFDFactory(std::shared_ptr< const Grid > g)
Constructs a new SSAFD.
static void set_diagonal_matrix_entry(Mat A, int i, int j, int component, double value)
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
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)
static double S(unsigned n)