20#include "pism/geometry/GeometryEvolution.hh"
22#include "pism/util/Grid.hh"
23#include "pism/util/Mask.hh"
24#include "pism/util/array/CellType.hh"
25#include "pism/util/array/Scalar.hh"
26#include "pism/util/array/Staggered.hh"
27#include "pism/util/array/Vector.hh"
29#include "pism/geometry/part_grid_threshold_thickness.hh"
30#include "pism/util/Context.hh"
31#include "pism/util/Logger.hh"
32#include "pism/util/Profiling.hh"
33#include "pism/util/Interpolation1D.hh"
34#include "pism/util/pism_utilities.hh"
36#include "pism/geometry/flux_limiter.hh"
48 Impl(std::shared_ptr<const Grid>
g);
95 : gc(*grid->ctx()->config()),
96 flux_divergence(grid,
"flux_divergence"),
97 conservation_error(grid,
"conservation_error"),
98 effective_SMB(grid,
"effective_SMB"),
99 effective_BMB(grid,
"effective_BMB"),
100 thickness_change(grid,
"thickness_change"),
101 ice_area_specific_volume_change(grid,
"ice_area_specific_volume_change"),
102 flux_staggered(grid,
"flux_staggered"),
103 input_velocity(grid,
"input_velocity"),
104 bed_elevation(grid,
"bed_elevation"),
105 sea_level(grid,
"sea_level"),
106 ice_thickness(grid,
"ice_thickness"),
107 area_specific_volume(grid,
"area_specific_volume"),
108 surface_elevation(grid,
"surface_elevation"),
109 cell_type(grid,
"cell_type"),
110 residual(grid,
"residual"),
111 thickness(grid,
"thickness") {
119 ice_density = config->get_number(
"constants.ice.density");
120 use_bmr = config->get_flag(
"geometry.update.use_basal_melt_rate");
121 use_part_grid = config->get_flag(
"geometry.part_grid.enabled");
128 .
long_name(
"fluxes through cell interfaces (sides) on the staggered grid (x-offset)")
132 .
long_name(
"fluxes through cell interfaces (sides) on the staggered grid (y-offset)")
143 "conservation error due to enforcing non-negativity of ice thickness (over the last time step)")
147 .
long_name(
"effective surface mass balance over the last time step")
151 .
long_name(
"effective basal mass balance over the last time step")
157 .
long_name(
"change in area-specific volume due to flow")
158 .
units(
"meters^3 / meters^2");
164 .
long_name(
"ghosted copy of the input velocity")
165 .
units(
"meters / second");
172 .
long_name(
"working (ghosted) copy of the ice thickness")
176 .
long_name(
"working (ghosted) copy of the area specific volume")
177 .
units(
"meters^3 / meters^2");
180 .
long_name(
"working (ghosted) copy of the surface elevation")
357 surface_mass_balance_rate,
386 for (
auto p =
m_grid->points(); p; p.next()) {
387 const int i = p.i(), j = p.j();
391 const double H_new = (H(i, j) + dH_SMB(i, j)) + dH_BMB(i, j);
418 if ((ice_free_ocean(current) and input > 0.0) or (ice_free_ocean(neighbor) and input < 0.0)) {
423 if ((ice_free_land(current) and input > 0.0) or (ice_free_land(neighbor) and input < 0.0)) {
428 if (grounded_ice(current) and grounded_ice(neighbor)) {
433 if ((grounded_ice(current) and floating_ice(neighbor)) or
434 (floating_ice(current) and grounded_ice(neighbor))) {
439 if ((grounded_ice(current) and ice_free_land(neighbor)) or
440 (ice_free_land(current) and grounded_ice(neighbor))) {
445 if ((grounded_ice(current) and ice_free_ocean(neighbor)) or
446 (ice_free_ocean(current) and grounded_ice(neighbor))) {
451 if (floating_ice(current) and floating_ice(neighbor)) {
456 if ((floating_ice(current) and ice_free_land(neighbor)) or
457 (ice_free_land(current) and floating_ice(neighbor))) {
463 if ((floating_ice(current) and ice_free_ocean(neighbor)) or
464 (ice_free_ocean(current) and floating_ice(neighbor))) {
469 if (ice_free_land(current) and ice_free_land(neighbor)) {
474 if ((ice_free_land(current) and ice_free_ocean(neighbor)) or
475 (ice_free_ocean(current) and ice_free_land(neighbor))) {
480 if (ice_free_ocean(current) and ice_free_ocean(neighbor)) {
496 if ((ice_free_ocean(current) and flux > 0.0) or (ice_free_ocean(neighbor) and flux < 0.0)) {
501 if ((ice_free_land(current) and flux > 0.0) or (ice_free_land(neighbor) and flux < 0.0)) {
506 if (grounded_ice(current) and grounded_ice(neighbor)) {
511 if ((grounded_ice(current) and floating_ice(neighbor)) or
512 (floating_ice(current) and grounded_ice(neighbor))) {
517 if ((grounded_ice(current) and ice_free_land(neighbor)) or
518 (ice_free_land(current) and grounded_ice(neighbor))) {
523 if ((grounded_ice(current) and ice_free_ocean(neighbor)) or
524 (ice_free_ocean(current) and grounded_ice(neighbor))) {
529 if (floating_ice(current) and floating_ice(neighbor)) {
535 if ((floating_ice(current) and ice_free_land(neighbor)) or
536 (ice_free_land(current) and floating_ice(neighbor))) {
542 if ((floating_ice(current) and ice_free_ocean(neighbor)) or
543 (ice_free_ocean(current) and floating_ice(neighbor))) {
548 if (ice_free_land(current) and ice_free_land(neighbor)) {
553 if ((ice_free_land(current) and ice_free_ocean(neighbor)) or
554 (ice_free_ocean(current) and ice_free_land(neighbor))) {
559 if (ice_free_ocean(current) and ice_free_ocean(neighbor)) {
581 array::AccessScope list{ &cell_type, &velocity, &ice_thickness, &diffusive_flux, &output };
586 for (
auto p =
m_grid->points(); p; p.next()) {
587 const int i = p.i(), j = p.j(), M = cell_type.
as_int(i, j);
589 const double H = ice_thickness(i, j);
592 for (
int n = 0;
n < 2; ++
n) {
593 const int oi = 1 -
n,
598 const int M_n = cell_type.
as_int(i_n, j_n);
603 const Vector2d& V_n = velocity(i_n, j_n);
604 int W =
static_cast<int>(icy(M)), W_n =
static_cast<int>(icy(M_n));
606 auto v_staggered = (W * V + W_n * V_n) / std::max(W + W_n, 1);
607 v =
n == 0 ? v_staggered.u : v_staggered.v;
611 const double H_n = ice_thickness(i_n, j_n),
612 Q_advective = v * (v > 0.0 ? H : H_n);
614 output(i, j,
n) = Q_advective;
619 for (
auto p =
m_grid->points(); p; p.next()) {
620 const int i = p.i(), j = p.j(), M = cell_type.
as_int(i, j);
622 for (
int n = 0;
n < 2; ++
n) {
623 const int oi = 1 -
n,
628 const int M_n = cell_type.
as_int(i_n, j_n);
634 output(i, j,
n) = Q_diffusive + Q_advective;
659 for (
auto p =
m_grid->points(); p; p.next()) {
660 const int i = p.i(), j = p.j();
662 auto Q = flux.
star(i, j);
664 double divQ = (Q.e - Q.w) / dx + (Q.n - Q.s) / dy;
666 if (thickness_bc_mask(i, j) > 0.5) {
722 const double Lz =
m_grid->Lz();
726 for (
auto p =
m_grid->points(); p; p.next()) {
727 const int i = p.i(), j = p.j();
735 area_specific_volume(i, j) += -divQ * dt;
743 if (threshold == 0.0) {
744 threshold = area_specific_volume(i, j);
747 if (area_specific_volume(i, j) >= threshold) {
748 ice_thickness(i, j) += threshold;
750 area_specific_volume(i, j) = 0.0;
759 ice_thickness(i, j) += -dt * divQ;
761 if (ice_thickness(i, j) > Lz) {
763 "ice thickness would exceed Lz at i=%d, j=%d (H=%f, Lz=%f)",
764 i, j, ice_thickness(i, j), Lz);
783 const int max_n_iterations = (
int)
m_config->get_number(
"geometry.part_grid.max_iterations");
786 for (
int i = 0; i < max_n_iterations and not done; ++i) {
787 m_log->message(4,
"redistribution iteration %d\n", i);
798 "WARNING: not done redistributing mass after %d iterations, remaining residual: %f m^3.\n",
807 if (max(ice_thickness) >
m_grid->Lz()) {
809 "after part_grid residual redistribution");
838 array::AccessScope list{ &cell_type, &ice_thickness, &area_specific_volume, &residual };
840 for (
auto p =
m_grid->points(); p; p.next()) {
841 const int i = p.i(), j = p.j();
843 if (residual(i, j) <= 0.0) {
851 N += ice_free_ocean(m[d]) ? 1 : 0;
861 ice_thickness(i, j) += residual(i, j);
862 residual(i, j) = 0.0;
869 for (
auto p =
m_grid->points(); p; p.next()) {
870 const int i = p.i(), j = p.j();
873 area_specific_volume(i, j) +=
874 (residual(i + 1, j) + residual(i - 1, j) + residual(i, j + 1) + residual(i, j - 1));
891 m_impl->
gc.
compute(sea_level, bed_topography, ice_thickness, cell_type, ice_surface_elevation);
893 double remaining_residual = 0.0;
900 &bed_topography, &cell_type };
902 for (
auto p =
m_grid->points(); p; p.next()) {
903 const int i = p.i(), j = p.j();
905 if (area_specific_volume(i, j) <= 0.0) {
911 ice_surface_elevation.
star(i, j), bed_topography(i, j));
915 if (threshold == 0.0) {
916 threshold = area_specific_volume(i, j);
919 if (area_specific_volume(i, j) >= threshold) {
920 ice_thickness(i, j) += threshold;
921 residual(i, j) = area_specific_volume(i, j) - threshold;
922 area_specific_volume(i, j) = 0.0;
924 remaining_residual += residual(i, j);
932 done = remaining_residual <= 0.0;
962 for (
auto p =
m_grid->points(); p; p.next()) {
963 const int i = p.i(), j = p.j();
965 const double H = ice_thickness(i, j), dH = thickness_change(i, j);
969 thickness_change(i, j) = -H;
973 const double V = area_specific_volume(i, j), dV = area_specific_volume_change(i, j);
976 area_specific_volume_change(i, j) = -V;
1020 array::AccessScope list{ &ice_thickness, &surface_mass_flux, &basal_melt_rate, &cell_type,
1021 &thickness_bc_mask, &effective_SMB, &effective_BMB };
1025 for (
auto p =
m_grid->points(); p; p.next()) {
1026 const int i = p.i(), j = p.j();
1030 effective_SMB(i, j) = 0.0;
1031 effective_BMB(i, j) = 0.0;
1035 const double H = ice_thickness(i, j);
1049 effective_SMB(i, j) = dH_SMB;
1050 effective_BMB(i, j) = dH_BMB;
1058namespace diagnostics {
1069 auto result = allocate<array::Scalar>(
"flux_divergence");
1086 auto result = allocate<array::Staggered>(
"flux_staggered");
1100 std::map<std::string, Ptr> result;
1102 {
"flux_staggered", Ptr(
new FluxStaggered(
this)) },
1103 {
"flux_divergence", Ptr(
new FluxDivergence(
this)) },
1130 velocity, diffusive_flux,
1137 for (
auto p =
m_grid->points(); p; p.next()) {
1138 const int i = p.i(), j = p.j();
1142 for (
int n : {0, 1}) {
1151 if (not (M == 0 and M_n == 0)) {
1152 output(i, j,
n) = 0.0;
1186 for (
auto p =
m_grid->points(); p; p.next()) {
1187 const int i = p.i(), j = p.j();
1190 effective_SMB(i, j) = 0.0;
1191 effective_BMB(i, j) = 0.0;
1238 Q.
n *= (
int)grounded(cell_type.
n);
1239 Q.e *= (
int)grounded(cell_type.
e);
1240 Q.s *= (
int)grounded(cell_type.
s);
1241 Q.w *= (
int)grounded(cell_type.
w);
1243 return dy * (Q.w - Q.e) + dx * (Q.s - Q.n);
1265 auto grid = output.
grid();
1267 const double dx = grid->dx(),
1274 for (
auto p = grid->points(); p; p.next()) {
1275 const int i = p.i(), j = p.j();
1277 double result = 0.0;
1279 if (cell_type.
ocean(i, j)) {
1281 auto Q = flux.
star(i, j);
1288 result *= unit_conversion_factor;
1291 output(i, j) += result;
1302 auto grid = cell_type.
grid();
1308 auto ice_density = grid->ctx()->config()->get_number(
"constants.ice.density");
1310 double conversion_factor = dt * ice_density;
1312 double total_flux = 0.0;
1318 for (
auto p = grid->points(); p; p.next()) {
1319 const int i = p.i(), j = p.j();
1321 if (cell_type.
ocean(i, j)) {
1323 auto Q = flux.
star(i, j);
1329 total_flux += volume_flux * conversion_factor;
1337 return GlobalSum(grid->com, total_flux);
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
DiagnosticList diagnostics() const
const Profiling & profiling() const
A class defining a common interface for most PISM sub-models.
std::shared_ptr< const Config > ConstPtr
const GeometryEvolution * model
A template derived from Diagnostic, adding a "Model".
std::vector< SpatialVariableMetadata > m_vars
metadata corresponding to NetCDF variables
std::shared_ptr< Diagnostic > Ptr
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)
void compute(const array::Scalar &sea_level, const array::Scalar &bed, const array::Scalar &thickness, array::Scalar &out_mask, array::Scalar &out_surface) const
const array::Scalar & thickness_change_due_to_flow() const
virtual void set_no_model_mask(const array::Scalar &mask)
virtual void init_impl(const InputOptions &opts)
virtual void compute_surface_and_basal_mass_balance(double dt, const array::Scalar &thickness_bc_mask, const array::Scalar &ice_thickness, const array::CellType &cell_type, const array::Scalar &surface_mass_flux, const array::Scalar &basal_melt_rate, array::Scalar &effective_SMB, array::Scalar &effective_BMB)
const array::Scalar & bottom_surface_mass_balance() const
void apply_mass_fluxes(Geometry &geometry) const
virtual void set_no_model_mask_impl(const array::Scalar &mask)
void source_term_step(const Geometry &geometry, double dt, const array::Scalar &thickness_bc_mask, const array::Scalar &surface_mass_balance_rate, const array::Scalar &basal_melt_rate)
const array::Scalar & flux_divergence() const
void update_in_place(double dt, const array::Scalar &bed_topography, const array::Scalar &sea_level, const array::Scalar &flux_divergence, array::Scalar &ice_thickness, array::Scalar &area_specific_volume)
virtual void ensure_nonnegativity(const array::Scalar &ice_thickness, const array::Scalar &area_specific_volume, array::Scalar &thickness_change, array::Scalar &area_specific_volume_change, array::Scalar &conservation_error)
virtual void compute_interface_fluxes(const array::CellType1 &cell_type, const array::Scalar &ice_thickness, const array::Vector &velocity, const array::Staggered &diffusive_flux, array::Staggered &output)
GeometryEvolution(std::shared_ptr< const Grid > grid)
void flow_step(const Geometry &ice_geometry, double dt, const array::Vector &advective_velocity, const array::Staggered &diffusive_flux, const array::Scalar &thickness_bc_mask)
const array::Scalar & top_surface_mass_balance() const
void apply_flux_divergence(Geometry &geometry) const
const array::Scalar & area_specific_volume_change_due_to_flow() const
virtual void compute_flux_divergence(double dt, const array::Staggered1 &flux, const array::Scalar &thickness_bc_mask, array::Scalar &conservation_error, array::Scalar &output)
void residual_redistribution_iteration(const array::Scalar &bed_topography, const array::Scalar &sea_level, array::Scalar1 &ice_surface_elevation, array::Scalar &ice_thickness, array::CellType1 &cell_type, array::Scalar &area_specific_volume, array::Scalar &residual, bool &done)
Perform one iteration of the residual mass redistribution.
const array::Scalar & conservation_error() const
const array::Staggered1 & flux_staggered() const
void init(const InputOptions &opts)
std::map< std::string, Diagnostic::Ptr > diagnostics_impl() const
array::Scalar1 sea_level_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
array::Scalar1 m_no_model_mask
RegionalGeometryEvolution(std::shared_ptr< const Grid > grid)
void compute_surface_and_basal_mass_balance(double dt, const array::Scalar &thickness_bc_mask, const array::Scalar &ice_thickness, const array::CellType &cell_type, const array::Scalar &surface_mass_flux, const array::Scalar &basal_melt_rate, array::Scalar &effective_SMB, array::Scalar &effective_BMB)
void compute_interface_fluxes(const array::CellType1 &cell_type, const array::Scalar &ice_thickness, const array::Vector &velocity, const array::Staggered &diffusive_flux, array::Staggered &output)
void set_no_model_mask_impl(const array::Scalar &mask)
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)
void set_interpolation_type(InterpolationType type)
std::shared_ptr< const Grid > grid() const
void set(double c)
Result: v[j] <- c for all j.
void update_ghosts()
Updates ghost points.
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
bool next_to_ice(int i, int j) const
Ice-free margin (at least one of four neighbors has ice).
stencils::Star< int > star_int(int i, int j) const
bool ice_free_ocean(int i, int j) const
bool ocean(int i, int j) const
"Cell type" mask. Adds convenience methods to array::Scalar.
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.
void copy_from(const array::Staggered &input)
A class for storing and accessing internal staggered-grid 2D fields. Uses dof=2 storage....
std::shared_ptr< array::Array > compute_impl() const
FluxDivergence(const GeometryEvolution *m)
Report the divergence of the ice flux.
std::shared_ptr< array::Array > compute_impl() const
FluxStaggered(const GeometryEvolution *m)
Report mass flux on the staggered grid.
#define PISM_ERROR_LOCATION
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).
static double effective_change(double H, double dH)
static double limit_advective_flux(int current, int neighbor, double input)
std::map< std::string, Diagnostic::Ptr > DiagnosticList
static double volume_flow_rate_from_land_to_water(const stencils::Star< int > &cell_type, const stencils::Star< double > &flux, double dx, double dy)
double part_grid_threshold_thickness(stencils::Star< int > cell_type, stencils::Star< double > ice_thickness, stencils::Star< double > surface_elevation, double bed_elevation)
Compute threshold thickness used when deciding if a partially-filled cell should be considered 'full'...
double total_grounding_line_flux(const array::CellType1 &cell_type, const array::Staggered1 &flux, double dt)
void ice_flow_rate_across_grounding_line(const array::CellType1 &cell_type, const array::Staggered1 &flux, double unit_conversion_factor, array::Scalar &output)
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)
static double limit_diffusive_flux(int current, int neighbor, double flux)
void make_nonnegative_preserving(double dt, const array::Scalar1 &x, const array::Staggered1 &flux, array::Staggered &result)
array::Scalar flux_divergence
Flux divergence (used to track thickness changes due to flow).
array::Scalar thickness_change
Change in ice thickness due to flow during the last time step.
array::Vector1 input_velocity
array::CellType1 cell_type
array::Scalar conservation_error
bool use_bmr
True if the basal melt rate contributes to geometry evolution.
Impl(std::shared_ptr< const Grid > g)
array::Scalar ice_area_specific_volume_change
Change in the ice area-specific volume due to flow during the last time step.
array::Scalar1 bed_elevation
array::Scalar effective_BMB
Effective basal mass balance.
array::Scalar1 area_specific_volume
bool use_part_grid
True if the part-grid scheme is enabled.
array::Scalar1 surface_elevation
array::Staggered1 flux_staggered
Flux through cell interfaces. Ghosted.
array::Scalar1 ice_thickness
array::Scalar effective_SMB
Effective surface mass balance.
Star stencil points (in the map-plane).