PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
DischargeRouting.cc
Go to the documentation of this file.
1// Copyright (C) 2018, 2019, 2021, 2022, 2023, 2024, 2025 Andy Aschwanden 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/coupler/frontalmelt/DischargeRouting.hh"
20
21#include "pism/util/Grid.hh"
22#include "pism/geometry/Geometry.hh"
23#include "pism/coupler/util/options.hh"
24#include "pism/coupler/frontalmelt/FrontalMeltPhysics.hh"
25#include "pism/util/array/Forcing.hh"
26#include "pism/util/Logger.hh"
27#include "pism/util/io/IO_Flags.hh"
28
29namespace pism {
30namespace frontalmelt {
31
32DischargeRouting::DischargeRouting(std::shared_ptr<const Grid> grid)
33 : FrontalMelt(grid, nullptr),
34 m_frontal_melt_rate(grid, "frontal_melt_rate") {
35
37 .long_name("frontal melt rate")
38 .units("m s^-1")
39 .output_units("m day^-1");
40
41 m_log->message(2, "* Initializing the frontal melt model\n"
42 " using the Rignot/Xu parameterization\n"
43 " and routing of subglacial discharge\n");
44
45 m_theta_ocean = array::Forcing::Constant(grid, "theta_ocean", 0.0);
46}
47
49 (void)geometry;
50
51 ForcingOptions opt(*m_grid->ctx(), "frontal_melt.routing");
52
53 {
54 unsigned int buffer_size = m_config->get_number("input.forcing.buffer_size");
55
57
58 m_theta_ocean = std::make_shared<array::Forcing>(m_grid, file, "theta_ocean",
59 "", // no standard name
60 buffer_size, opt.periodic, LINEAR);
61 }
62
63 m_theta_ocean->metadata(0)
64 .long_name("potential temperature of the adjacent ocean")
65 .units("degree_Celsius");
66
67 m_theta_ocean->init(opt.filename, opt.periodic);
68}
69
70/*!
71 * Initialize potential temperature from an array instead of an input
72 * file (for testing).
73 */
75 m_theta_ocean->copy_from(theta);
76}
77
78void DischargeRouting::update_impl(const FrontalMeltInputs &inputs, double t, double dt) {
79
80 m_theta_ocean->update(t, dt);
81
83
84 const auto &cell_type = inputs.geometry->cell_type;
85 const array::Scalar &bed_elevation = inputs.geometry->bed_elevation;
86 const array::Scalar &ice_thickness = inputs.geometry->ice_thickness;
87 const array::Scalar &sea_level_elevation = inputs.geometry->sea_level_elevation;
88 const array::Scalar &water_flux = *inputs.subglacial_water_flux;
89
90 array::AccessScope list{ &ice_thickness, &bed_elevation, &cell_type,
91 &sea_level_elevation, &water_flux, m_theta_ocean.get(),
93
94 double seconds_per_day = 86400, grid_spacing = 0.5 * (m_grid->dx() + m_grid->dy());
95
96 for (auto p : m_grid->points()) {
97 const int i = p.i(), j = p.j();
98
99 if (cell_type.icy(i, j)) {
100 // Assume for now that thermal forcing is equal to theta_ocean. Also, thermal
101 // forcing is generally not available at the grounding line.
102 double TF = (*m_theta_ocean)(i, j);
103
104 double water_depth = std::max(sea_level_elevation(i, j) - bed_elevation(i, j), 0.0),
105 submerged_front_area = water_depth * grid_spacing;
106
107 // Convert subglacial water flux (m^2/s) to an "effective subglacial freshwater
108 // velocity" or flux per unit area of ice front in m/day (see Xu et al 2013, section
109 // 2, paragraph 11).
110 //
111 // [flux] = m^2 / s, so
112 // [flux * grid_spacing] = m^3 / s, so
113 // [flux * grid_spacing / submerged_front_area] = m / s, and
114 // [flux * grid_spacing * (s / day) / submerged_front_area] = m / day
115 double Q_sg = water_flux(i, j) * grid_spacing;
116 double q_sg = Q_sg / submerged_front_area * seconds_per_day;
117
118 m_frontal_melt_rate(i, j) = physics.frontal_melt_from_undercutting(water_depth, q_sg, TF);
119 // convert from m / day to m / s
120 m_frontal_melt_rate(i, j) /= seconds_per_day;
121 } else {
122 m_frontal_melt_rate(i, j) = 0.0;
123 }
124 } // end of the loop over grid points
125
126 // Set frontal melt rate *near* grounded termini to the average of grounded icy
127 // neighbors: front retreat code uses values at these locations (the rest is for
128 // visualization).
129
131
132 for (auto p : m_grid->points()) {
133 const int i = p.i(), j = p.j();
134
135 if (apply(cell_type, i, j) and cell_type.ice_free(i, j)) {
136
137 auto R = m_frontal_melt_rate.star(i, j);
138 auto M = cell_type.star_int(i, j);
139
140 int N = 0;
141 double R_sum = 0.0;
142 for (auto d : { North, East, South, West }) {
143 if (mask::grounded_ice(M[d]) or (m_include_floating_ice and mask::icy(M[d]))) {
144 R_sum += R[d];
145 N++;
146 }
147 }
148
149 if (N > 0) {
150 m_frontal_melt_rate(i, j) = R_sum / N;
151 }
152 }
153 }
154}
155
159
161
162 auto dt = m_theta_ocean->max_timestep(t);
163
164 if (dt.finite()) {
165 return {dt.value(), "frontal_melt routing"};
166 }
167
168 return {"frontal_melt routing"};
169}
170
171} // end of namespace frontalmelt
172} // end of namespace pism
std::shared_ptr< const Grid > grid() const
Definition Component.cc:107
std::shared_ptr< const Config > m_config
configuration database used by this component
Definition Component.hh:160
const std::shared_ptr< const Grid > m_grid
grid used by this component
Definition Component.hh:158
std::shared_ptr< const Logger > m_log
logger (for easy access)
Definition Component.hh:164
High-level PISM I/O class.
Definition File.hh:57
const Geometry * geometry
const array::Scalar * subglacial_water_flux
array::Scalar1 sea_level_elevation
Definition Geometry.hh:48
array::CellType2 cell_type
Definition Geometry.hh:55
array::Scalar2 ice_thickness
Definition Geometry.hh:51
array::Scalar2 bed_elevation
Definition Geometry.hh:47
double value() const
Get the value of the maximum time step.
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
VariableMetadata & long_name(const std::string &input)
VariableMetadata & units(const std::string &input)
VariableMetadata & output_units(const std::string &input)
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition Array.hh:66
stencils::Star< T > star(int i, int j) const
Definition Array2D.hh:107
void update_ghosts()
Updates ghost points.
Definition Array.cc:645
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
Definition Array.cc:467
static std::shared_ptr< Forcing > Constant(std::shared_ptr< const Grid > grid, const std::string &short_name, double value)
Definition Forcing.cc:148
void update_impl(const FrontalMeltInputs &inputs, double t, double dt)
MaxTimestep max_timestep_impl(double t) const
DischargeRouting(std::shared_ptr< const Grid > g)
const array::Scalar & frontal_melt_rate_impl() const
void init_impl(const Geometry &geometry)
void initialize(const array::Scalar &theta)
std::shared_ptr< array::Forcing > m_theta_ocean
double frontal_melt_from_undercutting(double ice_thickness, double discharge_flux, double potential_temperature) const
bool apply(const array::CellType1 &M, int i, int j) const
A very rudimentary PISM frontal melt model.
@ PISM_NETCDF3
Definition IO_Flags.hh:58
@ PISM_READONLY
open an existing file for reading only
Definition IO_Flags.hh:69
bool icy(int M)
Ice-filled cell (grounded or floating).
Definition Mask.hh:48
bool grounded_ice(int M)
Definition Mask.hh:51
@ North
Definition stencils.hh:24
@ East
Definition stencils.hh:24
@ South
Definition stencils.hh:24
@ West
Definition stencils.hh:24
std::string filename
Definition options.hh:33