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