PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
frontretreat.cc
Go to the documentation of this file.
1 // Copyright (C) 2004--2021, 2023 Torsten Albrecht and Constantine Khroulev
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/icemodel/IceModel.hh"
20 
21 #include "pism/util/ConfigInterface.hh"
22 #include "pism/util/Grid.hh"
23 
24 #include "pism/frontretreat/FrontRetreat.hh"
25 #include "pism/frontretreat/calving/CalvingAtThickness.hh"
26 #include "pism/frontretreat/calving/EigenCalving.hh"
27 #include "pism/frontretreat/calving/FloatKill.hh"
28 #include "pism/frontretreat/calving/HayhurstCalving.hh"
29 #include "pism/frontretreat/calving/vonMisesCalving.hh"
30 
31 #include "pism/energy/EnergyModel.hh"
32 #include "pism/coupler/FrontalMelt.hh"
33 #include "pism/stressbalance/ShallowStressBalance.hh"
34 #include "pism/hydrology/Hydrology.hh"
35 #include "pism/frontretreat/util/remove_narrow_tongues.hh"
36 #include "pism/frontretreat/PrescribedRetreat.hh"
37 #include "pism/util/ScalarForcing.hh"
38 #include "pism/util/label_components.hh"
39 
40 namespace pism {
41 
43 
44  auto &tmp_p0 = *m_work2d_proc0;
45 
46  array::AccessScope list{ &cell_type, &result };
47 
48  auto grid = cell_type.grid();
49 
50  // assume that ice-free ocean points at the edge of the domain belong to the "global
51  // ocean"
52  for (auto p = grid->points(); p; p.next()) {
53  const int i = p.i(), j = p.j();
54 
55  if (cell_type.ice_free_ocean(i, j)) {
56  result(i, j) = 1.0;
57 
58  if (grid::domain_edge(*grid, i, j)) {
59  result(i, j) = 2.0;
60  }
61  } else {
62  result(i, j) = 0.0;
63  }
64  }
65 
66  label_components(result, tmp_p0, true, 2);
67 
68  // now `result` contains ones in "ice free ocean" cells that are not connected to the edge
69  // of the domain and zeros elsewhere
70 
71  // create a mask that contains ones at "ice free ocean" locations connected to the edge
72  // of the domain and zeros elsewhere:
73  for (auto p = grid->points(); p; p.next()) {
74  const int i = p.i(), j = p.j();
75 
76  if (cell_type.ice_free_ocean(i, j) and result(i, j) < 0.5) {
77  result(i, j) = 1;
78  } else {
79  result(i, j) = 0;
80  }
81  }
82 
83  result.update_ghosts();
84 }
85 
87 
88  bool retreat_rate_based_calving = m_eigen_calving or m_vonmises_calving or m_hayhurst_calving;
89  bool calving_is_active =
90  retreat_rate_based_calving or m_float_kill_calving or m_thickness_threshold_calving;
91  bool frontal_melt_only_open_ocean = m_config->get_flag("frontal_melt.open_ocean_margins_only");
92 
93  auto &open_ocean_mask = *m_work2d[3];
94  if (calving_is_active or (m_frontal_melt and frontal_melt_only_open_ocean)) {
95  identify_open_ocean(m_geometry.cell_type, open_ocean_mask);
96  } else {
97  open_ocean_mask.set(1.0);
98  }
99 
100  // compute retreat rates due to eigencalving, von Mises calving, Hayhurst calving,
101  // and frontal melt.
102  // We do this first to make sure that all three mechanisms use the same ice geometry.
103  {
104  if (m_eigen_calving) {
106  m_stress_balance->shallow()->velocity());
107  }
108 
109  if (m_hayhurst_calving) {
114  }
115 
116  if (m_vonmises_calving) {
117  // FIXME: consider computing vertically-averaged hardness here and providing that
118  // instead of using ice thickness and enthalpy.
121  m_stress_balance->shallow()->velocity(),
122  m_energy_model->enthalpy());
123  }
124 
125  if (m_frontal_melt) {
126  array::Scalar &flux_magnitude = *m_work2d[0];
127 
128  compute_magnitude(m_subglacial_hydrology->flux(), flux_magnitude);
129 
130  FrontalMeltInputs inputs;
131 
132  inputs.geometry = &m_geometry;
133  inputs.subglacial_water_flux = &flux_magnitude;
134 
135  m_frontal_melt->update(inputs, m_time->current(), m_dt);
136  }
137  }
138 
140  &old_H = *m_work2d[0],
141  &old_Href = *m_work2d[1];
142 
143  // frontal melt
144  if (m_frontal_melt) {
145  assert(m_front_retreat);
146 
148  old_Href.copy_from(m_geometry.ice_area_specific_volume);
149 
150  array::Scalar &retreat_rate = *m_work2d[2];
151  retreat_rate.copy_from(m_frontal_melt->retreat_rate());
152 
153  if (frontal_melt_only_open_ocean) {
154  array::AccessScope list{ &retreat_rate, &open_ocean_mask };
155 
156  for (Points p(*m_grid); p; p.next()) {
157  const int i = p.i(), j = p.j();
158 
159  if (open_ocean_mask(i, j) < 0.5) {
160  retreat_rate(i, j) = 0.0;
161  }
162  }
163  }
164 
165  // apply the frontal melt rate
167  retreat_rate,
170  bool add_values = false;
173  old_H, old_Href,
174  add_values,
176  } else {
178  }
179 
180  // calving
181  if (calving_is_active) {
182 
184  old_Href.copy_from(m_geometry.ice_area_specific_volume);
185 
186  // retreat-rate-based calving parameterizations:
187  if (retreat_rate_based_calving) {
188  assert(m_front_retreat);
189 
190  array::Scalar &retreat_rate = *m_work2d[2];
191  retreat_rate.set(0.0);
192 
193  if (m_eigen_calving) {
194  retreat_rate.add(1.0, m_eigen_calving->calving_rate());
195  }
196 
197  if (m_hayhurst_calving) {
198  retreat_rate.add(1.0, m_hayhurst_calving->calving_rate());
199  }
200 
201  if (m_vonmises_calving) {
202  retreat_rate.add(1.0, m_vonmises_calving->calving_rate());
203  }
204 
205  if (m_calving_rate_factor) {
206  double T = m_time->current() + 0.5 * m_dt;
207  retreat_rate.scale(m_calving_rate_factor->value(T));
208  }
209 
210  // modify the retreat rate to avoid calving into "holes" in ice shelves that are not
211  // connected to the open ocean
212  {
213  array::AccessScope list{ &open_ocean_mask, &retreat_rate };
214 
215  for (Points p(*m_grid); p; p.next()) {
216  const int i = p.i(), j = p.j();
217 
218  if (open_ocean_mask(i, j) < 0.5) {
219  retreat_rate(i, j) = 0.0;
220  }
221  }
222  }
223 
225  retreat_rate,
228 
229  auto thickness_threshold = m_config->get_number("stress_balance.ice_free_thickness_standard");
230 
231  m_geometry.ensure_consistency(thickness_threshold);
232 
235 
236  m_geometry.ensure_consistency(thickness_threshold);
237  }
238  }
239 
240  // calving using local geometry (usually calving one grid cell per time step)
241  {
242  auto &modified_cell_type = *m_work2d[2];
243 
244  // create a modified cell type mask to avoid calving into holes in ice shelves that
245  // are not connected to the open ocean
246  {
247  const auto &cell_type = m_geometry.cell_type;
248 
249  array::AccessScope list{ &modified_cell_type, &cell_type, &open_ocean_mask };
250 
251  for (Points p(*m_grid); p; p.next()) {
252  const int i = p.i(), j = p.j();
253 
254  if (cell_type.ice_free_ocean(i, j) and open_ocean_mask(i, j) < 0.5) {
255  // This modification will ensure that cells next to *these* ice free ocean
256  // cells will not be considered "marginal" and so thickness threshold and
257  // float-kill parameterizations will not apply.
258  modified_cell_type(i, j) = MASK_UNKNOWN;
259  } else {
260  modified_cell_type(i, j) = cell_type(i, j);
261  }
262  }
263  }
264 
265  if (m_float_kill_calving) {
266  m_float_kill_calving->update(modified_cell_type, m_geometry.ice_thickness);
267  }
268 
270  m_thickness_threshold_calving->update(m_time->current(), m_dt, modified_cell_type,
272  }
273  }
274 
275  bool add_values = false;
278  old_H, old_Href,
279  add_values,
281  } else {
283  }
284 
285  // prescribed retreat
286 
287  if (m_prescribed_retreat) {
289  old_Href.copy_from(m_geometry.ice_area_specific_volume);
290 
291  m_prescribed_retreat->update(m_time->current(), m_dt,
294 
295  bool add_values = false;
298  old_H, old_Href,
299  add_values,
301 
302  } else {
304  }
305 
306  // Changes above may create icebergs; here we remove them and account for additional
307  // mass losses.
308  {
310  old_Href.copy_from(m_geometry.ice_area_specific_volume);
311 
313 
314  bool add_values = true;
317  old_H, old_Href,
318  add_values,
320  }
321 }
322 
323 /**
324  * Compute the change in ice geometry from "old" to "current".
325  *
326  * Units: ice equivalent meters.
327  *
328  * @param thickness current ice thickness
329  * @param Href current "reference ice thickness"
330  * @param thickness_old old ice thickness
331  * @param Href_old old "reference ice thickness"
332  * @param[in] add_values if `true`, add computed values to `output`, otherwise
333  * overwrite them
334  * @param[in,out] output computed change
335  */
337  const array::Scalar &Href,
338  const array::Scalar &thickness_old,
339  const array::Scalar &Href_old,
340  bool add_values,
341  array::Scalar &output) {
342 
343  array::AccessScope list{&thickness, &thickness_old,
344  &Href, &Href_old, &output};
345 
346  for (auto p = m_grid->points(); p; p.next()) {
347  const int i = p.i(), j = p.j();
348 
349  const double
350  H_old = thickness_old(i, j) + Href_old(i, j),
351  H_new = thickness(i, j) + Href(i, j),
352  change = H_new - H_old;
353 
354  if (add_values) {
355  output(i, j) += change;
356  } else {
357  output(i, j) = change;
358  }
359  }
360 }
361 
362 } // end of namespace pism
const Geometry * geometry
Definition: FrontalMelt.hh:32
const array::Scalar * subglacial_water_flux
Definition: FrontalMelt.hh:35
array::Scalar1 sea_level_elevation
Definition: Geometry.hh:48
void ensure_consistency(double ice_free_thickness_threshold)
Definition: Geometry.cc:112
array::Scalar1 ice_area_specific_volume
Definition: Geometry.hh:52
array::CellType2 cell_type
Definition: Geometry.hh:55
array::Scalar2 ice_thickness
Definition: Geometry.hh:51
array::Scalar2 bed_elevation
Definition: Geometry.hh:47
void enforce_consistency_of_geometry(ConsistencyFlag flag)
Update the surface elevation and the flow-type mask when the geometry has changed.
Definition: IceModel.cc:293
void compute_geometry_change(const array::Scalar &thickness, const array::Scalar &Href, const array::Scalar &thickness_old, const array::Scalar &Href_old, bool add_values, array::Scalar &output)
std::shared_ptr< stressbalance::StressBalance > m_stress_balance
Definition: IceModel.hh:397
std::shared_ptr< petsc::Vec > m_work2d_proc0
Definition: IceModel.hh:395
const Config::Ptr m_config
Configuration flags and parameters.
Definition: IceModel.hh:243
ThicknessChanges m_thickness_change
Definition: IceModel.hh:412
const Time::Ptr m_time
Time manager.
Definition: IceModel.hh:251
Geometry m_geometry
Definition: IceModel.hh:295
std::shared_ptr< frontalmelt::FrontalMelt > m_frontal_melt
Definition: IceModel.hh:288
std::shared_ptr< Grid > grid() const
Return the grid used by this model.
Definition: utilities.cc:122
virtual void front_retreat_step()
Definition: frontretreat.cc:86
std::shared_ptr< calving::EigenCalving > m_eigen_calving
Definition: IceModel.hh:275
std::unique_ptr< ScalarForcing > m_calving_rate_factor
Definition: IceModel.hh:282
std::vector< std::shared_ptr< array::Scalar2 > > m_work2d
Definition: IceModel.hh:393
std::shared_ptr< calving::CalvingAtThickness > m_thickness_threshold_calving
Definition: IceModel.hh:274
std::shared_ptr< calving::FloatKill > m_float_kill_calving
Definition: IceModel.hh:273
void identify_open_ocean(const array::CellType &cell_type, array::Scalar &result)
Definition: frontretreat.cc:42
std::shared_ptr< PrescribedRetreat > m_prescribed_retreat
Definition: IceModel.hh:278
std::shared_ptr< calving::HayhurstCalving > m_hayhurst_calving
Definition: IceModel.hh:276
array::Scalar1 m_ice_thickness_bc_mask
Mask prescribing locations where ice thickness is held constant.
Definition: IceModel.hh:314
std::unique_ptr< hydrology::Hydrology > m_subglacial_hydrology
Definition: IceModel.hh:261
std::shared_ptr< calving::vonMisesCalving > m_vonmises_calving
Definition: IceModel.hh:277
double m_dt
mass continuity time step, s
Definition: IceModel.hh:318
std::shared_ptr< energy::EnergyModel > m_energy_model
Definition: IceModel.hh:267
const std::shared_ptr< Grid > m_grid
Computational grid.
Definition: IceModel.hh:241
std::shared_ptr< FrontRetreat > m_front_retreat
Definition: IceModel.hh:284
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition: Array.hh:65
void copy_from(const Array2D< T > &source)
Definition: Array2D.hh:73
void add(double alpha, const Array2D< T > &x)
Definition: Array2D.hh:65
void scale(double alpha)
Result: v <- v * alpha. Calls VecScale.
Definition: Array.cc:253
std::shared_ptr< const Grid > grid() const
Definition: Array.cc:132
void set(double c)
Result: v[j] <- c for all j.
Definition: Array.cc:707
void update_ghosts()
Updates ghost points.
Definition: Array.cc:693
bool ice_free_ocean(int i, int j) const
Definition: CellType.hh:58
"Cell type" mask. Adds convenience methods to array::Scalar.
Definition: CellType.hh:30
void compute_magnitude(const array::Vector &input, array::Scalar &result)
Definition: Scalar.cc:66
bool domain_edge(const Grid &grid, int i, int j)
Definition: Grid.hh:396
void remove_narrow_tongues(const Geometry &geometry, array::Scalar &ice_thickness)
@ MASK_UNKNOWN
Definition: Mask.hh:31
void label_components(array::Scalar &mask, petsc::Vec &mask_p0, bool identify_icebergs, double mask_grounded)