tDischargeRouting.cc - pism - [fork] customized build of PISM, the parallel ice sheet model (tillflux branch)
HTML git clone git://src.adamsgaard.dk/pism
DIR Log
DIR Files
DIR Refs
DIR LICENSE
---
tDischargeRouting.cc (6723B)
---
1 // Copyright (C) 2018, 2019 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 "DischargeRouting.hh"
20
21 #include "pism/util/IceGrid.hh"
22 #include "pism/geometry/Geometry.hh"
23 #include "pism/coupler/util/options.hh"
24 #include "FrontalMeltPhysics.hh"
25
26 namespace pism {
27 namespace frontalmelt {
28
29 DischargeRouting::DischargeRouting(IceGrid::ConstPtr grid)
30 : FrontalMelt(grid, nullptr) {
31
32 m_frontal_melt_rate = allocate_frontal_melt_rate(grid, 1);
33
34 m_log->message(2,
35 "* Initializing the frontal melt model\n"
36 " using the Rignot/Xu parameterization\n"
37 " and routing of subglacial discharge\n");
38
39 unsigned int evaluations_per_year = m_config->get_number("input.forcing.evaluations_per_year");
40
41 m_theta_ocean.reset(new IceModelVec2T(grid, "theta_ocean", 1, evaluations_per_year, LINEAR));
42 m_theta_ocean->set_attrs("climate_forcing",
43 "potential temperature of the adjacent ocean",
44 "Celsius", "Celsius", "", 0);
45
46 m_theta_ocean->init_constant(0.0);
47 }
48
49 DischargeRouting::~DischargeRouting() {
50 // empty
51 }
52
53 void DischargeRouting::init_impl(const Geometry &geometry) {
54 (void) geometry;
55
56 ForcingOptions opt(*m_grid->ctx(), "frontal_melt.routing");
57
58 {
59 unsigned int buffer_size = m_config->get_number("input.forcing.buffer_size");
60 unsigned int evaluations_per_year = m_config->get_number("input.forcing.evaluations_per_year");
61 bool periodic = opt.period > 0;
62
63 File file(m_grid->com, opt.filename, PISM_NETCDF3, PISM_READONLY);
64
65 m_theta_ocean = IceModelVec2T::ForcingField(m_grid,
66 file,
67 "theta_ocean",
68 "", // no standard name
69 buffer_size,
70 evaluations_per_year,
71 periodic,
72 LINEAR);
73 }
74
75 m_theta_ocean->set_attrs("climate_forcing",
76 "potential temperature of the adjacent ocean",
77 "Celsius", "Celsius", "", 0);
78
79 m_theta_ocean->init(opt.filename, opt.period, opt.reference_time);
80 }
81
82 /*!
83 * Initialize potential temperature from IceModelVecs instead of an input
84 * file (for testing).
85 */
86 void DischargeRouting::initialize(const IceModelVec2S &theta) {
87 m_theta_ocean->copy_from(theta);
88 }
89
90 void DischargeRouting::update_impl(const FrontalMeltInputs &inputs, double t, double dt) {
91
92 m_theta_ocean->update(t, dt);
93
94 FrontalMeltPhysics physics(*m_config);
95
96 const IceModelVec2CellType &cell_type = inputs.geometry->cell_type;
97 const IceModelVec2S &bed_elevation = inputs.geometry->bed_elevation;
98 const IceModelVec2S &ice_thickness = inputs.geometry->ice_thickness;
99 const IceModelVec2S &sea_level_elevation = inputs.geometry->sea_level_elevation;
100 const IceModelVec2S &water_flux = *inputs.subglacial_water_flux;
101
102 IceModelVec::AccessList list
103 {&ice_thickness, &bed_elevation, &cell_type, &sea_level_elevation,
104 &water_flux, m_theta_ocean.get(), m_frontal_melt_rate.get()};
105
106 double
107 seconds_per_day = 86400,
108 grid_spacing = 0.5 * (m_grid->dx() + m_grid->dy());
109
110 for (Points p(*m_grid); p; p.next()) {
111 const int i = p.i(), j = p.j();
112
113 if (cell_type.icy(i, j)) {
114 // Assume for now that thermal forcing is equal to theta_ocean. Also, thermal
115 // forcing is generally not available at the grounding line.
116 double TF = (*m_theta_ocean)(i, j);
117
118 double water_depth = std::max(sea_level_elevation(i, j) - bed_elevation(i, j), 0.0),
119 submerged_front_area = water_depth * grid_spacing;
120
121 // Convert subglacial water flux (m^2/s) to an "effective subglacial freshwater
122 // velocity" or flux per unit area of ice front in m/day (see Xu et al 2013, section
123 // 2, paragraph 11).
124 //
125 // [flux] = m^2 / s, so
126 // [flux * grid_spacing] = m^3 / s, so
127 // [flux * grid_spacing / submerged_front_area] = m / s, and
128 // [flux * grid_spacing * (s / day) / submerged_front_area] = m / day
129 double Q_sg = water_flux(i, j) * grid_spacing;
130 double q_sg = Q_sg / submerged_front_area * seconds_per_day;
131
132 (*m_frontal_melt_rate)(i, j) = physics.frontal_melt_from_undercutting(water_depth, q_sg, TF);
133 // convert from m / day to m / s
134 (*m_frontal_melt_rate)(i, j) /= seconds_per_day;
135 } else {
136 (*m_frontal_melt_rate)(i, j) = 0.0;
137 }
138 } // end of the loop over grid points
139
140 // Set frontal melt rate *near* grounded termini to the average of grounded icy
141 // neighbors: front retreat code uses values at these locations (the rest is for
142 // visualization).
143
144 m_frontal_melt_rate->update_ghosts();
145
146 const Direction dirs[] = {North, East, South, West};
147
148 for (Points p(*m_grid); p; p.next()) {
149 const int i = p.i(), j = p.j();
150
151 if (apply(cell_type, i, j) and cell_type.ice_free(i, j)) {
152
153 auto R = m_frontal_melt_rate->star(i, j);
154 auto M = cell_type.int_star(i, j);
155
156 int N = 0;
157 double R_sum = 0.0;
158 for (int n = 0; n < 4; ++n) {
159 Direction direction = dirs[n];
160 if (mask::grounded_ice(M[direction]) or
161 (m_include_floating_ice and mask::icy(M[direction]))) {
162 R_sum += R[direction];
163 N++;
164 }
165 }
166
167 if (N > 0) {
168 (*m_frontal_melt_rate)(i, j) = R_sum / N;
169 }
170 }
171 }
172 }
173
174 const IceModelVec2S& DischargeRouting::frontal_melt_rate_impl() const {
175 return *m_frontal_melt_rate;
176 }
177
178 MaxTimestep DischargeRouting::max_timestep_impl(double t) const {
179
180 auto dt = m_theta_ocean->max_timestep(t);
181
182 if (dt.finite()) {
183 return MaxTimestep(dt.value(), "frontal_melt routing");
184 } else {
185 return MaxTimestep("frontal_melt routing");
186 }
187 }
188
189 } // end of namespace frontalmelt
190 } // end of namespace pism