19 #include "pism/stressbalance/StressBalance.hh"
20 #include "pism/stressbalance/ShallowStressBalance.hh"
21 #include "pism/stressbalance/SSB_Modifier.hh"
22 #include "pism/util/EnthalpyConverter.hh"
23 #include "pism/rheology/FlowLaw.hh"
24 #include "pism/util/Grid.hh"
25 #include "pism/util/Mask.hh"
26 #include "pism/util/ConfigInterface.hh"
27 #include "pism/util/error_handling.hh"
28 #include "pism/util/Profiling.hh"
29 #include "pism/util/array/CellType.hh"
30 #include "pism/util/Time.hh"
31 #include "pism/geometry/Geometry.hh"
32 #include "pism/util/Context.hh"
35 namespace stressbalance {
66 auto config = ctx->config();
68 File output(ctx->com(), filename,
72 config->write(output);
75 io::append_time(output, config->get_string(
"time.dimension_name"), ctx->time()->current());
138 std::shared_ptr<ShallowStressBalance> sb,
139 std::shared_ptr<SSB_Modifier> ssb_mod)
142 m_strain_heating(m_grid,
"strain_heating", array::
WITHOUT_GHOSTS, m_grid->z()),
143 m_shallow_stress_balance(sb),
144 m_modifier(ssb_mod) {
147 .
long_name(
"vertical velocity of ice, relative to base of ice directly below")
153 .
long_name(
"rate of strain heating in ice (dissipation heating)")
176 inputs, full_update);
283 const bool use_upstream_fd =
m_config->get_string(
"stress_balance.vertical_velocity_approximation") ==
"upstream";
287 if (basal_melt_rate) {
288 list.
add(*basal_melt_rate);
291 const std::vector<double> &z =
m_grid->z();
292 const unsigned int Mz =
m_grid->Mz();
298 std::vector<double> u_x_plus_v_y(Mz);
300 for (
auto p =
m_grid->points(); p; p.next()) {
301 const int i = p.i(), j = p.j();
330 if (use_upstream_fd) {
332 uw = 0.5 * (u_w[0] + u_ij[0]),
333 ue = 0.5 * (u_ij[0] + u_e[0]);
335 if (uw > 0.0 and ue >= 0.0) {
338 }
else if (uw <= 0.0 and ue < 0.0) {
354 if (east + west > 0) {
355 D_x = 1.0 / (dx * (east + west));
365 if (use_upstream_fd) {
367 vs = 0.5 * (v_s[0] + v_ij[0]),
368 vn = 0.5 * (v_ij[0] + v_n[0]);
370 if (vs > 0.0 and vn >= 0.0) {
373 }
else if (vs <= 0.0 and vn < 0.0) {
389 if (north + south > 0) {
390 D_y = 1.0 / (dy * (north + south));
397 for (
unsigned int k = 0;
k < Mz; ++
k) {
399 u_x = D_x * (west * (u_ij[
k] - u_w[
k]) + east * (u_e[
k] - u_ij[
k])),
400 v_y = D_y * (south * (v_ij[
k] - v_s[
k]) + north * (v_n[
k] - v_ij[
k]));
401 u_x_plus_v_y[
k] = u_x + v_y;
405 if (basal_melt_rate != NULL) {
406 w_ij[0] = - (*basal_melt_rate)(i,j);
412 for (
unsigned int k = 1;
k < Mz; ++
k) {
413 const double dz = z[
k] - z[
k-1];
415 w_ij[
k] = w_ij[
k - 1] - (0.5 * dz) * (u_x_plus_v_y[
k] + u_x_plus_v_y[
k - 1]);
440 static inline double D2(
double u_x,
double u_y,
double u_z,
double v_x,
double v_y,
double v_z) {
441 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));
519 exponent = 0.5 * (1.0 /
n + 1.0),
520 e_to_a_power = pow(enhancement_factor,-1.0/
n);
524 const std::vector<double> &z =
m_grid->z();
525 const unsigned int Mz =
m_grid->Mz();
526 std::vector<double> depth(Mz), pressure(Mz), hardness(Mz);
530 for (
auto p =
m_grid->points(); p; p.next()) {
531 const int i = p.i(), j = p.j();
533 double H = thickness(i, j);
534 int ks =
m_grid->kBelowHeight(H);
536 *u_ij, *u_w, *u_n, *u_e, *u_s,
537 *v_ij, *v_w, *v_n, *v_e, *v_s;
541 double west = 1, east = 1, south = 1, north = 1,
547 if ((mask.icy(i,j) and mask.ice_free(i+1,j)) or (mask.ice_free(i,j) and mask.icy(i+1,j))) {
550 if ((mask.icy(i,j) and mask.ice_free(i-1,j)) or (mask.ice_free(i,j) and mask.icy(i-1,j))) {
554 if (east + west > 0) {
555 D_x = 1.0 / (
m_grid->dx() * (east + west));
563 if ((mask.icy(i,j) and mask.ice_free(i,j+1)) or (mask.ice_free(i,j) and mask.icy(i,j+1))) {
566 if ((mask.icy(i,j) and mask.ice_free(i,j-1)) or (mask.ice_free(i,j) and mask.icy(i,j-1))) {
570 if (north + south > 0) {
571 D_y = 1.0 / (
m_grid->dy() * (north + south));
583 v_ij = v.get_column(i, j);
584 v_w = v.get_column(i - 1, j);
585 v_e = v.get_column(i + 1, j);
586 v_s = v.get_column(i, j - 1);
587 v_n = v.get_column(i, j + 1);
592 for (
int k = 0;
k <= ks; ++
k) {
598 EC->pressure(depth, ks, pressure);
600 flow_law.
hardness_n(E_ij, pressure.data(), ks + 1, hardness.data());
602 for (
int k = 0;
k <= ks; ++
k) {
605 double u_z = 0.0, v_z = 0.0,
606 u_x = D_x * (west * (u_ij[
k] - u_w[
k]) + east * (u_e[
k] - u_ij[
k])),
607 u_y = D_y * (south * (u_ij[
k] - u_s[
k]) + north * (u_n[
k] - u_ij[
k])),
608 v_x = D_x * (west * (v_ij[
k] - v_w[
k]) + east * (v_e[
k] - v_ij[
k])),
609 v_y = D_y * (south * (v_ij[
k] - v_s[
k]) + north * (v_n[
k] - v_ij[
k]));
612 dz = z[
k+1] - z[
k-1];
613 u_z = (u_ij[
k+1] - u_ij[
k-1]) / dz;
614 v_z = (v_ij[
k+1] - v_ij[
k-1]) / dz;
618 u_z = (u_ij[1] - u_ij[0]) / dz;
619 v_z = (v_ij[1] - v_ij[0]) / dz;
622 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);
625 int remaining_levels = Mz - (ks + 1);
626 if (remaining_levels > 0) {
627 #if PETSC_VERSION_LT(3, 12, 0)
628 ierr = PetscMemzero(&Sigma[ks+1],
629 remaining_levels*
sizeof(
double));
631 ierr = PetscArrayzero(&Sigma[ks+1], remaining_levels);
688 auto grid = result.
grid();
689 double dx = grid->dx();
690 double dy = grid->dy();
694 for (
auto p = grid->points(); p; p.next()) {
695 const int i = p.i(), j = p.j();
698 result(i, j).eigen1 = 0.0;
699 result(i, j).eigen2 = 0.0;
703 auto m = mask.
star(i,j);
704 auto U = V.
star(i,j);
707 double u_x = 0, u_y = 0, v_x = 0, v_y = 0,
708 east = 1, west = 1, south = 1, north = 1;
741 if (west + east > 0) {
742 u_x = 1.0 / (dx * (west + east)) * (west * (U.c.u - U[
West].u) + east * (U[
East].u - U.c.u));
743 v_x = 1.0 / (dx * (west + east)) * (west * (U.c.v - U[
West].v) + east * (U[
East].v - U.c.v));
746 if (south + north > 0) {
747 u_y = 1.0 / (dy * (south + north)) * (south * (U.c.u - U[
South].u) + north * (U[
North].u - U.c.u));
748 v_y = 1.0 / (dy * (south + north)) * (south * (U.c.v - U[
South].v) + north * (U[
North].v - U.c.v));
751 const double A = 0.5 * (u_x + v_y),
752 B = 0.5 * (u_x - v_y),
753 Dxy = 0.5 * (v_x + u_y),
754 q = sqrt(B*B + Dxy*Dxy);
755 result(i, j).eigen1 = A + q;
756 result(i, j).eigen2 = A - q;
770 auto grid = result.
grid();
778 for (
auto p = grid->points(); p; p.next()) {
779 const int i = p.i(), j = p.j();
782 result(i,j).xx = 0.0;
783 result(i,j).yy = 0.0;
784 result(i,j).xy = 0.0;
788 auto m = cell_type.
star(i,j);
789 auto U = velocity.
star(i,j);
792 double u_x = 0, u_y = 0, v_x = 0, v_y = 0,
793 east = 1, west = 1, south = 1, north = 1;
826 if (west + east > 0) {
827 u_x = 1.0 / (dx * (west + east)) * (west * (U.c.u - U[
West].u) + east * (U[
East].u - U.c.u));
828 v_x = 1.0 / (dx * (west + east)) * (west * (U.c.v - U[
West].v) + east * (U[
East].v - U.c.v));
831 if (south + north > 0) {
832 u_y = 1.0 / (dy * (south + north)) * (south * (U.c.u - U[
South].u) + north * (U[
North].u - U.c.u));
833 v_y = 1.0 / (dy * (south + north)) * (south * (U.c.v - U[
South].v) + north * (U[
North].v - U.c.v));
842 result(i,j).xx = 2.0*nu*u_x;
843 result(i,j).yy = 2.0*nu*v_y;
844 result(i,j).xy = nu*(u_y+v_x);
const Config::ConstPtr 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
A class defining a common interface for most PISM sub-models.
std::shared_ptr< EnthalpyConverter > Ptr
High-level PISM I/O class.
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 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.
void write(const std::string &filename) const
std::shared_ptr< const Grid > grid() const
void add(double alpha, const Array &x)
Result: v <- v + alpha * x. Calls VecAXPY.
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
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 ...
void hardness_n(const double *enthalpy, const double *pressure, unsigned int n, double *result) const
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
virtual void write_model_state_impl(const File &output) const
The default (empty implementation).
CFLData max_timestep_cfl_3d() const
const array::Array3D & velocity_w() const
virtual void define_model_state_impl(const File &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)
#define PISM_CHK(errcode, name)
void append_time(const File &file, const Config &config, double time_seconds)
Prepare a file for output.
@ PISM_READWRITE_MOVE
create a file for writing, move foo.nc to foo.nc~ if present
void define_time(const File &file, const Context &ctx)
Prepare a file for output.
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.
io::Backend string_to_backend(const std::string &backend)
CFLData max_timestep_cfl_2d(const array::Scalar &ice_thickness, const array::CellType &cell_type, const array::Vector &velocity)
Compute the CFL constant associated to first-order upwinding for the sliding contribution to mass con...
static double secondInvariant_2D(const Vector2d &U_x, const Vector2d &U_y)
CFLData max_timestep_cfl_3d(const array::Scalar &ice_thickness, const array::CellType &cell_type, const array::Array3D &u3, const array::Array3D &v3, const array::Array3D &w3)
Compute the maximum velocities for time-stepping and reporting to user.