Loading [MathJax]/extensions/tex2jax.js
PISM, A Parallel Ice Sheet Model 2.2.2-d6b3a29ca committed by Constantine Khrulev on 2025-03-28
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
FrontRetreat.cc
Go to the documentation of this file.
1/* Copyright (C) 2016, 2017, 2018, 2019, 2020, 2022, 2023, 2024 PISM Authors
2 *
3 * This file is part of PISM.
4 *
5 * PISM is free software; you can redistribute it and/or modify it under the
6 * terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 3 of the License, or (at your option) any later
8 * version.
9 *
10 * PISM is distributed in the hope that it will be useful, but WITHOUT ANY
11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 * details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with PISM; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include "pism/frontretreat/FrontRetreat.hh"
20
21#include "pism/util/array/CellType.hh"
22#include "pism/util/MaxTimestep.hh"
23#include "pism/util/pism_utilities.hh"
24#include "pism/geometry/part_grid_threshold_thickness.hh"
25#include "pism/geometry/Geometry.hh"
26#include "pism/util/Context.hh"
27
28namespace pism {
29
30FrontRetreat::FrontRetreat(std::shared_ptr<const Grid> g)
31 : Component(g),
32 m_cell_type(m_grid, "cell_type"),
33 m_tmp(m_grid, "temporary_storage") {
34
35 m_tmp.metadata(0).long_name("additional mass loss at points near the front").units("m");
36 m_cell_type.metadata(0).long_name("cell type mask");
37}
38
39/*!
40 * Compute the modified mask to avoid "wrapping around" of front retreat at domain
41 * boundaries.
42 */
44 array::CellType1 &output) const {
45
46 array::AccessScope list{&input, &output};
47
48 const int Mx = m_grid->Mx();
49 const int My = m_grid->My();
50
51 ParallelSection loop(m_grid->com);
52 try {
53 for (auto p = m_grid->points(1); p; p.next()) {
54 const int i = p.i(), j = p.j();
55
56 if (i < 0 or i >= Mx or j < 0 or j >= My) {
57 output(i, j) = MASK_ICE_FREE_OCEAN;
58 } else {
59 output(i, j) = input(i, j);
60 }
61 }
62 } catch (...) {
63 loop.failed();
64 }
65 loop.check();
66}
67
68/*!
69 * Compute the maximum time step length provided a horizontal retreat rate.
70 */
72 const array::Scalar &bc_mask,
73 const array::Scalar &retreat_rate) const {
74
75 auto grid = retreat_rate.grid();
76 auto sys = grid->ctx()->unit_system();
77
78 using units::convert;
79
80 double dt_min = m_config->get_number("geometry.front_retreat.minimum_time_step", "seconds");
81
82 double
83 retreat_rate_max = 0.0,
84 retreat_rate_mean = 0.0;
85 int N_cells = 0;
86
87 array::AccessScope list{&cell_type, &bc_mask, &retreat_rate};
88
89 for (auto pt = grid->points(); pt; pt.next()) {
90 const int i = pt.i(), j = pt.j();
91
92 if (cell_type.ice_free_ocean(i, j) and
93 cell_type.next_to_ice(i, j) and
94 bc_mask(i, j) < 0.5) {
95 // NB: this condition has to match the one in update_geometry()
96
97 const double C = retreat_rate(i, j);
98
99 N_cells += 1;
100 retreat_rate_mean += C;
101 retreat_rate_max = std::max(C, retreat_rate_max);
102 }
103 }
104
105 N_cells = GlobalSum(grid->com, N_cells);
106 retreat_rate_mean = GlobalSum(grid->com, retreat_rate_mean);
107 retreat_rate_max = GlobalMax(grid->com, retreat_rate_max);
108
109 if (N_cells > 0.0) {
110 retreat_rate_mean /= N_cells;
111 } else {
112 retreat_rate_mean = 0.0;
113 }
114
115 double denom = retreat_rate_max / grid->dx();
116 const double epsilon = convert(sys, 0.001 / (grid->dx() + grid->dy()), "seconds", "years");
117
118 double dt = 1.0 / (denom + epsilon);
119
120 m_log->message(3,
121 " frontal retreat: maximum rate = %.2f m/year gives dt=%.5f years\n"
122 " mean rate = %.2f m/year over %d cells\n",
123 convert(m_sys, retreat_rate_max, "m second-1", "m year-1"),
124 convert(m_sys, dt, "seconds", "years"),
125 convert(m_sys, retreat_rate_mean, "m second-1", "m year-1"),
126 N_cells);
127
128 return MaxTimestep(std::max(dt, dt_min), "front_retreat");
129}
130
131/*!
132 * Update ice geometry by applying a horizontal retreat rate.
133 *
134 * This code applies a horizontal retreat rate at "partially-filled" cells that are next
135 * to icy cells.
136 *
137 * Models providing the "retreat rate" should set this field to zero in areas where a
138 * particular parameterization does not apply. (For example: some calving models apply at
139 * shelf calving fronts, others may apply at grounded termini but not at ice shelves,
140 * etc).
141 */
143 const Geometry &geometry,
144 const array::Scalar1 &bc_mask,
145 const array::Scalar &retreat_rate,
146 array::Scalar &Href,
147 array::Scalar1 &ice_thickness) {
148
149 const array::Scalar1 &bed = geometry.bed_elevation;
150 const array::Scalar1 &sea_level = geometry.sea_level_elevation;
151 const array::Scalar1 &surface_elevation = geometry.ice_surface_elevation;
152
153 if (m_config->get_flag("geometry.front_retreat.wrap_around")) {
155 } else {
156 // compute the modified mask needed to prevent front retreat from "wrapping around"
157 // the computational domain
159 }
160
161 const double dx = m_grid->dx();
162
163 m_tmp.set(0.0);
164
165 array::AccessScope list{&ice_thickness, &bc_mask,
166 &bed, &sea_level, &m_cell_type, &Href, &m_tmp, &retreat_rate,
167 &surface_elevation};
168
169 // Step 1: Apply the computed horizontal retreat rate:
170 for (auto pt = m_grid->points(); pt; pt.next()) {
171 const int i = pt.i(), j = pt.j();
172
173 // apply retreat rate at the margin (i.e. to partially-filled cells) only
174 if (m_cell_type.ice_free_ocean(i, j) and
175 m_cell_type.next_to_ice(i, j) and
176 bc_mask(i, j) < 0.5) {
177 // NB: this condition has to match the one in max_timestep()
178
179 const double
180 rate = retreat_rate(i, j),
181 Href_old = Href(i, j);
182
183 // Compute the number of floating neighbors and the neighbor-averaged ice thickness:
184 double H_threshold = part_grid_threshold_thickness(m_cell_type.star_int(i, j),
185 ice_thickness.star(i, j),
186 surface_elevation.star(i, j),
187 bed(i, j));
188
189 // Calculate mass loss with respect to the associated ice thickness and the grid size:
190 const double Href_change = -dt * rate * H_threshold / dx; // in m
191
192 if (Href_old + Href_change >= 0.0) {
193 // Href is high enough to absorb the mass loss
194 Href(i, j) = Href_old + Href_change;
195 } else {
196 Href(i, j) = 0.0;
197 // Href + Href_change is negative: need to distribute mass loss to neighboring points
198
199 // Find the number of neighbors to distribute to.
200 //
201 // We consider floating cells and grounded cells with the base below sea level. In other
202 // words, additional mass losses are distributed to shelf calving fronts and grounded marine
203 // termini.
204 int N = 0;
205 {
206 auto M = m_cell_type.star(i, j);
207 auto BC = bc_mask.star_int(i, j);
208
209 auto
210 b = bed.star(i, j),
211 sl = sea_level.star(i, j);
212
213 for (auto d : {North, East, South, West}) {
214 int m = M[d];
215 int bc = BC[d];
216
217 // note: this is where the modified cell type mask is used to prevent
218 // wrap-around
219 if (bc == 0 and // distribute to regular (*not* Dirichlet B.C.) neighbors only
220 (mask::floating_ice(m) or
221 (mask::grounded_ice(m) and b[d] < sl[d]))) {
222 N += 1;
223 }
224 }
225 }
226
227 if (N > 0) {
228 m_tmp(i, j) = (Href_old + Href_change) / (double)N;
229 } else {
230 // No shelf calving front of grounded terminus to distribute to: retreat stops here.
231 m_tmp(i, j) = 0.0;
232 }
233 }
234
235 } // end of "if ice free ocean next to ice and not a BC location "
236 } // end of loop over grid points
237
238 // Step 2: update ice thickness and Href in neighboring cells if we need to propagate mass losses.
240
241 for (auto p = m_grid->points(); p; p.next()) {
242 const int i = p.i(), j = p.j();
243
244 // Note: this condition has to match the one in step 1 above.
245 if (bc_mask.as_int(i, j) == 0 and
246 (m_cell_type.floating_ice(i, j) or
247 (m_cell_type.grounded_ice(i, j) and bed(i, j) < sea_level(i, j)))) {
248
249 const double delta_H = (m_tmp(i + 1, j) + m_tmp(i - 1, j) +
250 m_tmp(i, j + 1) + m_tmp(i, j - 1));
251
252 if (delta_H < 0.0) {
253 Href(i, j) = ice_thickness(i, j) + delta_H; // in m
254 ice_thickness(i, j) = 0.0;
255 }
256
257 // Stop retreat if the current cell does not have enough ice to absorb the loss.
258 if (Href(i, j) < 0.0) {
259 Href(i, j) = 0.0;
260 }
261 }
262 }
263}
264
265} // end of namespace pism
const units::System::Ptr m_sys
unit system used by this component
Definition Component.hh:160
std::shared_ptr< const Grid > grid() const
Definition Component.cc:105
const Config::ConstPtr m_config
configuration database used by this component
Definition Component.hh:158
const Logger::ConstPtr m_log
logger (for easy access)
Definition Component.hh:162
const std::shared_ptr< const Grid > m_grid
grid used by this component
Definition Component.hh:156
A class defining a common interface for most PISM sub-models.
Definition Component.hh:118
void update_geometry(double dt, const Geometry &geometry, const array::Scalar1 &bc_mask, const array::Scalar &retreat_rate, array::Scalar &Href, array::Scalar1 &ice_thickness)
array::CellType1 m_cell_type
MaxTimestep max_timestep(const array::CellType1 &cell_type, const array::Scalar &bc_mask, const array::Scalar &retreat_rate) const
array::Scalar1 m_tmp
FrontRetreat(std::shared_ptr< const Grid > g)
void compute_modified_mask(const array::CellType1 &input, array::CellType1 &output) const
array::Scalar1 sea_level_elevation
Definition Geometry.hh:48
array::Scalar2 ice_surface_elevation
Definition Geometry.hh:57
array::CellType2 cell_type
Definition Geometry.hh:55
array::Scalar2 bed_elevation
Definition Geometry.hh:47
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
void failed()
Indicates a failure of a parallel section.
VariableMetadata & long_name(const std::string &input)
VariableMetadata & units(const std::string &input)
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition Array.hh:64
void copy_from(const Array2D< T > &source)
Definition Array2D.hh:73
stencils::Star< T > star(int i, int j) const
Definition Array2D.hh:79
std::shared_ptr< const Grid > grid() const
Definition Array.cc:131
void set(double c)
Result: v[j] <- c for all j.
Definition Array.cc:629
void update_ghosts()
Updates ghost points.
Definition Array.cc:615
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
Definition Array.cc:476
bool next_to_ice(int i, int j) const
Ice-free margin (at least one of four neighbors has ice).
Definition CellType.hh:87
stencils::Star< int > star_int(int i, int j) const
Definition Scalar.hh:72
bool floating_ice(int i, int j) const
Definition CellType.hh:50
bool ice_free_ocean(int i, int j) const
Definition CellType.hh:58
bool grounded_ice(int i, int j) const
Definition CellType.hh:46
stencils::Star< int > star_int(int i, int j) const
Definition Scalar.hh:72
int as_int(int i, int j) const
Definition Scalar.hh:45
bool grounded_ice(int M)
Definition Mask.hh:51
bool floating_ice(int M)
Definition Mask.hh:54
double convert(System::Ptr system, double input, const std::string &spec1, const std::string &spec2)
Convert a quantity from unit1 to unit2.
Definition Units.cc:70
static const double g
Definition exactTestP.cc:36
void GlobalMax(MPI_Comm comm, double *local, double *result, int count)
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'...
@ MASK_ICE_FREE_OCEAN
Definition Mask.hh:35
@ North
Definition stencils.hh:24
@ East
Definition stencils.hh:24
@ South
Definition stencils.hh:24
@ West
Definition stencils.hh:24
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)