20#include "pism/stressbalance/StressBalance.hh"
21#include "pism/geometry/Geometry.hh"
22#include "pism/rheology/FlowLaw.hh"
23#include "pism/stressbalance/SSB_Modifier.hh"
24#include "pism/stressbalance/ShallowStressBalance.hh"
25#include "pism/util/Config.hh"
26#include "pism/util/Context.hh"
27#include "pism/util/EnthalpyConverter.hh"
28#include "pism/util/Grid.hh"
29#include "pism/util/Mask.hh"
30#include "pism/util/Profiling.hh"
31#include "pism/util/Time.hh"
32#include "pism/util/array/CellType.hh"
33#include "pism/util/error_handling.hh"
34#include "pism/util/io/SynchronousOutputWriter.hh"
35#include "pism/util/io/io_helpers.hh"
38namespace stressbalance {
69 auto ctx = grid->ctx();
70 auto config = ctx->config();
73 auto writer = std::make_shared<SynchronousOutputWriter>(ctx->com(), *config);
74 writer->initialize({},
true);
80 auto time = ctx->time();
95 for (
const auto * vec : geom) {
96 for (
const auto &var : vec->all_metadata()) {
101 for (
const auto * vec : geom) {
117 for (
const auto * vec : optional) {
118 for (
const auto &var : vec->all_metadata()) {
123 for (
const auto * vec : optional) {
129 std::shared_ptr<ShallowStressBalance> sb,
130 std::shared_ptr<SSB_Modifier> ssb_mod)
132 m_w(m_grid,
"wvel_rel", array::WITHOUT_GHOSTS, m_grid->z()),
133 m_strain_heating(m_grid,
"strain_heating", array::WITHOUT_GHOSTS, m_grid->z()),
134 m_shallow_stress_balance(sb),
135 m_modifier(ssb_mod) {
138 .
long_name(
"vertical velocity of ice, relative to base of ice directly below")
144 .
long_name(
"rate of strain heating in ice (dissipation heating)")
167 inputs, full_update);
276 const bool use_upstream_fd =
m_config->get_string(
"stress_balance.vertical_velocity_approximation") ==
"upstream";
280 if (basal_melt_rate) {
281 list.
add(*basal_melt_rate);
284 const std::vector<double> &z =
m_grid->z();
285 const unsigned int Mz =
m_grid->Mz();
291 std::vector<double> u_x_plus_v_y(Mz);
293 for (
auto p :
m_grid->points()) {
294 const int i = p.i(), j = p.j();
323 if (use_upstream_fd) {
325 uw = 0.5 * (u_w[0] + u_ij[0]),
326 ue = 0.5 * (u_ij[0] + u_e[0]);
328 if (uw > 0.0 and ue >= 0.0) {
331 }
else if (uw <= 0.0 and ue < 0.0) {
347 if (east + west > 0) {
348 D_x = 1.0 / (dx * (east + west));
358 if (use_upstream_fd) {
360 vs = 0.5 * (v_s[0] + v_ij[0]),
361 vn = 0.5 * (v_ij[0] + v_n[0]);
363 if (vs > 0.0 and vn >= 0.0) {
366 }
else if (vs <= 0.0 and vn < 0.0) {
382 if (north + south > 0) {
383 D_y = 1.0 / (dy * (north + south));
390 for (
unsigned int k = 0;
k < Mz; ++
k) {
392 u_x = D_x * (west * (u_ij[
k] - u_w[
k]) + east * (u_e[
k] - u_ij[
k])),
393 v_y = D_y * (south * (v_ij[
k] - v_s[
k]) + north * (v_n[
k] - v_ij[
k]));
394 u_x_plus_v_y[
k] = u_x + v_y;
398 if (basal_melt_rate != NULL) {
399 w_ij[0] = - (*basal_melt_rate)(i,j);
405 for (
unsigned int k = 1;
k < Mz; ++
k) {
406 const double dz = z[
k] - z[
k-1];
408 w_ij[
k] = w_ij[
k - 1] - (0.5 * dz) * (u_x_plus_v_y[
k] + u_x_plus_v_y[
k - 1]);
433static inline double D2(
double u_x,
double u_y,
double u_z,
double v_x,
double v_y,
double v_z) {
434 return 0.5 * (PetscSqr(u_x + v_y) + u_x*u_x + v_y*v_y + 0.5 * (PetscSqr(u_y + v_x) + u_z*u_z + v_z*v_z));
511 n = flow_law.exponent(),
512 exponent = 0.5 * (1.0 /
n + 1.0),
513 e_to_a_power = pow(enhancement_factor,-1.0/
n);
517 const std::vector<double> &z =
m_grid->z();
518 const unsigned int Mz =
m_grid->Mz();
519 std::vector<double> depth(Mz), pressure(Mz), hardness(Mz);
523 for (
auto p :
m_grid->points()) {
524 const int i = p.i(), j = p.j();
526 double H = thickness(i, j);
527 int ks =
m_grid->kBelowHeight(H);
529 *u_ij, *u_w, *u_n, *u_e, *u_s,
530 *v_ij, *v_w, *v_n, *v_e, *v_s;
534 double west = 1, east = 1, south = 1, north = 1,
540 if ((mask.icy(i,j) and mask.ice_free(i+1,j)) or (mask.ice_free(i,j) and mask.icy(i+1,j))) {
543 if ((mask.icy(i,j) and mask.ice_free(i-1,j)) or (mask.ice_free(i,j) and mask.icy(i-1,j))) {
547 if (east + west > 0) {
548 D_x = 1.0 / (
m_grid->dx() * (east + west));
556 if ((mask.icy(i,j) and mask.ice_free(i,j+1)) or (mask.ice_free(i,j) and mask.icy(i,j+1))) {
559 if ((mask.icy(i,j) and mask.ice_free(i,j-1)) or (mask.ice_free(i,j) and mask.icy(i,j-1))) {
563 if (north + south > 0) {
564 D_y = 1.0 / (
m_grid->dy() * (north + south));
576 v_ij = v.get_column(i, j);
577 v_w = v.get_column(i - 1, j);
578 v_e = v.get_column(i + 1, j);
579 v_s = v.get_column(i, j - 1);
580 v_n = v.get_column(i, j + 1);
585 for (
int k = 0;
k <= ks; ++
k) {
591 EC->pressure(depth, ks, pressure);
593 flow_law.hardness_n(E_ij, pressure.data(), ks + 1, hardness.data());
595 for (
int k = 0;
k <= ks; ++
k) {
598 double u_z = 0.0, v_z = 0.0,
599 u_x = D_x * (west * (u_ij[
k] - u_w[
k]) + east * (u_e[
k] - u_ij[
k])),
600 u_y = D_y * (south * (u_ij[
k] - u_s[
k]) + north * (u_n[
k] - u_ij[
k])),
601 v_x = D_x * (west * (v_ij[
k] - v_w[
k]) + east * (v_e[
k] - v_ij[
k])),
602 v_y = D_y * (south * (v_ij[
k] - v_s[
k]) + north * (v_n[
k] - v_ij[
k]));
605 dz = z[
k+1] - z[
k-1];
606 u_z = (u_ij[
k+1] - u_ij[
k-1]) / dz;
607 v_z = (v_ij[
k+1] - v_ij[
k-1]) / dz;
611 u_z = (u_ij[1] - u_ij[0]) / dz;
612 v_z = (v_ij[1] - v_ij[0]) / dz;
615 Sigma[
k] = 2.0 * e_to_a_power * hardness[
k] * pow(
D2(u_x, u_y, u_z, v_x, v_y, v_z), exponent);
618 int remaining_levels = Mz - (ks + 1);
619 if (remaining_levels > 0) {
620#if PETSC_VERSION_LT(3, 12, 0)
621 ierr = PetscMemzero(&Sigma[ks+1],
622 remaining_levels*
sizeof(
double));
624 ierr = PetscArrayzero(&Sigma[ks+1], remaining_levels);
682 auto grid = result.
grid();
683 double dx = grid->dx();
684 double dy = grid->dy();
688 for (
auto p : grid->points()) {
689 const int i = p.i(), j = p.j();
692 result(i, j).eigen1 = 0.0;
693 result(i, j).eigen2 = 0.0;
697 auto m = mask.
star(i,j);
698 auto U = V.
star(i,j);
701 double u_x = 0, u_y = 0, v_x = 0, v_y = 0,
702 east = 1, west = 1, south = 1, north = 1;
735 if (west + east > 0) {
736 u_x = 1.0 / (dx * (west + east)) * (west * (U.c.u - U[
West].u) + east * (U[
East].u - U.c.u));
737 v_x = 1.0 / (dx * (west + east)) * (west * (U.c.v - U[
West].v) + east * (U[
East].v - U.c.v));
740 if (south + north > 0) {
741 u_y = 1.0 / (dy * (south + north)) * (south * (U.c.u - U[
South].u) + north * (U[
North].u - U.c.u));
742 v_y = 1.0 / (dy * (south + north)) * (south * (U.c.v - U[
South].v) + north * (U[
North].v - U.c.v));
745 const double A = 0.5 * (u_x + v_y),
746 B = 0.5 * (u_x - v_y),
747 Dxy = 0.5 * (v_x + u_y),
748 q = sqrt(B*B + Dxy*Dxy);
749 result(i, j).eigen1 = A + q;
750 result(i, j).eigen2 = A - q;
764 auto grid = result.
grid();
772 for (
auto p : grid->points()) {
773 const int i = p.i(), j = p.j();
776 result(i,j).xx = 0.0;
777 result(i,j).yy = 0.0;
778 result(i,j).xy = 0.0;
782 auto m = cell_type.
star(i,j);
783 auto U = velocity.
star(i,j);
786 double u_x = 0, u_y = 0, v_x = 0, v_y = 0,
787 east = 1, west = 1, south = 1, north = 1;
820 if (west + east > 0) {
821 u_x = 1.0 / (dx * (west + east)) * (west * (U.c.u - U[
West].u) + east * (U[
East].u - U.c.u));
822 v_x = 1.0 / (dx * (west + east)) * (west * (U.c.v - U[
West].v) + east * (U[
East].v - U.c.v));
825 if (south + north > 0) {
826 u_y = 1.0 / (dy * (south + north)) * (south * (U.c.u - U[
South].u) + north * (U[
North].u - U.c.u));
827 v_y = 1.0 / (dy * (south + north)) * (south * (U.c.v - U[
South].v) + north * (U[
North].v - U.c.v));
836 result(i,j).xx = 2.0*nu*u_x;
837 result(i,j).yy = 2.0*nu*v_y;
838 result(i,j).xy = nu*(u_y+v_x);
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
const Profiling & profiling() const
std::set< VariableMetadata > state() const
A class defining a common interface for most PISM sub-models.
array::Scalar1 sea_level_elevation
array::Scalar cell_grounded_fraction
array::Scalar2 ice_surface_elevation
array::Scalar1 ice_area_specific_volume
array::CellType2 cell_type
array::Scalar2 ice_thickness
array::Scalar2 bed_elevation
void append_time(double time_seconds) const
void define_variable(const VariableMetadata &variable) const
void failed()
Indicates a failure of a parallel section.
void begin(const char *name) const
void end(const char *name) const
void add_context(const std::string &message)
Add a message providing some context. This way we can (sort of) get a stack trace even though C++ exc...
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
stencils::Star< T > star(int i, int j) const
A storage vector combining related fields in a struct.
double * get_column(int i, int j)
A virtual class collecting methods common to ice and bedrock 3D fields.
std::shared_ptr< const Grid > grid() const
void add(double alpha, const Array &x)
Result: v <- v + alpha * x. Calls VecAXPY.
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
Abstract class for reading, writing, allocating, and accessing a DA-based PETSc Vec (2D and 3D fields...
bool ice_free(int i, int j) const
bool icy(int i, int j) const
A class for storing and accessing internal staggered-grid 2D fields. Uses dof=2 storage....
void effective_viscosity(double hardness, double gamma, double *nu, double *dnu) const
Computes the regularized effective viscosity and its derivative with respect to the second invariant ...
Shallow stress balance modifier (such as the non-sliding SIA).
Shallow stress balance (such as the SSA).
array::Array3D m_strain_heating
std::shared_ptr< SSB_Modifier > m_modifier
CFLData max_timestep_cfl_3d() const
const array::Array3D & velocity_w() const
virtual void write_state_impl(const OutputFile &output) const
The default (empty implementation).
const SSB_Modifier * modifier() const
Returns a pointer to a stress balance modifier implementation.
const array::Array3D & velocity_u() const
Get components of the the 3D velocity field.
virtual void compute_volumetric_strain_heating(const Inputs &inputs)
Computes the volumetric strain heating using horizontal velocity.
std::shared_ptr< ShallowStressBalance > m_shallow_stress_balance
CFLData max_timestep_cfl_2d() const
double max_diffusivity() const
Get the max diffusivity (for the adaptive time-stepping).
virtual void compute_vertical_velocity(const array::CellType1 &mask, const array::Array3D &u, const array::Array3D &v, const array::Scalar *bmr, array::Array3D &result)
Compute vertical velocity using incompressibility of the ice.
void init()
Initialize the StressBalance object.
const array::Vector & advective_velocity() const
Get the thickness-advective (SSA) 2D velocity.
const array::Staggered & diffusive_flux() const
Get the diffusive (SIA) vertically-averaged flux on the staggered grid.
const ShallowStressBalance * shallow() const
Returns a pointer to a shallow stress balance solver implementation.
std::string stdout_report() const
Produce a report string for the standard output.
void update(const Inputs &inputs, bool full_update)
Update all the fields if (full_update), only update diffusive flux and max. diffusivity otherwise.
const array::Scalar & basal_frictional_heating() const
Get the basal frictional heating.
const array::Array3D & velocity_v() const
const array::Array3D & volumetric_strain_heating() const
StressBalance(std::shared_ptr< const Grid > g, std::shared_ptr< ShallowStressBalance > sb, std::shared_ptr< SSB_Modifier > ssb_mod)
virtual std::set< VariableMetadata > state_impl() const
#define PISM_CHK(errcode, name)
void write_config(const Config &config, const std::string &variable_name, const OutputFile &file)
bool ice_free(int M)
Ice-free cell (grounded or ocean).
void compute_2D_principal_strain_rates(const array::Vector1 &V, const array::CellType1 &mask, array::Array2D< PrincipalStrainRates > &result)
Compute eigenvalues of the horizontal, vertically-integrated strain rate tensor.
static double D2(double u_x, double u_y, double u_z, double v_x, double v_y, double v_z)
void compute_2D_stresses(const rheology::FlowLaw &flow_law, const array::Vector1 &velocity, const array::Scalar &hardness, const array::CellType1 &cell_type, array::Array2D< DeviatoricStresses > &result)
Compute 2D deviatoric stresses.
static double secondInvariant_2D(const Vector2d &U_x, const Vector2d &U_y)
CFLData max_timestep_cfl_2d(const array::Scalar &ice_thickness, const array::CellType &cell_type, const array::Scalar1 *no_model_mask, const array::Vector &velocity)
Compute the CFL constant associated to first-order upwinding for the sliding contribution to mass con...
T combine(const T &a, const T &b)
CFLData max_timestep_cfl_3d(const array::Scalar &ice_thickness, const array::CellType &cell_type, const array::Scalar1 *no_model_mask, const array::Array3D &u3, const array::Array3D &v3, const array::Array3D &w3)
Compute the maximum velocities for time-stepping and reporting to user.