PISM, A Parallel Ice Sheet Model  stable v2.1.1 committed by Constantine Khrulev on 2024-12-04 13:36:58 -0900
IBIceModel.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <limits>
3 #include <memory>
4 #include <string>
5 
6 #include "pism/energy/BedThermalUnit.hh"
7 #include "pism/util/EnthalpyConverter.hh"
8 #include "pism/util/io/File.hh"
9 #include "pism/util/io/io_helpers.hh"
10 
11 #include "pism/icebin/IBIceModel.hh"
12 #include "pism/icebin/IBSurfaceModel.hh"
13 #include "pism/coupler/ocean/Factory.hh"
14 #include "pism/energy/EnergyModel.hh"
15 
16 namespace pism {
17 namespace icebin {
18 
19 static double const NaN = std::numeric_limits<double>::quiet_NaN();
20 
21 // ================================
22 
23 IBIceModel::IBIceModel(std::shared_ptr<pism::Grid> grid, const std::shared_ptr<Context> &context,
24  IBIceModel::Params const &_params)
25  : pism::IceModel(grid, context),
26  params(_params),
27  // FIXME: should `prefix` be empty below?
28  base(grid, ""),
29  cur(grid, ""),
30  rate(grid, ""),
31  ice_top_senth(grid, "ice_top_senth"),
32  elevmask_ice(grid, "elevmask_ice"),
33  elevmask_land(grid, "elevmask_land") {
34 
35  std::cout << "IBIceModel Conservation Formulas:" << std::endl;
36  cur.print_formulas(std::cout);
37 }
38 
40  // empty
41 }
42 
43 
46  // indicates it has already been allocated
47  return;
48  }
49 
51 }
52 
53 
56 
57  m_log->message(2, "# Allocating the icebin surface model...\n");
58  m_surface = std::make_shared<IBSurfaceModel>(m_grid);
59  m_submodels["surface process model"] = m_surface.get();
60 }
61 
63 #if 0 // Avoid warnings until we put something in this method
64 
65  // Enthalpy and mass continuity are stepped with different timesteps.
66  // Fish out the timestep relevant to US.
67  const double my_t0 = m_grid.time->current();
68  const double my_dt = this->dt;
69 #endif
70 }
71 
72 
74 #if 0 // Avoid warnings until we put something in this method
75 
76  // Enthalpy and mass continuity are stepped with different timesteps.
77  // Fish out the timestep relevant to US.
78  const double my_t0 = m_grid.time->current();
79  const double my_dt = this->dt;
80 #endif
81 }
82 
83 
85 
86  printf("BEGIN IBIceModel::energyStep(t=%f, dt=%f)\n", t_TempAge, dt_TempAge);
87 
88  // Enthalpy and mass continuity are stepped with different timesteps.
89  // Fish out the timestep relevant to US.
90  // const double my_t0 = t_TempAge; // Time at beginning of timestep
91  const double my_dt = dt_TempAge;
92 
93  // =========== BEFORE Energy Step
94 
95  // =========== The Energy Step Itself
97 
98  // =========== AFTER Energy Step
99 
100  // We need to integrate over strain_heating and geothermal_flux, which
101  // are given in PISM as rates.
102 
103 
104  // --------- Upward Geothermal Flux
105  // Use actual geothermal flux, not the long-term average..
106  // See: file:///Users/rpfische/git/pism/build/doc/browser/html/classPISMBedThermalUnit.html#details
107  { cur.upward_geothermal_flux.add(my_dt, m_btu->flux_through_top_surface()); }
108 
109  // ----------- Geothermal Flux
110  cur.geothermal_flux.add(my_dt, m_btu->flux_through_bottom_surface());
111 
112  // ---------- Basal Frictional Heating (see iMenthalpy.cc l. 220)
113  array::Scalar const &Rb(m_stress_balance->basal_frictional_heating());
114  cur.basal_frictional_heating.add(my_dt, Rb);
115 
116  // NOTE: strain_heating is inf at the coastlines.
117  // See: https://github.com/pism/pism/issues/292
118  // ------------ Volumetric Strain Heating
119  // strain_heating_sum += my_dt * sum_columns(strainheating3p)
120  const auto &strain_heating3 = m_stress_balance->volumetric_strain_heating();
121 
122  array::sum_columns(strain_heating3, 1.0, my_dt, cur.strain_heating);
123 }
124 
126 
127  printf("BEGIN IBIceModel::MassContExplicitStep()\n");
128 
129  m_ice_density = m_config->get_number("constants.ice.density");
131 
132 
133  // =========== The Mass Continuity Step Itself
134  // This will call through to accumulateFluxes_massContExplicitStep()
135  // in the inner loop. We must open access to variables we will use
136  // in that subroutine.
137  {
140 
141  // FIXME: update to use PISM's current mass transport code
142  // super::massContExplicitStep();
143  }
144 
145  // =========== AFTER the Mass Continuity Step
146 
147  // ----------- SMB: Pass inputs through to outputs.
148  // They are needed to participate in mass/energy budget
149  // This allows them to be used in the MassEnergyBudget computation.
150  IBSurfaceModel *ib_surface = ib_surface_model();
151 
152  {
153  array::AccessScope access{ &ib_surface->massxfer, &ib_surface->enthxfer, &ib_surface->deltah,
154  &cur.smb, &cur.deltah };
155 
156  for (auto p = m_grid->points(); p; p.next()) {
157  const int i = p.i(), j = p.j();
158 
159  cur.smb.mass(i, j) += m_dt * ib_surface->massxfer(i, j);
160  cur.smb.enth(i, j) += m_dt * ib_surface->enthxfer(i, j);
161  cur.deltah(i, j) += m_dt * ib_surface->deltah(i, j);
162  }
163  }
164 }
165 
166 
167 /** This is called IMMEDIATELY after ice is gained/lost in
168 iMgeometry.cc (massContExplicitStep()). Here we can record the same
169 values that PISM saw when moving ice around. */
171  int i, int j,
172  double surface_mass_balance, // [m s-1] ice equivalent
173  double basal_melt_rate, // [m s-1] ice equivalent
174  double divQ_SIA, // [m s-1] ice equivalent
175  double divQ_SSA, // [m s-1] ice equivalent
176  double Href_to_H_flux, // [m] ice equivalent
177  double nonneg_rule_flux) // [m] ice equivalent
178 {
179  EnthalpyConverter::Ptr EC = ctx()->enthalpy_converter();
180 
181  const auto &ice_thickness = m_geometry.ice_thickness;
182 
183  const auto &ice_enthalpy = m_energy_model->enthalpy();
184 
185  // -------------- Melting
186  double p_basal = EC->pressure(ice_thickness(i, j));
187  double T = EC->melting_temperature(p_basal);
188  double specific_enth_basal = EC->enthalpy_permissive(T, 1.0, p_basal);
189  double mass;
190 
191  // ------- Melting at base of ice sheet
192  mass = -basal_melt_rate * m_meter_per_s_to_kg_per_m2;
193  // TODO: Change this to just cur.melt_rate
194  cur.melt_grounded.mass(i, j) += mass;
195  cur.melt_grounded.enth(i, j) += mass * specific_enth_basal;
196 
197  // -------------- internal_advection
198  const int ks = m_grid->kBelowHeight(ice_thickness(i, j));
199  const double *Enth = ice_enthalpy.get_column(i, j);
200  double specific_enth_top = Enth[ks]; // Approximate, we will use the enthalpy of the top layer...
201 
202  mass = -(divQ_SIA + divQ_SSA) * m_meter_per_s_to_kg_per_m2;
203 
204  cur.internal_advection.mass(i, j) += mass;
205  cur.internal_advection.enth(i, j) += mass * specific_enth_top;
206 
207 
208  // -------------- Get the easy variables out of the way...
209  mass = surface_mass_balance * m_meter_per_s_to_kg_per_m2;
210  cur.pism_smb.mass(i, j) += mass;
211  cur.pism_smb.enth(i, j) += mass * specific_enth_top;
212  cur.nonneg_rule(i, j) -= nonneg_rule_flux * m_ice_density;
213  cur.href_to_h(i, j) += Href_to_H_flux * m_ice_density;
214 }
215 
216 /** Differences and divides by accumulated time over coupling timestep.
217 Eg, to convert [kg m-2] --> [kg m-2 s-1]
218 @param t0 Time of last time we coupled. */
219 void IBIceModel::set_rate(double dt) {
220 
221  if (dt == 0)
222  throw RuntimeError(PISM_ERROR_LOCATION, "Coupling timestep has size dt=0");
223 
224  double by_dt = 1.0 / dt;
225  printf("IBIceModel::set_rate(dt=%f)\n", dt);
226 
228  cur.set_epsilon();
229 
230  // Compute differences, and set base = cur
231  auto base_ii(base.all_vecs.begin());
232  auto cur_ii(cur.all_vecs.begin());
233  auto rate_ii(rate.all_vecs.begin());
234  for (; base_ii != base.all_vecs.end(); ++base_ii, ++cur_ii, ++rate_ii) {
235  array::Scalar &vbase(base_ii->vec);
236  array::Scalar &vcur(cur_ii->vec);
237  array::Scalar &vrate(rate_ii->vec);
238 
239  {
240  array::AccessScope access{ &vbase, &vcur, &vrate };
241  for (auto p = m_grid->points(); p; p.next()) {
242  const int i = p.i(), j = p.j();
243 
244  // rate = cur - base: Just for DELTA and EPSILON flagged vectors
245  if (base_ii->flags & (MassEnergyBudget::DELTA | MassEnergyBudget::EPSILON)) {
246  vrate(i, j) = (vcur(i, j) - vbase(i, j)) * by_dt;
247  } else {
248  // Or else just copy the to "rate"
249  vrate(i, j) = vcur(i, j);
250  }
251  }
252  }
253  }
254 }
255 
257  // Compute differences, and set base = cur
258  auto base_ii(base.all_vecs.begin());
259  auto cur_ii(cur.all_vecs.begin());
260  for (; base_ii != base.all_vecs.end(); ++base_ii, ++cur_ii) {
261  array::Scalar &vbase(base_ii->vec);
262  array::Scalar &vcur(cur_ii->vec);
263 
264  // This cannot go in the loop above with PETSc because
265  // vbase is needed on the RHS of the equations above.
266  array::AccessScope access{ &vbase, &vcur };
267  for (auto p = m_grid->points(); p; p.next()) {
268  const int i = p.i(), j = p.j();
269  // base = cur: For ALL vectors
270  vbase(i, j) = vcur(i, j);
271  }
272  }
273 }
274 
275 void IBIceModel::prepare_outputs(double time_s) {
276  (void)time_s;
277 
278  EnthalpyConverter::Ptr EC = ctx()->enthalpy_converter();
279 
280  // --------- ice_surface_enth from m_ice_enthalpy
281  const auto &ice_surface_elevation = m_geometry.ice_surface_elevation;
282  const auto &cell_type = m_geometry.cell_type;
283  const auto &ice_enthalpy = m_energy_model->enthalpy();
284  const auto &ice_thickness = m_geometry.ice_thickness;
285 
286  array::AccessScope access{ &ice_enthalpy, &ice_thickness, // INPUTS
287  &ice_surface_elevation, &cell_type, &ice_top_senth,
288  &elevmask_ice, &elevmask_land }; // OUTPUT
289  for (int i = m_grid->xs(); i < m_grid->xs() + m_grid->xm(); ++i) {
290  for (int j = m_grid->ys(); j < m_grid->ys() + m_grid->ym(); ++j) {
291  double const *Enth = ice_enthalpy.get_column(i, j);
292 
293  // Top Layer
294  auto ks = m_grid->kBelowHeight(ice_thickness(i, j));
295  double senth = Enth[ks]; // [J kg-1]
296  ice_top_senth(i, j) = senth;
297 
298  // elevmask_ice and elevmask_land: Used by IceBin for elevation and masking
299  switch ((int)cell_type(i, j)) {
300  case MASK_GROUNDED:
301  case MASK_FLOATING:
302  elevmask_ice(i, j) = ice_surface_elevation(i, j);
303  elevmask_land(i, j) = ice_surface_elevation(i, j);
304  break;
306  elevmask_ice(i, j) = NaN;
307  elevmask_land(i, j) = ice_surface_elevation(i, j);
308  break;
309  case MASK_ICE_FREE_OCEAN:
310  case MASK_UNKNOWN:
311  elevmask_ice(i, j) = NaN;
312  elevmask_land(i, j) = NaN;
313  break;
314  }
315  }
316  }
317 
318  // ====================== Write to the post_energy.nc file (OPTIONAL)
319 }
320 
321 void IBIceModel::dumpToFile(const std::string &filename) const {
322  File file(m_grid->com, filename,
323  string_to_backend(m_config->get_string("output.format")), io::PISM_READWRITE_MOVE,
324  m_ctx->pio_iosys_id());
325 
327  write_run_stats(file, run_stats());
328 
329  // assume that "dumpToFile" is expected to save the model state *only*.
330  save_variables(file, INCLUDE_MODEL_STATE, {}, m_time->current());
331 }
332 
334  // super::m_grid_setup() trashes m_time->start(). Now set it correctly.
335  m_time->set_start(params.time_start_s);
336  m_time->set(params.time_start_s);
337 
338  m_log->message(2, "* Run time: [%s, %s] (%s years, using the '%s' calendar)\n",
339  m_time->date(m_time->start()).c_str(), m_time->date(m_time->end()).c_str(),
340  m_time->run_length().c_str(), m_time->calendar().c_str());
341 }
342 
345 
346 
347  // ------ Initialize MassEnth structures: base, cur, rate
348  for (auto &ii : cur.all_vecs) {
349  ii.vec.set(0);
350  }
352  cur.set_epsilon();
353 
354  // base = cur
355  auto base_ii(base.all_vecs.begin());
356  auto cur_ii(cur.all_vecs.begin());
357  for (; base_ii != base.all_vecs.end(); ++base_ii, ++cur_ii) {
358  base_ii->vec.copy_from(cur_ii->vec);
359  }
360 }
361 
362 /** Sums over columns to compute enthalpy on 2D m_grid.
363 This is used to track conservation of energy.
364 
365 NOTE: Unfortunately so far PISM does not keep track of enthalpy in
366 "partially-filled" cells, so Enth2(i,j) is not valid at locations like
367 this one. We need to address this, but so far, it seems to me, the
368 best thing we can do is estimate Enth2(i,j) at partially-filled cells
369 by computing the average over icy neighbors. I think you can re-use
370 the idea from IceModel::get_threshold_thickness(...) (iMpartm_grid->cc). */
371 
373  // getInternalColumn() is allocated already
374  double ice_density = m_config->get_number("constants.ice.density", "kg m-3");
375 
376  const auto &ice_enthalpy = m_energy_model->enthalpy();
377  const auto &ice_thickness = m_geometry.ice_thickness;
378 
379 
380  array::AccessScope access{ &ice_thickness, &ice_enthalpy, // Inputs
381  &enth2, &mass2 }; // Outputs
382  for (auto p = m_grid->points(); p; p.next()) {
383  const int i = p.i(), j = p.j();
384 
385  enth2(i, j) = 0;
386  mass2(i, j) = 0;
387 
388  // count all ice, including cells that have so little they
389  // are considered "ice-free"
390  if (ice_thickness(i, j) > 0) {
391  int ks = (int)m_grid->kBelowHeight(ice_thickness(i, j));
392  const auto *Enth = ice_enthalpy.get_column(i, j);
393 
394  for (int k = 0; k < ks; ++k) {
395  double dz = (m_grid->z(k + 1) - m_grid->z(k));
396  enth2(i, j) += Enth[k] * dz; // [m J kg-1]
397  }
398 
399  // Last layer is (potentially) partial
400  double dz = (ice_thickness(i, j) - m_grid->z(ks));
401  enth2(i, j) += Enth[ks] * dz; // [m J kg-1]
402 
403  // Finish off after all layers processed
404  enth2(i, j) *= ice_density; // --> [J m-2]
405  mass2(i, j) = ice_thickness(i, j) * ice_density; // --> [kg m-2]
406  }
407  }
408 }
409 
410 
411 /** Merges surface temperature derived from m_ice_enthalpy into any NaN values
412 in the vector provided.
413 @param deltah IN: Input from Icebin (change in enthalpy of each m_grid
414  cell over the timestep) [W m-2].
415 @param default_val: The value that deltah(i,j) will have if no value
416  is listed for that m_grid cell
417 @param timestep_s: Length of the current coupling timestep [s]
418 @param surface_temp OUT: Resulting surface temperature to use as the Dirichlet B.C.
419 */
421  pism::array::Scalar &deltah, // IN: Input from Icebin
422  double default_val,
423  double timestep_s, // Length of this coupling interval [s]
424  pism::array::Scalar &surface_temp) // OUT: Temperature @ top of ice sheet (to use for Dirichlet B.C.)
425 
426 {
427  printf("BEGIN IBIceModel::merge_surface_temp default_val=%g\n", default_val);
428  EnthalpyConverter::Ptr EC = ctx()->enthalpy_converter();
429 
430  double ice_density = m_config->get_number("constants.ice.density");
431  const auto &ice_enthalpy = m_energy_model->enthalpy();
432  const auto &ice_thickness = m_geometry.ice_thickness;
433 
434  {
435  array::AccessScope access{ &ice_enthalpy, &deltah, &ice_thickness, &surface_temp };
436 
437  // First time around, set effective_surface_temp to top temperature
438  for (int i = m_grid->xs(); i < m_grid->xs() + m_grid->xm(); ++i) {
439  for (int j = m_grid->ys(); j < m_grid->ys() + m_grid->ym(); ++j) {
440  double &surface_temp_ij(surface_temp(i, j));
441  double const &deltah_ij(deltah(i, j));
442 
443  const auto *Enth = ice_enthalpy.get_column(i, j);
444 
445  // Enthalpy at top of ice sheet
446  const int ks = m_grid->kBelowHeight(ice_thickness(i, j));
447  double spec_enth3 = Enth[ks]; // Specific enthalpy [J kg-1]
448 
449  if (deltah_ij != default_val) {
450  // Adjust enthalpy @top by deltah
451  double toplayer_dz = ice_thickness(i, j) - m_grid->z(ks); // [m]
452 
453  // [J kg-1] = [J kg-1]
454  // + [J m-2 s-1] * [m^2 m-3] * [m^3 kg-1] * [s]
455  spec_enth3 = spec_enth3 + deltah_ij / (toplayer_dz * ice_density) * timestep_s;
456  }
457 
458 
459  // Convert specific enthalpy value to surface temperature
460  const double p = 0.0; // Pressure at top of ice sheet
461  surface_temp_ij = EC->temperature(spec_enth3, p); // [K]
462  }
463  }
464  }
465 
466  printf("END IBIceModel::merge_surface_temp\n");
467 }
468 } // namespace icebin
469 } // namespace pism
std::shared_ptr< EnthalpyConverter > Ptr
High-level PISM I/O class.
Definition: File.hh:56
array::Scalar2 ice_surface_elevation
Definition: Geometry.hh:57
array::CellType2 cell_type
Definition: Geometry.hh:55
array::Scalar2 ice_thickness
Definition: Geometry.hh:51
std::map< std::string, const Component * > m_submodels
the list of sub-models, for writing model states and obtaining diagnostics
Definition: IceModel.hh:259
std::shared_ptr< stressbalance::StressBalance > m_stress_balance
Definition: IceModel.hh:397
VariableMetadata run_stats() const
Definition: utilities.cc:92
virtual void energy_step()
Manage the solution of the energy equation, and related parallel communication.
Definition: energy.cc:60
std::shared_ptr< surface::SurfaceModel > m_surface
Definition: IceModel.hh:286
const Config::Ptr m_config
Configuration flags and parameters.
Definition: IceModel.hh:243
const Time::Ptr m_time
Time manager.
Definition: IceModel.hh:251
Geometry m_geometry
Definition: IceModel.hh:295
const std::shared_ptr< Context > m_ctx
Execution context.
Definition: IceModel.hh:245
virtual void misc_setup()
Miscellaneous initialization tasks plus tasks that need the fields that can come from regridding.
const Logger::Ptr m_log
Logger.
Definition: IceModel.hh:249
double dt() const
Definition: IceModel.cc:140
std::shared_ptr< energy::BedThermalUnit > m_btu
Definition: IceModel.hh:266
virtual void save_variables(const File &file, OutputKind kind, const std::set< std::string > &variables, double time, io::Type default_diagnostics_type=io::PISM_FLOAT) const
Definition: output.cc:169
double t_TempAge
time of last update for enthalpy/temperature
Definition: IceModel.hh:320
std::shared_ptr< Context > ctx() const
Return the context this model is running in.
Definition: utilities.cc:127
virtual void allocate_couplers()
virtual void write_metadata(const File &file, MappingTreatment mapping_flag, HistoryTreatment history_flag) const
Write time-independent metadata to a file.
Definition: output.cc:72
std::unique_ptr< hydrology::Hydrology > m_subglacial_hydrology
Definition: IceModel.hh:261
double dt_TempAge
enthalpy/temperature and age time-steps
Definition: IceModel.hh:322
double m_dt
mass continuity time step, s
Definition: IceModel.hh:318
std::shared_ptr< energy::EnergyModel > m_energy_model
Definition: IceModel.hh:267
const std::shared_ptr< Grid > m_grid
Computational grid.
Definition: IceModel.hh:241
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition: Array.hh:65
void add(double alpha, const Array2D< T > &x)
Definition: Array2D.hh:65
pism::array::Scalar elevmask_ice
Definition: IBIceModel.hh:60
pism::array::Scalar ice_top_senth
Definition: IBIceModel.hh:56
void construct_surface_temp(pism::array::Scalar &deltah, double default_val, double timestep_s, pism::array::Scalar &surface_temp)
Definition: IBIceModel.cc:420
virtual void misc_setup()
Miscellaneous initialization tasks plus tasks that need the fields that can come from regridding.
Definition: IBIceModel.cc:343
MassEnergyBudget base
Definition: IBIceModel.hh:48
void dumpToFile(const std::string &filename) const
Definition: IBIceModel.cc:321
virtual void time_setup()
Initialize time from an input file or command-line options.
Definition: IBIceModel.cc:333
virtual void accumulateFluxes_massContExplicitStep(int i, int j, double surface_mass_balance, double basal_melt_rate, double divQ_SIA, double divQ_SSA, double Href_to_H_flux, double nonneg_rule_flux)
Definition: IBIceModel.cc:170
virtual void allocate_couplers()
Definition: IBIceModel.cc:54
virtual void massContExplicitStep()
Definition: IBIceModel.cc:125
IBIceModel(std::shared_ptr< pism::Grid > grid, const std::shared_ptr< Context > &context, IBIceModel::Params const &_params)
Definition: IBIceModel.cc:23
void compute_enth2(pism::array::Scalar &enth2, pism::array::Scalar &mass2)
Definition: IBIceModel.cc:372
void prepare_outputs(double time_s)
Definition: IBIceModel.cc:275
MassEnergyBudget rate
Definition: IBIceModel.hh:50
void energy_step()
Manage the solution of the energy equation, and related parallel communication.
Definition: IBIceModel.cc:84
virtual void allocate_subglacial_hydrology()
Decide which subglacial hydrology model to use.
Definition: IBIceModel.cc:44
MassEnergyBudget cur
Definition: IBIceModel.hh:49
void set_rate(double dt)
Definition: IBIceModel.cc:219
pism::icebin::IBSurfaceModel * ib_surface_model()
Definition: IBIceModel.hh:107
pism::array::Scalar elevmask_land
Definition: IBIceModel.hh:62
pism::array::Scalar enthxfer
pism::array::Scalar massxfer
pism::array::Scalar deltah
pism::array::Scalar href_to_h
SMB as seen by PISM in iMgeometry.cc massContExplicitSte(). Used to check icebin_smb....
std::ostream & print_formulas(std::ostream &out)
pism::array::Scalar geothermal_flux
Total amount of geothermal energy [J/m^2].
MassEnthVec2S smb
accumulation / ablation, as provided by Icebin
pism::array::Scalar basal_frictional_heating
Total amount of basal friction heating [J/m^2].
std::vector< VecWithFlags > all_vecs
pism::array::Scalar strain_heating
Total amount of strain heating [J/m^2].
MassEnthVec2S melt_grounded
basal melt (grounded) (from summing meltrate_grounded)
pism::array::Scalar upward_geothermal_flux
Total amount of geothermal energy [J/m^2].
MassEnthVec2S melt_floating
sub-shelf melt (from summing meltrate_floating)
pism::array::Scalar deltah
Change in enthalpy of top layer.
#define PISM_ERROR_LOCATION
void sum_columns(const Array3D &data, double A, double B, Scalar &output)
Definition: Array3D.cc:190
static double const NaN
Definition: IBIceModel.cc:19
@ PISM_READWRITE_MOVE
create a file for writing, move foo.nc to foo.nc~ if present
Definition: IO_Flags.hh:78
io::Backend string_to_backend(const std::string &backend)
Definition: File.cc:57
std::string printf(const char *format,...)
static const double k
Definition: exactTestP.cc:42
@ MASK_FLOATING
Definition: Mask.hh:34
@ MASK_ICE_FREE_OCEAN
Definition: Mask.hh:35
@ MASK_ICE_FREE_BEDROCK
Definition: Mask.hh:32
@ MASK_GROUNDED
Definition: Mask.hh:33
@ MASK_UNKNOWN
Definition: Mask.hh:31
void write_run_stats(const File &file, const pism::VariableMetadata &stats)
Definition: output.cc:162