24 #include "pism/util/EnthalpyConverter.hh"
25 #include "pism/rheology/FlowLawFactory.hh"
26 #include "pism/rheology/grain_size_vostok.hh"
27 #include "pism/util/IceGrid.hh"
28 #include "pism/util/Mask.hh"
29 #include "pism/util/Vars.hh"
30 #include "pism/util/error_handling.hh"
31 #include "pism/util/pism_utilities.hh"
32 #include "pism/util/Profiling.hh"
33 #include "pism/util/IceModelVec2CellType.hh"
34 #include "pism/geometry/Geometry.hh"
35 #include "pism/stressbalance/StressBalance.hh"
37 #include "pism/util/Time.hh"
38 #include "pism/util/Context.hh"
41 namespace stressbalance {
45 m_stencil_width(m_config->get_number(
"grid.max_stencil_width")),
46 m_work_2d_0(m_grid,
"work_vector_2d_0",
WITH_GHOSTS, m_stencil_width),
47 m_work_2d_1(m_grid,
"work_vector_2d_1",
WITH_GHOSTS, m_stencil_width),
51 m_delta_0(m_grid,
"delta_0",
WITH_GHOSTS, m_grid->z()),
52 m_delta_1(m_grid,
"delta_1",
WITH_GHOSTS, m_grid->z()),
53 m_work_3d_0(m_grid,
"work_3d_0",
WITH_GHOSTS, m_grid->z()),
54 m_work_3d_1(m_grid,
"work_3d_1",
WITH_GHOSTS, m_grid->z())
69 const bool compute_grain_size_using_age =
m_config->get_flag(
"stress_balance.sia.grain_size_age_coupling");
70 const bool age_model_enabled =
m_config->get_flag(
"age.enabled");
71 const bool e_age_coupling =
m_config->get_flag(
"stress_balance.sia.e_age_coupling");
73 if (compute_grain_size_using_age) {
76 "but sia.grain_size_age_coupling was set",
80 if (not age_model_enabled) {
82 "age is needed for grain-size-based flow law %s",
87 if (e_age_coupling and not age_model_enabled) {
89 "age is needed for age-dependent flow enhancement");
107 "* Initializing the SIA stress balance modifier...\n");
109 " [using the %s flow law]\n",
m_flow_law->name().c_str());
114 if (
m_config->get_flag(
"stress_balance.sia.e_age_coupling")) {
116 " using age-dependent enhancement factor:\n"
117 " e=%f for ice accumulated during interglacial periods\n"
118 " e=%f for ice accumulated during glacial periods\n",
134 profiling.
begin(
"sia.bed_smoother");
136 profiling.
end(
"sia.bed_smoother");
139 profiling.
begin(
"sia.gradient");
141 profiling.
end(
"sia.gradient");
143 profiling.
begin(
"sia.flux");
150 profiling.
end(
"sia.flux");
153 profiling.
begin(
"sia.3d_velocity");
156 profiling.
end(
"sia.3d_velocity");
200 const std::string method =
m_config->get_string(
"stress_balance.sia.surface_gradient_method");
202 if (method ==
"eta") {
208 }
else if (method ==
"haseloff") {
214 }
else if (method ==
"mahaffy") {
221 "value of sia.surface_gradient_method, option '-gradient %s', is not valid",
231 etapow = (2.0 *
n + 2.0)/
n,
232 invpow = 1.0 / etapow,
233 dinvpow = (-
n - 2.0) / (2.0 *
n + 2.0);
245 const int i = p.i(), j = p.j();
247 eta(i, j) = pow(ice_thickness(i, j), etapow);
259 const int i = p.i(), j = p.j();
261 auto b = bed_elevation.
box(i, j);
262 auto e = eta.
box(i, j);
266 double mean_eta = 0.5 * (e.e + e.ij);
267 if (mean_eta > 0.0) {
268 double factor = invpow * pow(mean_eta, dinvpow);
269 h_x(i, j, 0) = factor * (e.e - e.ij) / dx;
270 h_y(i, j, 0) = factor * (e.ne + e.n - e.se - e.s) / (4.0 * dy);
276 h_x(i, j, 0) += (b.e - b.ij) / dx;
277 h_y(i, j, 0) += (b.ne + b.n - b.se - b.s) / (4.0 * dy);
282 double mean_eta = 0.5 * (e.n + e.ij);
283 if (mean_eta > 0.0) {
284 double factor = invpow * pow(mean_eta, dinvpow);
285 h_x(i, j, 1) = factor * (e.ne + e.e - e.nw - e.w) / (4.0 * dx);
286 h_y(i, j, 1) = factor * (e.n - e.ij) / dy;
292 h_x(i, j, 1) += (b.ne + b.e - b.nw - b.w) / (4.0 * dx);
293 h_y(i, j, 1) += (b.n - b.ij) / dy;
316 const int i = p.i(), j = p.j();
319 h_x(i, j, 0) = (h(i + 1, j) - h(i, j)) / dx;
320 h_y(i, j, 0) = (+ h(i + 1, j + 1) + h(i, j + 1)
321 - h(i + 1, j - 1) - h(i, j - 1)) / (4.0*dy);
323 h_y(i, j, 1) = (h(i, j + 1) - h(i, j)) / dy;
324 h_x(i, j, 1) = (+ h(i + 1, j + 1) + h(i + 1, j)
325 - h(i - 1, j + 1) - h(i - 1, j)) / (4.0*dx);
383 &h = ice_surface_elevation;
397 assert(w_j.stencil_width() >= 1);
400 const int i = p.i(), j = p.j();
409 }
else if ((mask.
icy(i,j) && mask.
ice_free(i+1,j) && h(i+1,j) > h(i,j)) ||
410 (mask.
ice_free(i,j) && mask.
icy(i+1,j) && h(i,j) > h(i+1,j))) {
416 h_x(i,j,0) = (h(i+1,j) - h(i,j)) / dx;
428 }
else if ((mask.
icy(i,j) && mask.
ice_free(i,j+1) && h(i,j+1) > h(i,j)) ||
429 (mask.
ice_free(i,j) && mask.
icy(i,j+1) && h(i,j) > h(i,j+1))) {
435 h_y(i,j,1) = (h(i,j+1) - h(i,j)) / dy;
442 const int i = p.i(), j = p.j();
447 double W = w_i(i,j) + w_i(i-1,j) + w_i(i-1,j+1) + w_i(i,j+1);
449 h_x(i,j,1) = 1.0/W * (h_x(i,j,0) + h_x(i-1,j,0) + h_x(i-1,j+1,0) + h_x(i,j+1,0));
455 double W = w_i(i,j) + w_i(i-1,j);
457 h_x(i,j,1) = 1.0/W * (h_x(i,j,0) + h_x(i-1,j,0));
462 double W = w_i(i,j+1) + w_i(i-1,j+1);
464 h_x(i,j,1) = 1.0/W * (h_x(i-1,j+1,0) + h_x(i,j+1,0));
475 double W = w_j(i,j) + w_j(i,j-1) + w_j(i+1,j-1) + w_j(i+1,j);
477 h_y(i,j,0) = 1.0/W * (h_y(i,j,1) + h_y(i,j-1,1) + h_y(i+1,j-1,1) + h_y(i+1,j,1));
483 double W = w_j(i,j) + w_j(i,j-1);
485 h_y(i,j,0) = 1.0/W * (h_y(i,j,1) + h_y(i,j-1,1));
490 double W = w_j(i+1,j-1) + w_j(i+1,j);
492 h_y(i,j,0) = 1.0/W * (h_y(i+1,j-1,1) + h_y(i+1,j,1));
567 current_time =
m_grid->ctx()->time()->current(),
568 D_limit =
m_config->get_number(
"stress_balance.sia.max_diffusivity");
571 compute_grain_size_using_age =
m_config->get_flag(
"stress_balance.sia.grain_size_age_coupling"),
572 e_age_coupling =
m_config->get_flag(
"stress_balance.sia.e_age_coupling"),
573 limit_diffusivity =
m_config->get_flag(
"stress_balance.sia.limit_diffusivity"),
574 use_age = compute_grain_size_using_age or e_age_coupling;
593 list.add({delta[0], delta[1]});
598 assert(theta.stencil_width() >= 2);
605 const std::vector<double> &z =
m_grid->z();
611 std::vector<double> depth(Mz), stress(Mz), pressure(Mz), E(Mz), flow(Mz);
612 std::vector<double> delta_ij(Mz);
613 std::vector<double> A(Mz), ice_grain_size(Mz,
m_config->get_number(
"constants.ice.grain_size",
"m"));
617 int high_diffusivity_counter = 0;
618 for (
int o=0; o<2; o++) {
622 const int i = p.i(), j = p.j();
626 const int oi = 1 - o, oj = o;
629 thk = 0.5 * (thk_smooth(i, j) + thk_smooth(i+oi, j+oj));
633 result(i, j, o) = 0.0;
640 const int ks =
m_grid->kBelowHeight(thk);
642 for (
int k = 0;
k <= ks; ++
k) {
643 depth[
k] = thk - z[
k];
648 m_EC->pressure(depth, ks, pressure);
655 for (
int k = 0;
k <= ks; ++
k) {
656 A[
k] = 0.5 * (age_ij[
k] + age_offset[
k]);
659 if (compute_grain_size_using_age) {
660 for (
int k = 0;
k <= ks; ++
k) {
666 if (e_age_coupling) {
667 for (
int k = 0;
k <= ks; ++
k) {
668 const double accumulation_time = current_time - A[
k];
682 for (
int k = 0;
k <= ks; ++
k) {
683 E[
k] = 0.5 * (E_ij[
k] + E_offset[
k]);
687 const double alpha = sqrt(PetscSqr(h_x(i, j, o)) + PetscSqr(h_y(i, j, o)));
688 for (
int k = 0;
k <= ks; ++
k) {
689 stress[
k] = alpha * pressure[
k];
692 m_flow_law->flow_n(&stress[0], &E[0], &pressure[0], &ice_grain_size[0], ks + 1,
695 const double theta_local = 0.5 * (theta(i, j) + theta(i+oi, j+oj));
696 for (
int k = 0;
k <= ks; ++
k) {
697 delta_ij[
k] = e_factor[
k] * theta_local * 2.0 * pressure[
k] * flow[
k];
702 for (
int k = 1;
k <= ks; ++
k) {
704 const double dz = z[
k] - z[
k-1];
705 D += 0.5 * dz * ((depth[
k] + dz) * delta_ij[
k-1] + depth[
k] * delta_ij[
k]);
708 const double dz = thk - z[ks];
709 D += 0.5 * dz * dz * delta_ij[ks];
721 if ((i < 0 or i >= (
int)Mx - 1) and
725 if ((j < 0 or j >= (
int)My - 1) and
731 if (limit_diffusivity and
D >= D_limit) {
733 high_diffusivity_counter += 1;
743 for (
unsigned int k = ks + 1;
k < Mz; ++
k) {
757 high_diffusivity_counter =
GlobalSum(
m_grid->com, high_diffusivity_counter);
764 "Maximum diffusivity of SIA flow (%f m2/s) is too high.\n"
765 "This probably means that the bed elevation or the ice thickness is "
767 "Increase stress_balance.sia.max_diffusivity to suppress this message.",
m_D_max);
771 if (high_diffusivity_counter > 0) {
776 m_log->message(2,
" SIA diffusivity was capped at %.2f m2/s at %d locations.\n",
777 D_limit, high_diffusivity_counter);
787 for (
int o = 0; o < 2; o++) {
791 const int i = p.i(), j = p.j();
793 const double slope = (o == 0) ? h_x(i, j, o) : h_y(i, j, o);
832 assert(
I[0]->stencil_width() >= 1);
833 assert(
I[1]->stencil_width() >= 1);
834 assert(delta[0]->stencil_width() >= 1);
835 assert(delta[1]->stencil_width() >= 1);
838 const unsigned int Mz =
m_grid->Mz();
840 std::vector<double> dz(Mz);
841 for (
unsigned int k = 1;
k < Mz; ++
k) {
845 for (
int o = 0; o < 2; ++o) {
849 const int i = p.i(), j = p.j();
851 const int oi = 1 - o, oj = o;
853 thk = 0.5 * (thk_smooth(i, j) + thk_smooth(i + oi, j + oj));
855 const double *delta_ij = delta[o]->
get_column(i, j);
856 double *I_ij =
I[o]->get_column(i, j);
858 const unsigned int ks =
m_grid->kBelowHeight(thk);
862 double I_current = 0.0;
863 for (
unsigned int k = 1;
k <= ks; ++
k) {
865 I_current += 0.5 * dz[
k] * (delta_ij[
k - 1] + delta_ij[
k]);
870 for (
unsigned int k = ks + 1;
k < Mz; ++
k) {
911 const unsigned int Mz =
m_grid->Mz();
914 const int i = p.i(), j = p.j();
917 *I_e =
I[0]->get_column(i, j),
918 *I_w =
I[0]->get_column(i - 1, j),
919 *I_n =
I[1]->get_column(i, j),
920 *I_s =
I[1]->get_column(i, j - 1);
924 h_x_w = h_x(i - 1, j, 0),
925 h_x_e = h_x(i, j, 0),
926 h_x_n = h_x(i, j, 1),
927 h_x_s = h_x(i, j - 1, 1);
930 h_y_w = h_y(i - 1, j, 0),
931 h_y_e = h_y(i, j, 0),
932 h_y_n = h_y(i, j, 1),
933 h_y_s = h_y(i, j - 1, 1);
936 sliding_velocity_u = sliding_velocity(i, j).u,
937 sliding_velocity_v = sliding_velocity(i, j).v;
944 for (
unsigned int k = 0;
k < Mz; ++
k) {
945 u_ij[
k] = sliding_velocity_u - 0.25 * (I_e[
k] * h_x_e + I_w[
k] * h_x_w +
946 I_n[
k] * h_x_n + I_s[
k] * h_x_s);
948 for (
unsigned int k = 0;
k < Mz; ++
k) {
949 v_ij[
k] = sliding_velocity_v - 0.25 * (I_e[
k] * h_y_e + I_w[
k] * h_y_w +
950 I_n[
k] * h_y_n + I_s[
k] * h_y_s);
Makes sure that we call begin_access() and end_access() for all accessed IceModelVecs.
const units::System::Ptr m_sys
unit system used by this component
const Config::ConstPtr m_config
configuration database used by this component
const Logger::ConstPtr m_log
logger (for easy access)
const IceGrid::ConstPtr m_grid
grid used by this component
IceModelVec2S ice_surface_elevation
IceModelVec2CellType cell_type
IceModelVec2S bed_elevation
IceModelVec2S ice_thickness
std::shared_ptr< const IceGrid > ConstPtr
bool icy(int i, int j) const
bool ice_free_ocean(int i, int j) const
bool floating_ice(int i, int j) const
bool ice_free(int i, int j) const
"Cell type" mask. Adds convenience methods to IceModelVec2Int.
stencils::Box< double > box(int i, int j) const
A class for storing and accessing internal staggered-grid 2D fields. Uses dof=2 storage....
double * get_column(int i, int j)
void set_column(int i, int j, double c)
Set all values of scalar quantity to given a single value in a particular column.
A virtual class collecting methods common to ice and bedrock 3D fields.
void update_ghosts()
Updates ghost points.
unsigned int stencil_width() const
Get the stencil width of the current IceModelVec. Returns 0 if ghosts are not available.
void set(double c)
Result: v[j] <- c for all j.
void failed()
Indicates a failure of a parallel section.
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
std::shared_ptr< FlowLaw > create()
A relationship between the age of the ice and the grain size from the Vostok core.
void preprocess_bed(const IceModelVec2S &topg)
void theta(const IceModelVec2S &usurf, IceModelVec2S &result) const
void smoothed_thk(const IceModelVec2S &usurf, const IceModelVec2S &thk, const IceModelVec2CellType &mask, IceModelVec2S &thksmooth) const
Computes a smoothed thickness map.
PISM bed smoother, plus bed roughness parameterization, based on Schoof (2003).
const IceModelVec2Stag & surface_gradient_x() const
virtual void compute_surface_gradient(const Inputs &inputs, IceModelVec2Stag &h_x, IceModelVec2Stag &h_y)
Compute the ice surface gradient for the SIA.
virtual void surface_gradient_mahaffy(const IceModelVec2S &ice_surface_elevation, IceModelVec2Stag &h_x, IceModelVec2Stag &h_y)
Compute the ice surface gradient using the Mary Anne Mahaffy method; see [Mahaffy].
virtual void compute_3d_horizontal_velocity(const Geometry &geometry, const IceModelVec2Stag &h_x, const IceModelVec2Stag &h_y, const IceModelVec2V &vel_input, IceModelVec3 &u_out, IceModelVec3 &v_out)
Compute horizontal components of the SIA velocity (in 3D).
const IceModelVec2Stag & diffusivity() const
const unsigned int m_stencil_width
virtual void update(const IceModelVec2V &sliding_velocity, const Inputs &inputs, bool full_update)
Do the update; if full_update == false skip the update of 3D velocities and strain heating.
bool interglacial(double accumulation_time) const
Determine if accumulation_time corresponds to an interglacial period.
virtual void surface_gradient_eta(const IceModelVec2S &ice_thickness, const IceModelVec2S &bed_elevation, IceModelVec2Stag &h_x, IceModelVec2Stag &h_y)
Compute the ice surface gradient using the eta-transformation.
IceModelVec2S m_work_2d_1
double m_seconds_per_year
const BedSmoother & bed_smoother() const
IceModelVec2Stag m_h_x
temporary storage for the surface gradient and the diffusivity
virtual void surface_gradient_haseloff(const IceModelVec2S &ice_surface_elevation, const IceModelVec2CellType &cell_type, IceModelVec2Stag &h_x, IceModelVec2Stag &h_y)
Compute the ice surface gradient using a modification of Marianne Haseloff's approach.
double m_e_factor_interglacial
BedSmoother * m_bed_smoother
IceModelVec2S m_work_2d_0
temporary storage for eta, theta and the smoothed thickness
virtual void init()
Initialize the SIA module.
virtual void compute_diffusivity(bool full_update, const Geometry &geometry, const IceModelVec3 *enthalpy, const IceModelVec3 *age, const IceModelVec2Stag &h_x, const IceModelVec2Stag &h_y, IceModelVec2Stag &result)
Compute the SIA diffusivity. If full_update, also store delta on the staggered grid.
SIAFD(IceGrid::ConstPtr g)
IceModelVec3 m_work_3d_0
temporary storage used to store I and strain_heating on the staggered grid
virtual void compute_I(const Geometry &geometry)
Compute I.
IceModelVec3 m_delta_0
temporary storage for delta on the staggered grid
virtual void compute_diffusive_flux(const IceModelVec2Stag &h_x, const IceModelVec2Stag &h_y, const IceModelVec2Stag &diffusivity, IceModelVec2Stag &result)
const IceModelVec2Stag & surface_gradient_y() const
IceModelVec2Stag m_diffusive_flux
EnthalpyConverter::Ptr m_EC
std::shared_ptr< rheology::FlowLaw > m_flow_law
Shallow stress balance modifier (such as the non-sliding SIA).
#define PISM_ERROR_LOCATION
bool FlowLawUsesGrainSize(const FlowLaw &flow_law)
double convert(System::Ptr system, double input, const std::string &spec1, const std::string &spec2)
Convert a quantity from unit1 to unit2.
double max(const IceModelVec2S &input)
Finds maximum over all the values in an IceModelVec2S object. Ignores ghosts.
void GlobalMax(MPI_Comm comm, double *local, double *result, int count)
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)