PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
CHSystem.cc
Go to the documentation of this file.
1/* Copyright (C) 2016, 2017, 2018, 2023, 2025 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 <algorithm> // std::max
20
21#include "pism/energy/CHSystem.hh"
22#include "pism/energy/enthSystem.hh"
23#include "pism/energy/utilities.hh"
24#include "pism/util/Context.hh"
25#include "pism/util/EnthalpyConverter.hh"
26#include "pism/util/array/CellType.hh"
27#include "pism/util/io/File.hh"
28#include "pism/util/Logger.hh"
29
30namespace pism {
31namespace energy {
32
33/*!
34 * Model of the energy content in the cryo-hydrologic system.
35 *
36 * This model can be used to include the influence of cryo-hydrologic warming on the
37 * internal energy of the ice.
38 *
39 * This model is based on
40 *
41 * @article{PhillipsRajaramSteffan2010,
42 * author = {Phillips, T. and Rajaram, H. and Steffen, K.},
43 * doi = {10.1029/2010GL044397},
44 * journal = {Geophy. Res. Lett.},
45 * number = {20},
46 * pages = {1--5},
47 * title = {{Cryo-hydrologic warming: A potential mechanism for rapid thermal response of ice sheets}},
48 * volume = {37},
49 * year = {2010}
50 * }
51 *
52 * We assume that during the melt season the enthalpy in the cryo-hydrologic system is
53 * equal to the enthalpy of the ice with a fixed water fraction corresponding to the
54 * amount of water remaining in the system once all of the moving water drains out (0.5%
55 * by default). During the winter the CH system is allowed to cool.
56*/
57
58CHSystem::CHSystem(std::shared_ptr<const Grid> grid,
59 std::shared_ptr<const stressbalance::StressBalance> stress_balance)
60 : EnergyModel(grid, stress_balance) {
61
62 m_ice_enthalpy.set_name("ch_enthalpy");
63 m_ice_enthalpy.metadata().set_name("ch_enthalpy");
64 m_ice_enthalpy.metadata()["long_name"] = "enthalpy of the cryo-hydrologic system";
65}
66
67void CHSystem::restart_impl(const File &input_file, int record) {
68
69 m_log->message(2, "* Restarting the cryo-hydrologic system from %s...\n",
70 input_file.name().c_str());
71
72 init_enthalpy(input_file, false, record);
73
75}
76
77void CHSystem::bootstrap_impl(const File &input_file,
78 const array::Scalar &ice_thickness,
79 const array::Scalar &surface_temperature,
80 const array::Scalar &climatic_mass_balance,
81 const array::Scalar &basal_heat_flux) {
82
83 m_log->message(2, "* Bootstrapping the cryo-hydrologic warming model from %s...\n",
84 input_file.name().c_str());
85
86 int enthalpy_revision = m_ice_enthalpy.state_counter();
88
89 if (enthalpy_revision == m_ice_enthalpy.state_counter()) {
90 bootstrap_ice_enthalpy(ice_thickness, surface_temperature, climatic_mass_balance,
91 basal_heat_flux, m_ice_enthalpy);
92 }
93}
94
95void CHSystem::initialize_impl(const array::Scalar &basal_melt_rate,
96 const array::Scalar &ice_thickness,
97 const array::Scalar &surface_temperature,
98 const array::Scalar &climatic_mass_balance,
99 const array::Scalar &basal_heat_flux) {
100 (void) basal_melt_rate;
101
102 m_log->message(2, "* Bootstrapping the cryo-hydrologic warming model...\n");
103
104 int enthalpy_revision = m_ice_enthalpy.state_counter();
106
107 if (enthalpy_revision == m_ice_enthalpy.state_counter()) {
108 bootstrap_ice_enthalpy(ice_thickness, surface_temperature, climatic_mass_balance,
109 basal_heat_flux, m_ice_enthalpy);
110 }
111}
112
113//! Update the enthalpy of the cryo-hydrologic system.
114/*!
115 This method updates array::Array3D m_work. No communication of ghosts is done.
116*/
117void CHSystem::update_impl(double t, double dt, const Inputs &inputs) {
118 // current time does not matter here
119 (void) t;
120
121 auto EC = m_grid->ctx()->enthalpy_converter();
122
123 inputs.check();
124
125 // give them names that are a bit shorter...
126 const array::Array3D
127 &volumetric_heat = *inputs.volumetric_heating_rate,
128 &u3 = *inputs.u3,
129 &v3 = *inputs.v3,
130 &w3 = *inputs.w3;
131
132 const auto &cell_type = *inputs.cell_type;
133
134 const array::Scalar
135 &basal_frictional_heating = *inputs.basal_frictional_heating,
136 &basal_heat_flux = *inputs.basal_heat_flux,
137 &surface_liquid_fraction = *inputs.surface_liquid_fraction,
138 &shelf_base_temp = *inputs.shelf_base_temp,
139 &ice_surface_temp = *inputs.surface_temp;
140
141 const array::Scalar1 &ice_thickness = *inputs.ice_thickness;
142
143 energy::enthSystemCtx system(m_grid->z(), "energy.ch_warming", m_grid->dx(), m_grid->dy(), dt,
144 *m_config, m_ice_enthalpy, u3, v3, w3, volumetric_heat, EC);
145
146 const size_t Mz_fine = system.z().size();
147 const double dz = system.dz();
148 std::vector<double> Enthnew(Mz_fine); // new enthalpy in column
149
150 array::AccessScope list{&ice_surface_temp, &shelf_base_temp, &surface_liquid_fraction,
151 &ice_thickness, &basal_frictional_heating, &basal_heat_flux,
152 &cell_type, &u3, &v3, &w3, &volumetric_heat, &m_ice_enthalpy,
153 &m_work};
154
155 double
156 margin_threshold = m_config->get_number("energy.margin_ice_thickness_limit"),
157 T_pm = m_config->get_number("constants.fresh_water.melting_point_temperature"),
158 residual_water_fraction = m_config->get_number("energy.ch_warming.residual_water_fraction");
159
160 const std::vector<double> &z = m_ice_enthalpy.levels();
161 const unsigned int Mz = z.size();
162
163 ParallelSection loop(m_grid->com);
164 try {
165 for (auto pt : m_grid->points()) {
166 const int i = pt.i(), j = pt.j();
167
168 const double H = ice_thickness(i, j);
169
170 if (ice_surface_temp(i, j) >= T_pm) {
171 // We use surface temperature to determine if we're in a melt season or not. It
172 // probably makes sense to use the surface mass balance instead.
173
174 double *column = m_work.get_column(i, j);
175 for (unsigned int k = 0; k < Mz; ++k) {
176 double
177 depth = std::max(H - z[k], 0.0),
178 P = EC->pressure(depth);
179 column[k] = EC->enthalpy(EC->melting_temperature(P),
180 residual_water_fraction,
181 P);
182 }
183 continue;
184 }
185
186 // enthalpy and pressures at top of ice
187 const double
188 depth_ks = H - system.ks() * dz,
189 p_ks = EC->pressure(depth_ks); // FIXME issue #15
190
191 const double Enth_ks = EC->enthalpy_permissive(ice_surface_temp(i, j),
192 surface_liquid_fraction(i, j), p_ks);
193
194 system.init(i, j,
195 marginal(ice_thickness, i, j, margin_threshold),
196 H);
197
198 const bool ice_free_column = (system.ks() == 0);
199
200 // deal completely with columns with no ice
201 if (ice_free_column) {
202 m_work.set_column(i, j, Enth_ks);
203 continue;
204 } // end of if (ice_free_column)
205
206 if (system.lambda() < 1.0) {
207 m_stats.reduced_accuracy_counter += 1; // count columns with lambda < 1
208 }
209
210 // set boundary conditions and update enthalpy
211 {
212 system.set_surface_dirichlet_bc(Enth_ks);
213
214 if (cell_type.ocean(i, j)) {
215 // floating base: Dirichlet application of known temperature from ocean coupler;
216 // assumes base of ice shelf has zero liquid fraction
217 double Enth0 = EC->enthalpy_permissive(shelf_base_temp(i, j), 0.0, EC->pressure(H));
218
219 system.set_basal_dirichlet_bc(Enth0);
220 } else {
221 // grounded
222 system.set_basal_heat_flux(basal_heat_flux(i, j) + basal_frictional_heating(i, j));
223 }
224 // solve the system
225 system.solve(Enthnew);
226 }
227
228 system.fine_to_coarse(Enthnew, i, j, m_work);
229 }
230 } catch (...) {
231 loop.failed();
232 }
233 loop.check();
234}
235
236std::set<VariableMetadata> CHSystem::state_impl() const {
237 return array::metadata({ &m_ice_enthalpy });
238}
239
240void CHSystem::write_state_impl(const OutputFile &output) const {
241 m_ice_enthalpy.write(output);
242}
243
244/*!
245 * Compute the heat flux corresponding to the cryo-hydrologic warming.
246 *
247 * `Q = (k / R**2) * (T_ch - T_ice),`
248 *
249 * where `k` is the thermal conductivity of ice and `R` us the average spacing of
250 * channels in the cryo-hydrologic system.
251 */
253 double R,
254 const array::Scalar &ice_thickness,
255 const array::Array3D &ice_enthalpy,
256 const array::Array3D &ch_enthalpy,
257 array::Array3D &result) {
258
259 auto grid = result.grid();
260
261 const auto &z = ice_enthalpy.levels();
262 auto Mz = z.size();
263
264 auto EC = grid->ctx()->enthalpy_converter();
265
266 array::AccessScope access{&ice_thickness, &ice_enthalpy, &ch_enthalpy, &result};
267
268 double C = k / (R * R);
269
270 ParallelSection loop(grid->com);
271 try {
272 for (auto p : grid->points()) {
273 const int i = p.i(), j = p.j();
274
275 const double
276 *E_ch = ch_enthalpy.get_column(i, j),
277 *E_ice = ice_enthalpy.get_column(i, j);
278 double *Q = result.get_column(i, j);
279
280 for (unsigned int m = 0; m < Mz; ++m) {
281 double
282 depth = ice_thickness(i, j) - z[m];
283
284 if (depth > 0.0) {
285 double P = EC->pressure(depth);
286 Q[m] = std::max(C * (EC->temperature(E_ch[m], P) - EC->temperature(E_ice[m], P)),
287 0.0);
288 } else {
289 Q[m] = 0.0;
290 }
291 }
292 }
293 } catch (...) {
294 loop.failed();
295 }
296 loop.check();
297}
298
302
303
304} // end of namespace energy
305} // end of namespace pism
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
static Ptr wrap(const T &input)
std::string name() const
Definition File.cc:274
High-level PISM I/O class.
Definition File.hh:57
void failed()
Indicates a failure of a parallel section.
VariableMetadata & set_name(const std::string &name)
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition Array.hh:66
void set_column(int i, int j, double c)
Set all values of scalar quantity to given a single value in a particular column.
Definition Array3D.cc:56
double * get_column(int i, int j)
Definition Array3D.cc:127
A virtual class collecting methods common to ice and bedrock 3D fields.
Definition Array3D.hh:33
void set_name(const std::string &name)
Sets the variable name to name.
Definition Array.cc:345
void write(const OutputFile &file) const
Definition Array.cc:859
const std::vector< double > & levels() const
Definition Array.cc:142
int state_counter() const
Get the object state counter.
Definition Array.cc:130
std::shared_ptr< const Grid > grid() const
Definition Array.cc:134
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
Definition Array.cc:467
const std::vector< double > & z() const
void fine_to_coarse(const std::vector< double > &input, int i, int j, array::Array3D &output) const
unsigned int ks() const
CHSystem(std::shared_ptr< const Grid > grid, std::shared_ptr< const stressbalance::StressBalance > stress_balance)
Definition CHSystem.cc:58
DiagnosticList spatial_diagnostics_impl() const
Definition CHSystem.cc:299
std::set< VariableMetadata > state_impl() const
Definition CHSystem.cc:236
void restart_impl(const File &input_file, int record)
Definition CHSystem.cc:67
void update_impl(double t, double dt, const Inputs &inputs)
Update the enthalpy of the cryo-hydrologic system.
Definition CHSystem.cc:117
void initialize_impl(const array::Scalar &basal_melt_rate, const array::Scalar &ice_thickness, const array::Scalar &surface_temperature, const array::Scalar &climatic_mass_balance, const array::Scalar &basal_heat_flux)
Definition CHSystem.cc:95
void bootstrap_impl(const File &input_file, const array::Scalar &ice_thickness, const array::Scalar &surface_temperature, const array::Scalar &climatic_mass_balance, const array::Scalar &basal_heat_flux)
Definition CHSystem.cc:77
void write_state_impl(const OutputFile &output) const
The default (empty implementation).
Definition CHSystem.cc:240
void init_enthalpy(const File &input_file, bool regrid, int record)
Initialize enthalpy by reading it from a file, or by reading temperature and liquid water fraction,...
EnergyModelStats m_stats
const array::Scalar & basal_melt_rate() const
Basal melt rate in grounded areas. (It is set to zero elsewhere.)
array::Array3D m_ice_enthalpy
void regrid_enthalpy()
Regrid enthalpy from the -regrid_file.
const array::Scalar * surface_liquid_fraction
const array::Scalar1 * ice_thickness
const array::Array3D * w3
const array::Array3D * v3
const array::Scalar * shelf_base_temp
const array::Scalar * basal_heat_flux
const array::Scalar * basal_frictional_heating
const array::Array3D * u3
const array::Scalar * surface_temp
const array::CellType * cell_type
const array::Array3D * volumetric_heating_rate
void init(int i, int j, bool ismarginal, double ice_thickness)
void set_basal_heat_flux(double heat_flux)
Set coefficients in discrete equation for Neumann condition at base of ice.
void solve(std::vector< double > &result)
Solve the tridiagonal system, in a single column, which determines the new values of the ice enthalpy...
void set_basal_dirichlet_bc(double E_basal)
Set coefficients in discrete equation for at base of ice.
void set_surface_dirichlet_bc(double E_surface)
Tridiagonal linear system for conservation of energy in vertical column of ice enthalpy.
Definition enthSystem.hh:38
std::set< VariableMetadata > metadata(std::initializer_list< const Array * > vecs)
Definition Array.cc:1244
void cryo_hydrologic_warming_flux(double k, double R, const array::Scalar &ice_thickness, const array::Array3D &ice_enthalpy, const array::Array3D &ch_enthalpy, array::Array3D &result)
Definition CHSystem.cc:252
bool marginal(const array::Scalar1 &thickness, int i, int j, double threshold)
void bootstrap_ice_enthalpy(const array::Scalar &ice_thickness, const array::Scalar &ice_surface_temp, const array::Scalar &surface_mass_balance, const array::Scalar &basal_heat_flux, array::Array3D &result)
Definition utilities.cc:438
std::map< std::string, Diagnostic::Ptr > DiagnosticList
static const double k
Definition exactTestP.cc:42