PISM, A Parallel Ice Sheet Model  stable v2.0.6 committed by Constantine Khrulev on 2023-01-23 15:14:38 -0900
StressBalance_diagnostics.cc
Go to the documentation of this file.
1 // Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 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 
20 #include "SSB_Modifier.hh"
21 #include "ShallowStressBalance.hh"
22 #include "pism/util/Mask.hh"
23 #include "pism/util/ConfigInterface.hh"
24 #include "pism/util/Vars.hh"
25 #include "pism/util/error_handling.hh"
26 #include "pism/util/pism_utilities.hh"
27 #include "pism/util/IceModelVec2CellType.hh"
28 #include "pism/rheology/FlowLaw.hh"
29 #include "pism/rheology/FlowLawFactory.hh"
30 #include "pism/util/Context.hh"
31 
32 namespace pism {
33 namespace stressbalance {
34 
36  DiagnosticList result = {
37  {"bfrict", Diagnostic::Ptr(new PSB_bfrict(this))},
38  {"velbar_mag", Diagnostic::Ptr(new PSB_velbar_mag(this))},
39  {"flux", Diagnostic::Ptr(new PSB_flux(this))},
40  {"flux_mag", Diagnostic::Ptr(new PSB_flux_mag(this))},
41  {"velbase_mag", Diagnostic::Ptr(new PSB_velbase_mag(this))},
42  {"velsurf_mag", Diagnostic::Ptr(new PSB_velsurf_mag(this))},
43  {"uvel", Diagnostic::Ptr(new PSB_uvel(this))},
44  {"vvel", Diagnostic::Ptr(new PSB_vvel(this))},
45  {"strainheat", Diagnostic::Ptr(new PSB_strainheat(this))},
46  {"velbar", Diagnostic::Ptr(new PSB_velbar(this))},
47  {"velbase", Diagnostic::Ptr(new PSB_velbase(this))},
48  {"velsurf", Diagnostic::Ptr(new PSB_velsurf(this))},
49  {"wvel", Diagnostic::Ptr(new PSB_wvel(this))},
50  {"wvelbase", Diagnostic::Ptr(new PSB_wvelbase(this))},
51  {"wvelsurf", Diagnostic::Ptr(new PSB_wvelsurf(this))},
52  {"wvel_rel", Diagnostic::Ptr(new PSB_wvel_rel(this))},
53  {"strain_rates", Diagnostic::Ptr(new PSB_strain_rates(this))},
54  {"vonmises_stress", Diagnostic::Ptr(new PSB_vonmises_stress(this))},
55  {"deviatoric_stresses", Diagnostic::Ptr(new PSB_deviatoric_stresses(this))},
56  {"pressure", Diagnostic::Ptr(new PSB_pressure(this))},
57  {"tauxz", Diagnostic::Ptr(new PSB_tauxz(this))},
58  {"tauyz", Diagnostic::Ptr(new PSB_tauyz(this))}
59  };
60 
61  if (m_config->get_flag("output.ISMIP6")) {
62  result["velmean"] = Diagnostic::Ptr(new PSB_velbar(this));
63  result["zvelbase"] = Diagnostic::Ptr(new PSB_wvelbase(this));
64  result["zvelsurf"] = Diagnostic::Ptr(new PSB_wvelsurf(this));
65  }
66 
67  // add diagnostics from the shallow stress balance and the "modifier"
68  result = pism::combine(result, m_shallow_stress_balance->diagnostics());
69  result = pism::combine(result, m_modifier->diagnostics());
70 
71  return result;
72 }
73 
75  return pism::combine(m_shallow_stress_balance->ts_diagnostics(),
76  m_modifier->ts_diagnostics());
77 }
78 
80  : Diag<StressBalance>(m) {
81 
82  auto ismip6 = m_config->get_flag("output.ISMIP6");
83 
84  // set metadata:
85  m_vars = {{m_sys, ismip6 ? "xvelmean" : "ubar"},
86  {m_sys, ismip6 ? "yvelmean" : "vbar"}};
87 
88  set_attrs("vertical mean of horizontal ice velocity in the X direction",
89  "land_ice_vertical_mean_x_velocity",
90  "m s-1", "m year-1", 0);
91  set_attrs("vertical mean of horizontal ice velocity in the Y direction",
92  "land_ice_vertical_mean_y_velocity",
93  "m s-1", "m year-1", 1);
94 }
95 
97  // get the thickness
98  const IceModelVec2S* thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
99 
100  // Compute the vertically-integrated horizontal ice flux:
101  IceModelVec2V::Ptr result = IceModelVec::cast<IceModelVec2V>(PSB_flux(model).compute());
102 
103  // Override metadata set by the flux computation
104  result->metadata(0) = m_vars[0];
105  result->metadata(1) = m_vars[1];
106 
107  IceModelVec::AccessList list{thickness, result.get()};
108 
109  for (Points p(*m_grid); p; p.next()) {
110  const int i = p.i(), j = p.j();
111  double thk = (*thickness)(i,j);
112 
113  // Ice flux is masked already, but we need to check for division
114  // by zero anyway.
115  if (thk > 0.0) {
116  (*result)(i,j) /= thk;
117  } else {
118  (*result)(i,j) = 0.0;
119  }
120  }
121 
122  return result;
123 }
124 
126  : Diag<StressBalance>(m) {
127 
128  // set metadata:
129  m_vars = {{m_sys, "velbar_mag"}};
130 
131  set_attrs("magnitude of vertically-integrated horizontal velocity of ice", "",
132  "m second-1", "m year-1", 0);
133 
134  m_vars[0]["_FillValue"] = {to_internal(m_fill_value)};
135  m_vars[0]["valid_min"] = {0.0};
136 }
137 
139 
140  IceModelVec2S::Ptr result(new IceModelVec2S(m_grid, "velbar_mag", WITHOUT_GHOSTS));
141  result->metadata(0) = m_vars[0];
142 
143  // compute vertically-averaged horizontal velocity:
144  IceModelVec2V::Ptr velbar = IceModelVec::cast<IceModelVec2V>(PSB_velbar(model).compute());
145 
146  // compute its magnitude:
147  compute_magnitude(*velbar, *result);
148 
149  const IceModelVec2S *thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
150 
151  // mask out ice-free areas:
152  apply_mask(*thickness, to_internal(m_fill_value), *result);
153 
154  return result;
155 }
156 
157 
159  : Diag<StressBalance>(m) {
160 
161  // set metadata:
162  m_vars = {{m_sys, "uflux"}, {m_sys, "vflux"}};
163 
164  set_attrs("Vertically integrated horizontal flux of ice in the X direction",
165  "", // no CF standard name
166  "m2 s-1", "m2 year-1", 0);
167  set_attrs("Vertically integrated horizontal flux of ice in the Y direction",
168  "", // no CF standard name
169  "m2 s-1", "m2 year-1", 1);
170 }
171 
173  double H_threshold = m_config->get_number("geometry.ice_free_thickness_standard");
174 
176  result->metadata(0) = m_vars[0];
177  result->metadata(1) = m_vars[1];
178 
179  // get the thickness
180  const IceModelVec2S *thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
181 
182  const IceModelVec3
183  &u3 = model->velocity_u(),
184  &v3 = model->velocity_v();
185 
186  IceModelVec::AccessList list{&u3, &v3, thickness, result.get()};
187 
188  auto &z = m_grid->z();
189 
190  ParallelSection loop(m_grid->com);
191  try {
192  for (Points p(*m_grid); p; p.next()) {
193  const int i = p.i(), j = p.j();
194 
195  double H = (*thickness)(i,j);
196 
197  // an "ice-free" cell:
198  if (H < H_threshold) {
199  (*result)(i, j) = 0.0;
200  continue;
201  }
202 
203  // an icy cell:
204  {
205  auto u = u3.get_column(i, j);
206  auto v = v3.get_column(i, j);
207 
208  Vector2 Q(0.0, 0.0);
209 
210  // ks is "k just below the surface"
211  int ks = m_grid->kBelowHeight(H);
212 
213  if (ks > 0) {
214  Vector2 v0(u[0], v[0]);
215 
216  for (int k = 1; k <= ks; ++k) {
217  Vector2 v1(u[k], v[k]);
218 
219  // trapezoid rule
220  Q += (z[k] - z[k - 1]) * 0.5 * (v0 + v1);
221 
222  v0 = v1;
223  }
224  }
225 
226  // rectangle method to integrate over the last level
227  Q += (H - z[ks]) * Vector2(u[ks], v[ks]);
228 
229  (*result)(i, j) = Q;
230  }
231  }
232  } catch (...) {
233  loop.failed();
234  }
235  loop.check();
236 
237  return result;
238 }
239 
240 
242  : Diag<StressBalance>(m) {
243 
244  // set metadata:
245  m_vars = {{m_sys, "flux_mag"}};
246 
247  set_attrs("magnitude of vertically-integrated horizontal flux of ice", "",
248  "m2 s-1", "m2 year-1", 0);
249 
250  m_vars[0]["_FillValue"] = {to_internal(m_fill_value)};
251  m_vars[0]["valid_min"] = {0.0};
252 }
253 
255  const IceModelVec2S *thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
256 
257  // Compute the vertically-averaged horizontal ice velocity:
258  auto result = IceModelVec::cast<IceModelVec2S>(PSB_velbar_mag(model).compute());
259 
260  result->metadata() = m_vars[0];
261 
262  IceModelVec::AccessList list{thickness, result.get()};
263 
264  for (Points p(*m_grid); p; p.next()) {
265  const int i = p.i(), j = p.j();
266 
267  (*result)(i,j) *= (*thickness)(i,j);
268  }
269 
270  apply_mask(*thickness, to_internal(m_fill_value), *result);
271 
272  return result;
273 }
274 
276  : Diag<StressBalance>(m) {
277 
278  // set metadata:
279  m_vars = {{m_sys, "velbase_mag"}};
280 
281  set_attrs("magnitude of horizontal velocity of ice at base of ice", "",
282  "m s-1", "m year-1", 0);
283 
284  m_vars[0]["_FillValue"] = {to_internal(m_fill_value)};
285  m_vars[0]["valid_min"] = {0.0};
286 }
287 
289  IceModelVec2S::Ptr result(new IceModelVec2S(m_grid, "velbase_mag", WITHOUT_GHOSTS));
290  result->metadata(0) = m_vars[0];
291 
292  compute_magnitude(*IceModelVec::cast<IceModelVec2V>(PSB_velbase(model).compute()), *result);
293 
294  double fill_value = to_internal(m_fill_value);
295 
296  const IceModelVec2CellType &mask = *m_grid->variables().get_2d_cell_type("mask");
297 
298  IceModelVec::AccessList list{&mask, result.get()};
299 
300  for (Points p(*m_grid); p; p.next()) {
301  const int i = p.i(), j = p.j();
302 
303  if (mask.ice_free(i, j)) {
304  (*result)(i, j) = fill_value;
305  }
306  }
307 
308  return result;
309 }
310 
312  : Diag<StressBalance>(m) {
313  // set metadata:
314  m_vars = {{m_sys, "velsurf_mag"}};
315 
316  set_attrs("magnitude of horizontal velocity of ice at ice surface", "",
317  "m s-1", "m year-1", 0);
318 
319  m_vars[0]["_FillValue"] = {to_internal(m_fill_value)};
320  m_vars[0]["valid_min"] = {0.0};
321 }
322 
324  double fill_value = to_internal(m_fill_value);
325 
326  IceModelVec2S::Ptr result(new IceModelVec2S(m_grid, "velsurf_mag", WITHOUT_GHOSTS));
327  result->metadata(0) = m_vars[0];
328 
329  compute_magnitude(*IceModelVec::cast<IceModelVec2V>(PSB_velsurf(model).compute()), *result);
330 
331  const IceModelVec2CellType &mask = *m_grid->variables().get_2d_cell_type("mask");
332 
333  IceModelVec::AccessList list{&mask, result.get()};
334 
335  for (Points p(*m_grid); p; p.next()) {
336  const int i = p.i(), j = p.j();
337 
338  if (mask.ice_free(i, j)) {
339  (*result)(i, j) = fill_value;
340  }
341  }
342 
343  return result;
344 }
345 
346 
348  : Diag<StressBalance>(m) {
349 
350  auto ismip6 = m_config->get_flag("output.ISMIP6");
351 
352  // set metadata:
353  m_vars = {{m_sys, ismip6 ? "xvelsurf" : "uvelsurf"},
354  {m_sys, ismip6 ? "yvelsurf" : "vvelsurf"}};
355 
356  set_attrs("x-component of the horizontal velocity of ice at ice surface",
357  "land_ice_surface_x_velocity", // InitMIP "standard" name
358  "m s-1", "m year-1", 0);
359  set_attrs("y-component of the horizontal velocity of ice at ice surface",
360  "land_ice_surface_y_velocity", // InitMIP "standard" name
361  "m s-1", "m year-1", 1);
362 
363  auto large_number = to_internal(1e6);
364 
365  m_vars[0]["valid_range"] = {-large_number, large_number};
366  m_vars[0]["_FillValue"] = {to_internal(m_fill_value)};
367 
368  m_vars[1]["valid_range"] = {-large_number, large_number};
369  m_vars[1]["_FillValue"] = {to_internal(m_fill_value)};
370 }
371 
373  double fill_value = to_internal(m_fill_value);
374 
376  result->metadata(0) = m_vars[0];
377  result->metadata(1) = m_vars[1];
378 
379  IceModelVec2S u_surf(m_grid, "u_surf", WITHOUT_GHOSTS);
380  IceModelVec2S v_surf(m_grid, "v_surf", WITHOUT_GHOSTS);
381 
382  const IceModelVec3
383  &u3 = model->velocity_u(),
384  &v3 = model->velocity_v();
385 
386  const IceModelVec2S *thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
387 
388  extract_surface(u3, *thickness, u_surf);
389  extract_surface(v3, *thickness, v_surf);
390 
391  const IceModelVec2CellType &mask = *m_grid->variables().get_2d_cell_type("mask");
392 
393  IceModelVec::AccessList list{&mask, &u_surf, &v_surf, result.get()};
394 
395  for (Points p(*m_grid); p; p.next()) {
396  const int i = p.i(), j = p.j();
397 
398  if (mask.ice_free(i, j)) {
399  (*result)(i, j) = fill_value;
400  } else {
401  (*result)(i, j) = {u_surf(i, j), v_surf(i, j)};
402  }
403  }
404 
405  return result;
406 }
407 
409  : Diag<StressBalance>(m) {
410 
411  // set metadata:
412  m_vars = {{m_sys, "wvel", m_grid->z()}};
413 
414  set_attrs("vertical velocity of ice, relative to geoid", "",
415  "m s-1", "m year-1", 0);
416 
417  auto large_number = to_internal(1e6);
418 
419  m_vars[0]["valid_range"] = {-large_number, large_number};
420 }
421 
423  IceModelVec3::Ptr result3(new IceModelVec3(m_grid, "wvel", WITHOUT_GHOSTS, m_grid->z()));
424  result3->metadata() = m_vars[0];
425 
426  const IceModelVec2S *bed, *uplift;
427  bed = m_grid->variables().get_2d_scalar("bedrock_altitude");
428  uplift = m_grid->variables().get_2d_scalar("tendency_of_bedrock_altitude");
429 
430  const IceModelVec2S &thickness = *m_grid->variables().get_2d_scalar("land_ice_thickness");
431  const IceModelVec2CellType &mask = *m_grid->variables().get_2d_cell_type("mask");
432 
433  const IceModelVec3
434  &u3 = model->velocity_u(),
435  &v3 = model->velocity_v(),
436  &w3 = model->velocity_w();
437 
438  IceModelVec::AccessList list{&thickness, &mask, bed, &u3, &v3, &w3, uplift, result3.get()};
439 
440  const double ice_density = m_config->get_number("constants.ice.density"),
441  sea_water_density = m_config->get_number("constants.sea_water.density"),
442  R = ice_density / sea_water_density;
443 
444  ParallelSection loop(m_grid->com);
445  try {
446  for (Points p(*m_grid); p; p.next()) {
447  const int i = p.i(), j = p.j();
448 
449  const double
450  *u = u3.get_column(i, j),
451  *v = v3.get_column(i, j),
452  *w = w3.get_column(i, j);
453  double *result = result3->get_column(i, j);
454 
455  int ks = m_grid->kBelowHeight(thickness(i,j));
456 
457  // in the ice:
458  if (mask.grounded(i,j)) {
459  const double
460  bed_dx = diff_x_p(*bed, i, j),
461  bed_dy = diff_y_p(*bed, i, j),
462  uplift_ij = (*uplift)(i,j);
463  for (int k = 0; k <= ks ; k++) {
464  result[k] = w[k] + uplift_ij + u[k] * bed_dx + v[k] * bed_dy;
465  }
466 
467  } else { // floating
468  const double
469  z_sl = R * thickness(i,j),
470  w_sl = w3.interpolate(i, j, z_sl);
471 
472  for (int k = 0; k <= ks ; k++) {
473  result[k] = w[k] - w_sl;
474  }
475 
476  }
477 
478  // above the ice:
479  if (zero_above_ice) {
480  // set to zeros
481  for (unsigned int k = ks+1; k < m_grid->Mz() ; k++) {
482  result[k] = 0.0;
483  }
484  } else {
485  // extrapolate using the topmost value
486  for (unsigned int k = ks+1; k < m_grid->Mz() ; k++) {
487  result[k] = result[ks];
488  }
489  }
490 
491  }
492  } catch (...) {
493  loop.failed();
494  }
495  loop.check();
496 
497  return result3;
498 }
499 
501  return this->compute(true); // fill wvel above the ice with zeros
502 }
503 
505  : Diag<StressBalance>(m) {
506 
507  auto ismip6 = m_config->get_flag("output.ISMIP6");
508 
509  // set metadata:
510  m_vars = {{m_sys, ismip6 ? "zvelsurf" : "wvelsurf"}};
511 
512  set_attrs("vertical velocity of ice at ice surface, relative to the geoid",
513  "land_ice_surface_upward_velocity", // InitMIP "standard" name
514  "m s-1", "m year-1", 0);
515 
516  auto large_number = to_internal(1e6);
517 
518  m_vars[0]["valid_range"] = {-large_number, large_number};
519  m_vars[0]["_FillValue"] = {to_internal(m_fill_value)};
520 }
521 
523  double fill_value = to_internal(m_fill_value);
524 
525  IceModelVec2S::Ptr result(new IceModelVec2S(m_grid, "wvelsurf", WITHOUT_GHOSTS));
526  result->metadata() = m_vars[0];
527 
528  // here "false" means "don't fill w3 above the ice surface with zeros"
529  auto w3 = IceModelVec::cast<IceModelVec3>(PSB_wvel(model).compute(false));
530 
531  const IceModelVec2S *thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
532 
533  extract_surface(*w3, *thickness, *result);
534 
535  const IceModelVec2CellType &mask = *m_grid->variables().get_2d_cell_type("mask");
536 
537  IceModelVec::AccessList list{&mask, result.get()};
538 
539  for (Points p(*m_grid); p; p.next()) {
540  const int i = p.i(), j = p.j();
541 
542  if (mask.ice_free(i, j)) {
543  (*result)(i, j) = fill_value;
544  }
545  }
546 
547  return result;
548 }
549 
551  : Diag<StressBalance>(m) {
552 
553  auto ismip6 = m_config->get_flag("output.ISMIP6");
554 
555  // set metadata:
556  m_vars = {{m_sys, ismip6 ? "zvelbase" : "wvelbase"}};
557 
558  set_attrs("vertical velocity of ice at the base of ice, relative to the geoid",
559  "land_ice_basal_upward_velocity", // InitMIP "standard" name
560  "m s-1", "m year-1", 0);
561 
562  auto large_number = to_internal(1e6);
563 
564  m_vars[0]["valid_range"] = {-large_number, large_number};
565  m_vars[0]["_FillValue"] = {to_internal(m_fill_value)};
566 }
567 
569  double fill_value = to_internal(m_fill_value);
570 
571  IceModelVec2S::Ptr result(new IceModelVec2S(m_grid, "wvelbase", WITHOUT_GHOSTS));
572  result->metadata() = m_vars[0];
573 
574  // here "false" means "don't fill w3 above the ice surface with zeros"
575  auto w3 = IceModelVec::cast<IceModelVec3>(PSB_wvel(model).compute(false));
576 
577  extract_surface(*w3, 0.0, *result);
578 
579  const IceModelVec2CellType &mask = *m_grid->variables().get_2d_cell_type("mask");
580 
581  IceModelVec::AccessList list{&mask, result.get()};
582 
583  for (Points p(*m_grid); p; p.next()) {
584  const int i = p.i(), j = p.j();
585 
586  if (mask.ice_free(i, j)) {
587  (*result)(i, j) = fill_value;
588  }
589  }
590 
591  return result;
592 }
593 
595  : Diag<StressBalance>(m) {
596 
597  auto ismip6 = m_config->get_flag("output.ISMIP6");
598 
599  // set metadata:
600  m_vars = {{m_sys, ismip6 ? "xvelbase" : "uvelbase"},
601  {m_sys, ismip6 ? "yvelbase" : "vvelbase"}};
602 
603  set_attrs("x-component of the horizontal velocity of ice at the base of ice",
604  "land_ice_basal_x_velocity", // InitMIP "standard" name
605  "m s-1", "m year-1", 0);
606  set_attrs("y-component of the horizontal velocity of ice at the base of ice",
607  "land_ice_basal_y_velocity", // InitMIP "standard" name
608  "m s-1", "m year-1", 1);
609 
610  auto fill_value = to_internal(m_fill_value);
611  auto large_number = to_internal(1e6);
612 
613  m_vars[0]["valid_range"] = {-large_number, large_number};
614  m_vars[1]["valid_range"] = {-large_number, large_number};
615 
616  m_vars[0]["_FillValue"] = {fill_value};
617  m_vars[1]["_FillValue"] = {fill_value};
618 }
619 
621  double fill_value = to_internal(m_fill_value);
622 
624  result->metadata(0) = m_vars[0];
625  result->metadata(1) = m_vars[1];
626 
627  IceModelVec2S u_base(m_grid, "u_base", WITHOUT_GHOSTS);
628  IceModelVec2S v_base(m_grid, "v_base", WITHOUT_GHOSTS);
629 
630  const IceModelVec3
631  &u3 = model->velocity_u(),
632  &v3 = model->velocity_v();
633 
634  extract_surface(u3, 0.0, u_base);
635  extract_surface(v3, 0.0, v_base);
636 
637  const IceModelVec2CellType &mask = *m_grid->variables().get_2d_cell_type("mask");
638 
639  IceModelVec::AccessList list{&mask, &u_base, &v_base, result.get()};
640 
641  for (Points p(*m_grid); p; p.next()) {
642  const int i = p.i(), j = p.j();
643 
644  if (mask.ice_free(i, j)) {
645  (*result)(i, j) = fill_value;
646  } else {
647  (*result)(i, j) = {u_base(i, j), v_base(i, j)};
648  }
649  }
650 
651  return result;
652 }
653 
654 
656  : Diag<StressBalance>(m) {
657 
658  // set metadata:
659  m_vars = {{m_sys, "bfrict"}};
660 
661  set_attrs("basal frictional heating", "",
662  "W m-2", "W m-2", 0);
663 }
664 
666 
667  IceModelVec2S::Ptr result(new IceModelVec2S(m_grid, "bfrict", WITHOUT_GHOSTS));
668  result->metadata() = m_vars[0];
669 
670  result->copy_from(model->basal_frictional_heating());
671 
672  return result;
673 }
674 
675 
677  : Diag<StressBalance>(m) {
678 
679  // set metadata:
680  m_vars = {{m_sys, "uvel", m_grid->z()}};
681 
682  set_attrs("horizontal velocity of ice in the X direction", "land_ice_x_velocity",
683  "m s-1", "m year-1", 0);
684 }
685 
686 /*!
687  * Copy F to result and set it to zero above the surface of the ice.
688  */
689 static void zero_above_ice(const IceModelVec3 &F, const IceModelVec2S &H,
690  IceModelVec3 &result) {
691 
692  IceModelVec::AccessList list{&F, &H, &result};
693 
694  IceGrid::ConstPtr grid = result.grid();
695 
696  auto Mz = grid->Mz();
697 
698  ParallelSection loop(grid->com);
699  try {
700  for (Points p(*grid); p; p.next()) {
701  const int i = p.i(), j = p.j();
702 
703  int ks = grid->kBelowHeight(H(i,j));
704 
705  const double *F_ij = F.get_column(i,j);
706  double *F_out_ij = result.get_column(i,j);
707 
708  // in the ice:
709  for (int k = 0; k <= ks ; k++) {
710  F_out_ij[k] = F_ij[k];
711  }
712  // above the ice:
713  for (unsigned int k = ks+1; k < Mz ; k++) {
714  F_out_ij[k] = 0.0;
715  }
716  }
717  } catch (...) {
718  loop.failed();
719  }
720  loop.check();
721 }
722 
724 
725  IceModelVec3::Ptr result(new IceModelVec3(m_grid, "uvel", WITHOUT_GHOSTS, m_grid->z()));
726  result->metadata() = m_vars[0];
727 
728  zero_above_ice(model->velocity_u(),
729  *m_grid->variables().get_2d_scalar("land_ice_thickness"),
730  *result);
731 
732  return result;
733 }
734 
736  : Diag<StressBalance>(m) {
737 
738  // set metadata:
739  m_vars = {{m_sys, "vvel", m_grid->z()}};
740 
741  set_attrs("horizontal velocity of ice in the Y direction", "land_ice_y_velocity",
742  "m s-1", "m year-1", 0);
743 }
744 
746 
747  IceModelVec3::Ptr result(new IceModelVec3(m_grid, "vvel", WITHOUT_GHOSTS, m_grid->z()));
748  result->metadata() = m_vars[0];
749 
750  zero_above_ice(model->velocity_v(),
751  *m_grid->variables().get_2d_scalar("land_ice_thickness"),
752  *result);
753 
754  return result;
755 }
756 
758  : Diag<StressBalance>(m) {
759 
760  // set metadata:
761  m_vars = {{m_sys, "wvel_rel", m_grid->z()}};
762 
763  set_attrs("vertical velocity of ice, relative to base of ice directly below", "",
764  "m s-1", "m year-1", 0);
765 }
766 
768 
769  IceModelVec3::Ptr result(new IceModelVec3(m_grid, "wvel_rel", WITHOUT_GHOSTS, m_grid->z()));
770  result->metadata() = m_vars[0];
771 
772  zero_above_ice(model->velocity_w(),
773  *m_grid->variables().get_2d_scalar("land_ice_thickness"),
774  *result);
775 
776  return result;
777 }
778 
779 
781  : Diag<StressBalance>(m) {
782 
783  // set metadata:
784  m_vars = {{m_sys, "strainheat", m_grid->z()}};
785 
786  set_attrs("rate of strain heating in ice (dissipation heating)", "",
787  "W m-3", "mW m-3", 0);
788 }
789 
791  IceModelVec3::Ptr result(new IceModelVec3(m_grid, "strainheat", WITHOUT_GHOSTS, m_grid->z()));
792  result->metadata() = m_vars[0];
793 
794  result->copy_from(model->volumetric_strain_heating());
795 
796  return result;
797 }
798 
800  : Diag<StressBalance>(m) {
801  // set metadata:
802  m_vars = {{m_sys, "eigen1"}, {m_sys, "eigen2"}};
803 
804  set_attrs("first eigenvalue of the horizontal, vertically-integrated strain rate tensor",
805  "", "s-1", "s-1", 0);
806  set_attrs("second eigenvalue of the horizontal, vertically-integrated strain rate tensor",
807  "", "s-1", "s-1", 1);
808 }
809 
811  auto velbar = IceModelVec::cast<IceModelVec2V>(PSB_velbar(model).compute());
812 
814  "strain_rates", WITHOUT_GHOSTS, 2));
815  result->metadata(0) = m_vars[0];
816  result->metadata(1) = m_vars[1];
817 
818  const IceModelVec2CellType &mask = *m_grid->variables().get_2d_cell_type("mask");
819 
820  IceModelVec2V velbar_with_ghosts(m_grid, "velbar", WITH_GHOSTS);
821 
822  // copy_from communicates ghosts
823  velbar_with_ghosts.copy_from(*velbar);
824 
825  compute_2D_principal_strain_rates(velbar_with_ghosts, mask, *result);
826 
827  return result;
828 }
829 
831  : Diag<StressBalance>(m) {
832  // set metadata:
833  m_vars = {{m_sys, "sigma_xx"}, {m_sys, "sigma_yy"}, {m_sys, "sigma_xy"}};
834 
835  set_attrs("deviatoric stress in X direction", "", "Pa", "Pa", 0);
836  set_attrs("deviatoric stress in Y direction", "", "Pa", "Pa", 1);
837  set_attrs("deviatoric shear stress", "", "Pa", "Pa", 2);
838 
839 }
840 
842 
844  "deviatoric_stresses",
845  WITHOUT_GHOSTS, 3));
846  result->metadata(0) = m_vars[0];
847  result->metadata(1) = m_vars[1];
848  result->metadata(2) = m_vars[2];
849 
850  const IceModelVec2CellType &cell_type = *m_grid->variables().get_2d_cell_type("mask");
851  const IceModelVec3 *enthalpy = m_grid->variables().get_3d_scalar("enthalpy");
852  const IceModelVec2S *thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
853 
854  IceModelVec2S hardness(m_grid, "hardness", WITHOUT_GHOSTS);
855  IceModelVec2V velocity(m_grid, "velocity", WITH_GHOSTS);
856 
857  averaged_hardness_vec(*model->shallow()->flow_law(), *thickness, *enthalpy,
858  hardness);
859 
860  // copy_from updates ghosts
861  velocity.copy_from(*IceModelVec::cast<IceModelVec2V>(PSB_velbar(model).compute()));
862 
863  stressbalance::compute_2D_stresses(*model->shallow()->flow_law(),
864  velocity, hardness, cell_type, *result);
865 
866  return result;
867 }
868 
870  : Diag<StressBalance>(m) {
871 
872  // set metadata:
873  m_vars = {{m_sys, "pressure", m_grid->z()}};
874 
875  set_attrs("pressure in ice (hydrostatic)", "", "Pa", "Pa", 0);
876 }
877 
879 
880  IceModelVec3::Ptr result(new IceModelVec3(m_grid, "pressure", WITHOUT_GHOSTS, m_grid->z()));
881  result->metadata(0) = m_vars[0];
882 
883  const IceModelVec2S *thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
884 
885  IceModelVec::AccessList list{thickness, result.get()};
886 
887  const double rg = m_config->get_number("constants.ice.density") * m_config->get_number("constants.standard_gravity");
888 
889  ParallelSection loop(m_grid->com);
890  try {
891  for (Points p(*m_grid); p; p.next()) {
892  const int i = p.i(), j = p.j();
893 
894  unsigned int ks = m_grid->kBelowHeight((*thickness)(i,j));
895  double *P_out_ij = result->get_column(i,j);
896  const double H = (*thickness)(i,j);
897  // within the ice:
898  for (unsigned int k = 0; k <= ks; ++k) {
899  P_out_ij[k] = rg * (H - m_grid->z(k)); // FIXME: add atmospheric pressure?
900  }
901  // above the ice:
902  for (unsigned int k = ks + 1; k < m_grid->Mz(); ++k) {
903  P_out_ij[k] = 0.0; // FIXME: use atmospheric pressure?
904  }
905  }
906  } catch (...) {
907  loop.failed();
908  }
909  loop.check();
910 
911  return result;
912 }
913 
914 
916  : Diag<StressBalance>(m) {
917 
918  // set metadata:
919  m_vars = {{m_sys, "tauxz", m_grid->z()}};
920 
921  set_attrs("shear stress xz component (in shallow ice approximation SIA)", "",
922  "Pa", "Pa", 0);
923 }
924 
925 
926 /*!
927  * The SIA-applicable shear stress component tauxz computed here is not used
928  * by the model. This implementation intentionally does not use the
929  * eta-transformation or special cases at ice margins.
930  * CODE DUPLICATION WITH PSB_tauyz
931  */
933 
934  IceModelVec3::Ptr result(new IceModelVec3(m_grid, "tauxz", WITHOUT_GHOSTS, m_grid->z()));
935  result->metadata() = m_vars[0];
936 
937  const IceModelVec2S *thickness, *surface;
938 
939  thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
940  surface = m_grid->variables().get_2d_scalar("surface_altitude");
941 
942  IceModelVec::AccessList list{surface, thickness, result.get()};
943 
944  const double rg = m_config->get_number("constants.ice.density") * m_config->get_number("constants.standard_gravity");
945 
946  ParallelSection loop(m_grid->com);
947  try {
948  for (Points p(*m_grid); p; p.next()) {
949  const int i = p.i(), j = p.j();
950 
951  unsigned int ks = m_grid->kBelowHeight((*thickness)(i,j));
952  double *tauxz_out_ij = result->get_column(i, j);
953  const double
954  H = (*thickness)(i,j),
955  dhdx = diff_x_p(*surface, i,j);
956 
957  // within the ice:
958  for (unsigned int k = 0; k <= ks; ++k) {
959  tauxz_out_ij[k] = - rg * (H - m_grid->z(k)) * dhdx;
960  }
961  // above the ice:
962  for (unsigned int k = ks + 1; k < m_grid->Mz(); ++k) {
963  tauxz_out_ij[k] = 0.0;
964  }
965  }
966  } catch (...) {
967  loop.failed();
968  }
969  loop.check();
970 
971  return result;
972 }
973 
974 
976  : Diag<StressBalance>(m) {
977 
978  // set metadata:
979  m_vars = {{m_sys, "tauyz", m_grid->z()}};
980 
981  set_attrs("shear stress yz component (in shallow ice approximation SIA)", "",
982  "Pa", "Pa", 0);
983 }
984 
985 
986 /*!
987  * The SIA-applicable shear stress component tauyz computed here is not used
988  * by the model. This implementation intentionally does not use the
989  * eta-transformation or special cases at ice margins.
990  * CODE DUPLICATION WITH PSB_tauxz
991  */
993 
994  IceModelVec3::Ptr result(new IceModelVec3(m_grid, "tauyz", WITHOUT_GHOSTS, m_grid->z()));
995  result->metadata(0) = m_vars[0];
996 
997  const IceModelVec2S *thickness = m_grid->variables().get_2d_scalar("land_ice_thickness");
998  const IceModelVec2S *surface = m_grid->variables().get_2d_scalar("surface_altitude");
999 
1000  IceModelVec::AccessList list{surface, thickness, result.get()};
1001 
1002  const double rg = m_config->get_number("constants.ice.density") * m_config->get_number("constants.standard_gravity");
1003 
1004  ParallelSection loop(m_grid->com);
1005  try {
1006  for (Points p(*m_grid); p; p.next()) {
1007  const int i = p.i(), j = p.j();
1008 
1009  unsigned int ks = m_grid->kBelowHeight((*thickness)(i,j));
1010  double *tauyz_out_ij = result->get_column(i, j);
1011  const double
1012  H = (*thickness)(i,j),
1013  dhdy = diff_y_p(*surface, i,j);
1014 
1015  // within the ice:
1016  for (unsigned int k = 0; k <= ks; ++k) {
1017  tauyz_out_ij[k] = - rg * (H - m_grid->z(k)) * dhdy;
1018  }
1019  // above the ice:
1020  for (unsigned int k = ks + 1; k < m_grid->Mz(); ++k) {
1021  tauyz_out_ij[k] = 0.0;
1022  }
1023  }
1024  } catch (...) {
1025  loop.failed();
1026  }
1027  loop.check();
1028 
1029  return result;
1030 }
1031 
1033  : Diag<StressBalance>(m) {
1034 
1035  /* set metadata: */
1036  m_vars = {{m_sys, "vonmises_stress"}};
1037 
1038  set_attrs("tensile von Mises stress",
1039  "", // no standard name
1040  "Pascal", "Pascal", 0);
1041 }
1042 
1044 
1045  using std::max;
1046  using std::sqrt;
1047  using std::pow;
1048 
1049  IceModelVec2S::Ptr result(new IceModelVec2S(m_grid, "vonmises_stress", WITHOUT_GHOSTS));
1050  result->metadata(0) = m_vars[0];
1051 
1052  IceModelVec2S &vonmises_stress = *result;
1053 
1054  auto velbar = IceModelVec::cast<IceModelVec2V>(PSB_velbar(model).compute());
1055  IceModelVec2V &velocity = *velbar;
1056 
1057  auto eigen12 = IceModelVec::cast<IceModelVec3>(PSB_strain_rates(model).compute());
1058  IceModelVec3 &strain_rates = *eigen12;
1059 
1060  const IceModelVec2S &ice_thickness = *m_grid->variables().get_2d_scalar("land_ice_thickness");
1061  const IceModelVec3 *enthalpy = m_grid->variables().get_3d_scalar("enthalpy");
1062  const IceModelVec2CellType &mask = *m_grid->variables().get_2d_cell_type("mask");
1063 
1064  std::shared_ptr<const rheology::FlowLaw> flow_law;
1065 
1066  if (m_config->get_flag("calving.vonmises_calving.use_custom_flow_law")) {
1067  EnthalpyConverter::Ptr EC = m_grid->ctx()->enthalpy_converter();
1068  rheology::FlowLawFactory factory("calving.vonmises_calving.", m_config, EC);
1069  flow_law = factory.create();
1070  } else {
1071  flow_law = model->shallow()->flow_law();
1072  }
1073 
1074  const double *z = &m_grid->z()[0];
1075 
1076  double glen_exponent = flow_law->exponent();
1077 
1078  IceModelVec::AccessList list{&vonmises_stress, &velocity, &strain_rates, &ice_thickness,
1079  enthalpy, &mask};
1080 
1081  for (Points pt(*m_grid); pt; pt.next()) {
1082  const int i = pt.i(), j = pt.j();
1083 
1084  if (mask.icy(i, j)) {
1085 
1086  const double H = ice_thickness(i, j);
1087  const unsigned int k = m_grid->kBelowHeight(H);
1088 
1089  const double
1090  *enthalpy_column = enthalpy->get_column(i, j),
1091  hardness = averaged_hardness(*flow_law, H, k, z, enthalpy_column),
1092  eigen1 = strain_rates(i, j, 0),
1093  eigen2 = strain_rates(i, j, 1);
1094 
1095  // [\ref Morlighem2016] equation 6
1096  const double effective_tensile_strain_rate = sqrt(0.5 * (pow(max(0.0, eigen1), 2) +
1097  pow(max(0.0, eigen2), 2)));
1098  // [\ref Morlighem2016] equation 7
1099  vonmises_stress(i, j) = sqrt(3.0) * hardness * pow(effective_tensile_strain_rate,
1100  1.0 / glen_exponent);
1101 
1102  } else { // end of "if (mask.icy(i, j))"
1103  vonmises_stress(i, j) = 0.0;
1104  }
1105  } // end of loop over grid points
1106 
1107  return result;
1108 }
1109 
1110 } // end of namespace stressbalance
1111 } // end of namespace pism
Makes sure that we call begin_access() and end_access() for all accessed IceModelVecs.
Definition: iceModelVec.hh:59
const Config::ConstPtr m_config
configuration database used by this component
Definition: Component.hh:138
const StressBalance * model
Definition: Diagnostic.hh:166
A template derived from Diagnostic, adding a "Model".
Definition: Diagnostic.hh:161
IceModelVec::Ptr compute() const
Compute a diagnostic quantity and return a pointer to a newly-allocated IceModelVec.
Definition: Diagnostic.cc:166
double m_fill_value
fill value (used often enough to justify storing it)
Definition: Diagnostic.hh:114
const units::System::Ptr m_sys
the unit system
Definition: Diagnostic.hh:108
double to_internal(double x) const
Definition: Diagnostic.cc:58
std::vector< SpatialVariableMetadata > m_vars
metadata corresponding to NetCDF variables
Definition: Diagnostic.hh:112
std::shared_ptr< Diagnostic > Ptr
Definition: Diagnostic.hh:64
IceGrid::ConstPtr m_grid
the grid
Definition: Diagnostic.hh:106
void set_attrs(const std::string &long_name, const std::string &standard_name, const std::string &units, const std::string &glaciological_units, unsigned int N=0)
A method for setting common variable attributes.
Definition: Diagnostic.cc:132
const Config::ConstPtr m_config
Configuration flags and parameters.
Definition: Diagnostic.hh:110
std::shared_ptr< EnthalpyConverter > Ptr
std::shared_ptr< const IceGrid > ConstPtr
Definition: IceGrid.hh:233
bool icy(int i, int j) const
bool grounded(int i, int j) const
bool ice_free(int i, int j) const
"Cell type" mask. Adds convenience methods to IceModelVec2Int.
std::shared_ptr< IceModelVec2S > Ptr
Definition: iceModelVec.hh:341
std::shared_ptr< IceModelVec2V > Ptr
void copy_from(const IceModelVec2< T > &source)
Definition: IceModelVec2.hh:97
std::shared_ptr< IceModelVec3 > Ptr
Definition: iceModelVec.hh:423
double * get_column(int i, int j)
A virtual class collecting methods common to ice and bedrock 3D fields.
Definition: iceModelVec.hh:404
std::shared_ptr< IceModelVec > Ptr
Definition: iceModelVec.hh:206
IceGrid::ConstPtr grid() const
Definition: iceModelVec.cc:128
void failed()
Indicates a failure of a parallel section.
This class represents a 2D vector field (such as ice velocity) at a certain grid point.
Definition: Vector2.hh:29
std::shared_ptr< FlowLaw > create()
virtual IceModelVec::Ptr compute_impl() const
Computes basal frictional heating.
Reports the vertically-integrated (2D) deviatoric stresses.
virtual IceModelVec::Ptr compute_impl() const
Computes flux_mag, the magnitude of vertically-integrated horizontal flux of ice.
virtual IceModelVec::Ptr compute_impl() const
Computes uflux and vflux, components of vertically-integrated horizontal flux of ice.
virtual IceModelVec::Ptr compute_impl() const
Reports the pressure within the ice (3D).
virtual IceModelVec::Ptr compute_impl() const
Reports the vertically-integrated (2D) principal strain rates.
virtual IceModelVec::Ptr compute_impl() const
Reports the volumetric strain heating (3D).
virtual IceModelVec::Ptr compute_impl() const
Reports the xz component of the shear stress within the ice (3D), according to the SIA formula.
virtual IceModelVec::Ptr compute_impl() const
Reports the yz component of the shear stress within the ice (3D), according to the SIA formula.
virtual IceModelVec::Ptr compute_impl() const
Computes the x-component of the horizontal ice velocity.
virtual IceModelVec::Ptr compute_impl() const
Computes velbar_mag, the magnitude of vertically-integrated horizontal velocity of ice and masks out ...
virtual IceModelVec::Ptr compute_impl() const
Computes the vertically-averaged ice velocity.
virtual IceModelVec::Ptr compute_impl() const
Computes velbase_mag, the magnitude of horizontal velocity of ice at base of ice and masks out ice-fr...
virtual IceModelVec::Ptr compute_impl() const
Computes horizontal ice velocity at the base of ice.
virtual IceModelVec::Ptr compute_impl() const
Computes velsurf_mag, the magnitude of horizontal ice velocity at the surface.
virtual IceModelVec::Ptr compute_impl() const
Computes velsurf, the horizontal velocity of ice at ice surface.
virtual IceModelVec::Ptr compute_impl() const
Computes the y-component of the horizontal ice velocity.
virtual IceModelVec::Ptr compute_impl() const
Computes vertical velocity of ice, relative to the bed directly below.
virtual IceModelVec::Ptr compute_impl() const
Computes vertical ice velocity (relative to the geoid).
virtual IceModelVec::Ptr compute_impl() const
Computes wvelbase, the vertical velocity of ice at the base of ice.
virtual IceModelVec::Ptr compute_impl() const
Computes wvelsurf, the vertical velocity of ice at ice surface.
std::shared_ptr< SSB_Modifier > m_modifier
virtual TSDiagnosticList ts_diagnostics_impl() const
std::shared_ptr< ShallowStressBalance > m_shallow_stress_balance
virtual DiagnosticList diagnostics_impl() const
The class defining PISM's interface to the shallow stress balance code.
double averaged_hardness(const FlowLaw &ice, double thickness, int kbelowH, const double *zlevels, const double *enthalpy)
Computes vertical average of B(E, p) ice hardness, namely .
Definition: FlowLaw.cc:214
void averaged_hardness_vec(const FlowLaw &ice, const IceModelVec2S &thickness, const IceModelVec3 &enthalpy, IceModelVec2S &result)
Definition: FlowLaw.cc:182
void compute_2D_stresses(const rheology::FlowLaw &flow_law, const IceModelVec2V &velocity, const IceModelVec2S &hardness, const IceModelVec2CellType &cell_type, IceModelVec3 &result)
Compute 2D deviatoric stresses.
void compute_2D_principal_strain_rates(const IceModelVec2V &V, const IceModelVec2CellType &mask, IceModelVec3 &result)
Compute eigenvalues of the horizontal, vertically-integrated strain rate tensor.
static void zero_above_ice(const IceModelVec3 &F, const IceModelVec2S &H, IceModelVec3 &result)
void apply_mask(const IceModelVec2S &M, double fill, IceModelVec2S &result)
Masks out all the areas where by setting them to fill.
double max(const IceModelVec2S &input)
Finds maximum over all the values in an IceModelVec2S object. Ignores ghosts.
static double F(double SL, double B, double H, double alpha)
void compute_magnitude(const IceModelVec2S &v_x, const IceModelVec2S &v_y, IceModelVec2S &result)
Sets an IceModelVec2 to the magnitude of a 2D vector field with components v_x and v_y.
Definition: iceModelVec2.cc:80
double diff_x_p(const IceModelVec2S &array, int i, int j)
Returns the x-derivative at i,j approximated using centered finite differences. Respects grid periodi...
void extract_surface(const IceModelVec3 &data, double z, IceModelVec2S &output)
Copies a horizontal slice at level z of an IceModelVec3 into an IceModelVec2S gslice.
std::map< std::string, TSDiagnostic::Ptr > TSDiagnosticList
Definition: Diagnostic.hh:346
std::map< std::string, Diagnostic::Ptr > DiagnosticList
Definition: Diagnostic.hh:117
static const double v0
Definition: exactTestP.cc:53
static const double k
Definition: exactTestP.cc:45
T combine(const T &a, const T &b)
double diff_y_p(const IceModelVec2S &array, int i, int j)
Returns the y-derivative at i,j approximated using centered finite differences. Respects grid periodi...
@ WITHOUT_GHOSTS
Definition: iceModelVec.hh:49
@ WITH_GHOSTS
Definition: iceModelVec.hh:49