PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
initialization.cc
Go to the documentation of this file.
1 // Copyright (C) 2009--2023 Ed Bueler 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 //This file contains various initialization routines. See the IceModel::init()
20 //documentation comment in iceModel.cc for the order in which they are called.
21 
22 #include "pism/icemodel/IceModel.hh"
23 #include "pism/basalstrength/ConstantYieldStress.hh"
24 #include "pism/basalstrength/MohrCoulombYieldStress.hh"
25 #include "pism/basalstrength/OptTillphiYieldStress.hh"
26 #include "pism/frontretreat/util/IcebergRemover.hh"
27 #include "pism/frontretreat/util/IcebergRemoverFEM.hh"
28 #include "pism/frontretreat/calving/CalvingAtThickness.hh"
29 #include "pism/frontretreat/calving/EigenCalving.hh"
30 #include "pism/frontretreat/calving/FloatKill.hh"
31 #include "pism/frontretreat/calving/HayhurstCalving.hh"
32 #include "pism/frontretreat/calving/vonMisesCalving.hh"
33 #include "pism/energy/BedThermalUnit.hh"
34 #include "pism/hydrology/NullTransport.hh"
35 #include "pism/hydrology/Routing.hh"
36 #include "pism/hydrology/SteadyState.hh"
37 #include "pism/hydrology/Distributed.hh"
38 #include "pism/stressbalance/StressBalance.hh"
39 #include "pism/util/ConfigInterface.hh"
40 #include "pism/util/Time.hh"
41 #include "pism/util/error_handling.hh"
42 #include "pism/util/io/File.hh"
43 #include "pism/coupler/OceanModel.hh"
44 #include "pism/coupler/SurfaceModel.hh"
45 #include "pism/coupler/atmosphere/Factory.hh"
46 #include "pism/coupler/ocean/Factory.hh"
47 #include "pism/coupler/ocean/Initialization.hh"
48 #include "pism/coupler/ocean/sea_level/Factory.hh"
49 #include "pism/coupler/ocean/sea_level/Initialization.hh"
50 #include "pism/coupler/surface/Factory.hh"
51 #include "pism/coupler/surface/Initialization.hh"
52 #include "pism/earth/LingleClark.hh"
53 #include "pism/earth/BedDef.hh"
54 #include "pism/earth/Given.hh"
55 #include "pism/util/Vars.hh"
56 #include "pism/util/projection.hh"
57 #include "pism/util/pism_utilities.hh"
58 #include "pism/age/AgeModel.hh"
59 #include "pism/age/Isochrones.hh"
60 #include "pism/energy/EnthalpyModel.hh"
61 #include "pism/energy/TemperatureModel.hh"
62 #include "pism/fracturedensity/FractureDensity.hh"
63 #include "pism/frontretreat/FrontRetreat.hh"
64 #include "pism/frontretreat/PrescribedRetreat.hh"
65 #include "pism/coupler/frontalmelt/Factory.hh"
66 #include "pism/coupler/util/options.hh" // ForcingOptions
67 #include "pism/util/ScalarForcing.hh"
68 #include "pism/stressbalance/ShallowStressBalance.hh"
69 #include "pism/util/array/Forcing.hh"
70 #include <memory>
71 
72 namespace pism {
73 
74 //! Initialize time from an input file or command-line options.
76 
77  bool use_calendar = m_config->get_flag("output.runtime.time_use_calendar");
78 
79  if (use_calendar) {
80  m_log->message(2,
81  "* Run time: [%s, %s] (%s years, using the '%s' calendar)\n",
82  m_time->date(m_time->start()).c_str(),
83  m_time->date(m_time->end()).c_str(),
84  m_time->run_length().c_str(),
85  m_time->calendar().c_str());
86  } else {
87  std::string time_units = m_config->get_string("output.runtime.time_unit_name");
88 
89  double
90  start = m_time->convert_time_interval(m_time->start(), time_units),
91  end = m_time->convert_time_interval(m_time->end(), time_units),
92  length = end - start;
93 
94  m_log->message(2,
95  "* Run time: [%f %s, %f %s] (%f %s)\n",
96  start, time_units.c_str(),
97  end, time_units.c_str(),
98  length, time_units.c_str());
99  }
100 }
101 
102 //! Sets the starting values of model state variables.
103 /*!
104  There are two cases:
105 
106  1) Initializing from a PISM output file.
107 
108  2) Setting the values using command-line options only (verification and
109  simplified geometry runs, for example) or from a bootstrapping file, using
110  heuristics to fill in missing and 3D fields.
111 
112  Calls IceModel::regrid().
113 
114  This function is called after all the memory allocation is done and all the
115  physical parameters are set.
116 
117  Calling this method should be all one needs to set model state variables.
118  Please avoid modifying them in other parts of the initialization sequence.
119 
120  Also, please avoid operations that would make it unsafe to call this more
121  than once (memory allocation is one example).
122  */
124 
125  // Check if we are initializing from a PISM output file:
127 
128  const bool use_input_file = input.type == INIT_BOOTSTRAP or input.type == INIT_RESTART;
129 
130  std::unique_ptr<File> input_file;
131 
132  if (use_input_file) {
133  input_file.reset(new File(m_grid->com, input.filename, io::PISM_GUESS, io::PISM_READONLY));
134  }
135 
136  // Initialize 2D fields owned by IceModel (ice geometry, etc)
137  {
138  switch (input.type) {
139  case INIT_RESTART:
140  restart_2d(*input_file, input.record);
141  break;
142  case INIT_BOOTSTRAP:
143  bootstrap_2d(*input_file);
144  break;
145  case INIT_OTHER:
146  default:
147  initialize_2d();
148  }
149 
150  regrid();
151  }
152 
153  // Get projection information and compute latitudes and longitudes *before* a component
154  // decides to use them...
155  {
156  if (use_input_file) {
157  std::string mapping_name = m_grid->get_mapping_info().mapping.get_name();
158  MappingInfo info = get_projection_info(*input_file, mapping_name,
159  m_ctx->unit_system());
160 
161  if (not info.proj.empty()) {
162  m_log->message(2, "* Got projection parameters \"%s\" from \"%s\".\n",
163  info.proj.c_str(), input.filename.c_str());
164  }
165 
166  m_output_global_attributes["proj"] = info.proj;
167  m_grid->set_mapping_info(info);
168 
169  std::string history = input_file->read_text_attribute("PISM_GLOBAL", "history");
170  m_output_global_attributes["history"] = history + m_output_global_attributes.get_string("history");
171 
172  }
173 
174  compute_lat_lon();
175  }
176 
177  m_sea_level->init(m_geometry);
178 
179  // Initialize a bed deformation model.
180  if (m_beddef) {
181  m_beddef->init(input, m_geometry.ice_thickness, m_sea_level->elevation());
182  m_grid->variables().add(m_beddef->bed_elevation());
183  m_grid->variables().add(m_beddef->uplift());
184  }
185 
186  // Now ice thickness, bed elevation, and sea level are available, so we can compute the ice
187  // surface elevation and the cell type mask. This also ensures consistency of ice geometry.
188  //
189  // The stress balance code is executed near the beginning of a step and ice geometry is
190  // updated near the end, so during the second time step the stress balance code is
191  // guaranteed not to see "icebergs". Here we make sure that the first time step is OK
192  // too.
194 
195  // By now ice geometry is set (including regridding) and so we can initialize the ocean model,
196  // which may need ice thickness, bed topography, and the cell type mask.
197  {
198  m_ocean->init(m_geometry);
199  }
200 
201  // Now surface elevation is initialized, so we can initialize surface models (some use
202  // elevation-based parameterizations of surface temperature and/or mass balance).
203  m_surface->init(m_geometry);
204 
206 
207  switch (input.type) {
208  case INIT_RESTART:
209  m_subglacial_hydrology->restart(*input_file, input.record);
210  break;
211  case INIT_BOOTSTRAP:
212  m_subglacial_hydrology->bootstrap(*input_file,
214  break;
215  case INIT_OTHER:
216  {
218  &W_till = *m_work2d[0],
219  &W = *m_work2d[1],
220  &P = *m_work2d[2];
221 
222  W_till.set(m_config->get_number("bootstrapping.defaults.tillwat"));
223  W.set(m_config->get_number("bootstrapping.defaults.bwat"));
224  P.set(m_config->get_number("bootstrapping.defaults.bwp"));
225 
226  m_subglacial_hydrology->init(W_till, W, P);
227  break;
228  }
229  }
230  }
231 
232  // basal_yield_stress_model->init() needs till water thickness so this must happen
233  // after subglacial_hydrology->init()
235  auto inputs = yield_stress_inputs();
236 
237  switch (input.type) {
238  case INIT_RESTART:
239  m_basal_yield_stress_model->restart(*input_file, input.record);
240  break;
241  case INIT_BOOTSTRAP:
242  m_basal_yield_stress_model->bootstrap(*input_file, inputs);
243  break;
244  default:
245  case INIT_OTHER:
246  m_basal_yield_stress_model->init(inputs);
247  }
248  m_basal_yield_stress.copy_from(m_basal_yield_stress_model->basal_material_yield_stress());
249  }
250 
251  // Initialize the bedrock thermal layer model.
252  //
253  // If
254  // - PISM is bootstrapping and
255  // - we are using a non-zero-thickness thermal layer
256  //
257  // initialization of m_btu requires the temperature at the top of the bedrock. This is a problem
258  // because get_bed_top_temp() uses the enthalpy field that is not initialized until later and
259  // bootstrapping enthalpy uses the flux through the bottom surface of the ice (top surface of the
260  // bedrock) provided by m_btu.
261  //
262  // We get out of this by using the fact that the full state of m_btu is not needed and
263  // bootstrapping of the temperature field can be delayed.
264  //
265  // Note that to bootstrap m_btu we use the steady state solution of the heat equation in columns
266  // of the bedrock (a straight line at each column), so the flux through the top surface of the
267  // bedrock after bootstrapping is the same as the time-independent geothermal flux applied at the
268  // BOTTOM surface of the bedrock layer.
269  //
270  // The code then delays bootstrapping of the thickness field until the first time step.
271  if (m_btu != nullptr) {
272  m_btu->init(input);
273  }
274 
275  if (m_age_model) {
276  m_age_model->init(input);
277  m_grid->variables().add(m_age_model->age());
278  }
279 
280  if (m_isochrones) {
281  if (input.type == INIT_RESTART) {
282  m_isochrones->restart(*input_file, (int)input.record);
283  } else {
285  }
286  }
287 
288  // Initialize the energy balance sub-model.
289  {
290  switch (input.type) {
291  case INIT_RESTART:
292  {
293  m_energy_model->restart(*input_file, input.record);
294  break;
295  }
296  case INIT_BOOTSTRAP:
297  {
298 
299  m_energy_model->bootstrap(*input_file,
301  m_surface->temperature(),
302  m_surface->mass_flux(),
303  m_btu->flux_through_top_surface());
304  break;
305  }
306  case INIT_OTHER:
307  default:
308  {
309  m_basal_melt_rate.set(m_config->get_number("bootstrapping.defaults.bmelt"));
310 
311  m_energy_model->initialize(m_basal_melt_rate,
313  m_surface->temperature(),
314  m_surface->mass_flux(),
315  m_btu->flux_through_top_surface());
316 
317  }
318  }
319  m_grid->variables().add(m_energy_model->enthalpy());
320  }
321 
322  // this has to go after we add enthalpy to m_grid->variables()
323  if (m_stress_balance) {
324  m_stress_balance->init();
325  }
326 
327  // we keep ice thickness fixed at all the locations where the sliding (SSA) velocity is
328  // prescribed
329  {
331 
332  for (auto p = m_grid->points(); p; p.next()) {
333  const int i = p.i(), j = p.j();
334 
335  if (m_velocity_bc_mask.as_int(i, j) != 0) {
336  m_ice_thickness_bc_mask(i, j) = 1.0;
337  }
338  }
339  }
340 
341  // miscellaneous steps
342  {
343  reset_counters();
344 
345  auto startstr = pism::printf("PISM (%s) started on %d procs.",
346  pism::revision, (int)m_grid->size());
347  prepend_history(startstr + args_string());
348  }
349 }
350 
351 //! Initialize 2D model state fields managed by IceModel from a file (for re-starting).
352 /*!
353  * This method should eventually go away as IceModel turns into a "coupler" and all physical
354  * processes are handled by sub-models.
355  */
356 void IceModel::restart_2d(const File &input_file, unsigned int last_record) {
357  std::string filename = input_file.filename();
358 
359  m_log->message(2, "initializing 2D fields from NetCDF file '%s'...\n", filename.c_str());
360 
361  for (auto *variable : m_model_state) {
362  variable->read(input_file, last_record);
363  }
364 }
365 
366 void IceModel::bootstrap_2d(const File &input_file) {
367 
368  m_log->message(2, "bootstrapping from file '%s'...\n", input_file.filename().c_str());
369 
370  auto usurf = input_file.find_variable("usurf", "surface_altitude");
371 
372  bool mask_found = input_file.find_variable("mask");
373 
374  // now work through all the 2d variables, regridding if present and otherwise
375  // setting to default values appropriately
376 
377  if (mask_found) {
378  m_log->message(2, " WARNING: 'mask' found; IGNORING IT!\n");
379  }
380 
381  if (usurf.exists) {
382  m_log->message(2, " WARNING: surface elevation 'usurf' found; IGNORING IT!\n");
383  }
384 
385  m_log->message(2, " reading 2D model state variables by regridding ...\n");
386 
387  // longitude
388  {
389  m_geometry.longitude.regrid(input_file, io::Default(0.0));
390 
391  auto lon = input_file.find_variable("lon", "longitude");
392 
393  if (not lon.exists) {
394  m_geometry.longitude.metadata()["missing_at_bootstrap"] = "true";
395  }
396  }
397 
398  // latitude
399  {
400  m_geometry.latitude.regrid(input_file, io::Default(0.0));
401 
402  auto lat = input_file.find_variable("lat", "latitude");
403 
404  if (not lat.exists) {
405  m_geometry.latitude.metadata()["missing_at_bootstrap"] = "true";
406  }
407  }
408 
410  input_file, io::Default(m_config->get_number("bootstrapping.defaults.ice_thickness")));
411 
412  if (m_config->get_flag("geometry.part_grid.enabled")) {
413  // Read the Href field from an input file. This field is
414  // grid-dependent, so interpolating it from one grid to a
415  // different one does not make sense in general.
416  // (IceModel::Href_cleanup() will take care of the side effects of
417  // such interpolation, though.)
418  //
419  // On the other hand, we need to read it in to be able to re-start
420  // from a PISM output file using the -bootstrap option.
422  }
423 
424  if (m_config->get_flag("stress_balance.ssa.dirichlet_bc")) {
425  // Do not use Dirichlet B.C. anywhere if bc_mask is not present.
426  m_velocity_bc_mask.regrid(input_file, io::Default(0.0));
427  // In absence of u_bc and v_bc in the file the only B.C. that make sense are the
428  // zero Dirichlet B.C.
429  m_velocity_bc_values.regrid(input_file, io::Default(0.0));
430  } else {
431  m_velocity_bc_mask.set(0.0);
433  }
434 
435  m_ice_thickness_bc_mask.regrid(input_file, io::Default(0.0));
436 
437  // check if Lz is valid
438  auto max_thickness = array::max(m_geometry.ice_thickness);
439 
440  if (max_thickness > m_grid->Lz()) {
441  throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Max. ice thickness (%3.3f m)\n"
442  "exceeds the height of the computational domain (%3.3f m).",
443  max_thickness, m_grid->Lz());
444  }
445 }
446 
448  // This method should NOT have the "noreturn" attribute. (This attribute does not mix with virtual
449  // methods).
450  throw RuntimeError(PISM_ERROR_LOCATION, "cannot initialize IceModel without an input file");
451 }
452 
453 //! Manage regridding based on user options.
455 
456  auto filename = m_config->get_string("input.regrid.file");
457  auto regrid_vars = set_split(m_config->get_string("input.regrid.vars"), ',');
458 
459  // Return if no regridding is requested:
460  if (filename.empty()) {
461  return;
462  }
463 
464  m_log->message(2, "regridding from file %s ...\n", filename.c_str());
465 
466  {
467  File regrid_file(m_grid->com, filename, io::PISM_GUESS, io::PISM_READONLY);
468  for (auto *v : m_model_state) {
469  if (regrid_vars.find(v->get_name()) != regrid_vars.end()) {
470  v->regrid(regrid_file, io::Default::Nil());
471  }
472  }
473 
474  // Check the range of the ice thickness.
475  {
476  double
477  max_thickness = array::max(m_geometry.ice_thickness),
478  Lz = m_grid->Lz();
479 
480  if (max_thickness >= Lz + 1e-6) {
481  throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Maximum ice thickness (%f meters)\n"
482  "exceeds the height of the computational domain (%f meters).",
483  max_thickness, Lz);
484  }
485  }
486  }
487 }
488 
489 //! \brief Decide which stress balance model to use.
491 
492  if (m_stress_balance) {
493  return;
494  }
495 
496  m_log->message(2, "# Allocating a stress balance model...\n");
497 
498  // false means "not regional"
499  m_stress_balance = stressbalance::create(m_config->get_string("stress_balance.model"),
500  m_grid, false);
501 
502  m_submodels["stress balance"] = m_stress_balance.get();
503 }
504 
506  if (m_geometry_evolution) {
507  return;
508  }
509 
510  m_log->message(2, "# Allocating the geometry evolution model...\n");
511 
513 
514  m_submodels["geometry_evolution"] = m_geometry_evolution.get();
515 }
516 
517 
519 
520  if (m_iceberg_remover != NULL) {
521  return;
522  }
523 
524  m_log->message(2,
525  "# Allocating an iceberg remover (part of a calving model)...\n");
526 
527  if (m_config->get_flag("geometry.remove_icebergs")) {
528 
529  auto model = m_config->get_string("stress_balance.model");
530  auto ssa_method = m_config->get_string("stress_balance.ssa.method");
531 
532  if ((member(model, {"ssa", "ssa+sia"}) and ssa_method == "fem") or
533  model == "blatter") {
534  m_iceberg_remover = std::make_shared<calving::IcebergRemoverFEM>(m_grid);
535  } else {
536  m_iceberg_remover = std::make_shared<calving::IcebergRemover>(m_grid);
537  }
538 
539  m_submodels["iceberg remover"] = m_iceberg_remover.get();
540  }
541 }
542 
544 
545  if (m_age_model) {
546  return;
547  }
548 
549  if (m_config->get_flag("age.enabled")) {
550  m_log->message(2, "# Allocating an ice age model...\n");
551 
552  if (m_stress_balance == nullptr) {
554  "Cannot allocate an age model: m_stress_balance == nullptr.");
555  }
556 
557  m_age_model = std::make_shared<AgeModel>(m_grid, m_stress_balance);
558  m_submodels["age model"] = m_age_model.get();
559  }
560 }
561 
563 
564  if (m_isochrones) {
565  return;
566  }
567 
568  auto deposition_times = m_config->get_string("isochrones.deposition_times");
569  if (not deposition_times.empty()) {
570  m_log->message(2, "# Allocating isochrone tracking...\n");
571 
572  if (m_stress_balance == nullptr) {
575  "Cannot allocate the isochrone tracking model: m_stress_balance == nullptr.");
576  }
577 
578  m_isochrones = std::make_shared<Isochrones>(m_grid, m_stress_balance);
579 
580  m_submodels["isochrones"] = m_isochrones.get();
581  }
582 }
583 
585 
586  if (m_energy_model != NULL) {
587  return;
588  }
589 
590  m_log->message(2, "# Allocating an energy balance model...\n");
591 
592  if (m_config->get_flag("energy.enabled")) {
593  if (m_config->get_flag("energy.temperature_based")) {
594  m_energy_model = std::make_shared<energy::TemperatureModel>(m_grid, m_stress_balance);
595  } else {
596  m_energy_model = std::make_shared<energy::EnthalpyModel>(m_grid, m_stress_balance);
597  }
598  } else {
599  m_energy_model = std::make_shared<energy::DummyEnergyModel>(m_grid, m_stress_balance);
600  }
601 
602  m_submodels["energy balance model"] = m_energy_model.get();
603 }
604 
605 
606 //! \brief Decide which bedrock thermal unit to use.
608 
609  if (m_btu != nullptr) {
610  return;
611  }
612 
613  m_log->message(2, "# Allocating a bedrock thermal layer model...\n");
614 
616 
617  m_submodels["bedrock thermal model"] = m_btu.get();
618 }
619 
620 //! \brief Decide which subglacial hydrology model to use.
622 
623  using namespace pism::hydrology;
624 
625  std::string hydrology_model = m_config->get_string("hydrology.model");
626 
627  if (m_subglacial_hydrology) { // indicates it has already been allocated
628  return;
629  }
630 
631  m_log->message(2, "# Allocating a subglacial hydrology model...\n");
632 
633  if (hydrology_model == "null") {
635  } else if (hydrology_model == "routing") {
637  } else if (hydrology_model == "steady") {
639  } else if (hydrology_model == "distributed") {
641  } else {
643  "unknown 'hydrology.model': %s", hydrology_model.c_str());
644  }
645 
646  m_submodels["subglacial hydrology"] = m_subglacial_hydrology.get();
647 }
648 
649 //! \brief Decide which basal yield stress model to use.
651 
653  return;
654  }
655 
656  m_log->message(2,
657  "# Allocating a basal yield stress model...\n");
658 
659  std::string model = m_config->get_string("stress_balance.model");
660 
661  // only these two use the yield stress (so far):
662  if (member(model, {"ssa", "ssa+sia", "blatter"})) {
663  std::string yield_stress_model = m_config->get_string("basal_yield_stress.model");
664 
665  if (yield_stress_model == "constant") {
666  m_basal_yield_stress_model = std::make_shared<ConstantYieldStress>(m_grid);
667  } else if (yield_stress_model == "mohr_coulomb") {
668  m_basal_yield_stress_model = std::make_shared<MohrCoulombYieldStress>(m_grid);
669  } else if (yield_stress_model == "tillphi_opt") {
670  m_basal_yield_stress_model = std::make_shared<OptTillphiYieldStress>(m_grid);
671  } else {
672  throw RuntimeError::formatted(PISM_ERROR_LOCATION, "yield stress model '%s' is not supported.",
673  yield_stress_model.c_str());
674  }
675 
676  m_submodels["basal yield stress"] = m_basal_yield_stress_model.get();
677  }
678 }
679 
680 //! Allocate PISM's sub-models implementing some physical processes.
681 /*!
682  This method is called after memory allocation but before filling any of
683  Arrays because all the physical parameters should be initialized before
684  setting up the coupling or filling model-state variables.
685  */
687 
689 
691 
693 
694  // this has to happen *after* allocate_stressbalance()
695  {
700  }
701 
702  // this has to happen *after* allocate_subglacial_hydrology()
704 
706 
708 
710 
711  if (m_config->get_flag("fracture_density.enabled")) {
712  m_fracture = std::make_shared<FractureDensity>(m_grid, m_stress_balance->shallow()->flow_law());
713  m_submodels["fracture_density"] = m_fracture.get();
714  }
715 }
716 
717 
719  // Initialize boundary models:
720 
721  if (not m_surface) {
722 
723  m_log->message(2, "# Allocating a surface process model or coupler...\n");
724 
726 
727  m_surface = std::make_shared<surface::InitializationHelper>(m_grid, ps.create());
728 
729  m_submodels["surface process model"] = m_surface.get();
730  }
731 
732  if (not m_sea_level) {
733  m_log->message(2, "# Allocating sea level forcing...\n");
734 
735  using namespace ocean::sea_level;
736 
737  m_sea_level = std::make_shared<InitializationHelper>(m_grid, Factory(m_grid).create());
738 
739  m_submodels["sea level forcing"] = m_sea_level.get();
740  }
741 
742  if (not m_ocean) {
743  m_log->message(2, "# Allocating an ocean model or coupler...\n");
744 
745  using namespace ocean;
746 
747  m_ocean = std::make_shared<InitializationHelper>(m_grid, Factory(m_grid).create());
748 
749  m_submodels["ocean model"] = m_ocean.get();
750  }
751 }
752 
753 //! Miscellaneous initialization tasks plus tasks that need the fields that can come from regridding.
755 
756  m_log->message(3, "Finishing initialization...\n");
758 
759  if (not (opts.type == INIT_OTHER)) {
760  // initializing from a file
762 
763  std::string source = file.read_text_attribute("PISM_GLOBAL", "source");
764 
765  if (opts.type == INIT_RESTART) {
766  // If it's missing, print a warning
767  if (source.empty()) {
768  m_log->message(1,
769  "PISM WARNING: file '%s' does not have the 'source' global attribute.\n"
770  " If '%s' is a PISM output file, please run the following to get rid of this warning:\n"
771  " ncatted -a source,global,c,c,PISM %s\n",
772  opts.filename.c_str(), opts.filename.c_str(), opts.filename.c_str());
773  } else if (source.find("PISM") == std::string::npos) {
774  // If the 'source' attribute does not contain the string "PISM", then print
775  // a message and stop:
776  m_log->message(1,
777  "PISM WARNING: '%s' does not seem to be a PISM output file.\n"
778  " If it is, please make sure that the 'source' global attribute contains the string \"PISM\".\n",
779  opts.filename.c_str());
780  }
781  }
782  }
783 
784  {
785  // A single record of a time-dependent variable cannot exceed 2^32-4
786  // bytes in size. See the NetCDF User's Guide
787  // <http://www.unidata.ucar.edu/software/netcdf/docs/netcdf.html#g_t64-bit-Offset-Limitations>.
788  // Here we use "long int" to avoid integer overflow.
789  const long int two_to_thirty_two = 4294967296L;
790  const long int
791  Mx = m_grid->Mx(),
792  My = m_grid->My(),
793  Mz = m_grid->Mz();
794  std::string output_format = m_config->get_string("output.format");
795  if (Mx * My * Mz * sizeof(double) > two_to_thirty_two - 4 and
796  (output_format == io::PISM_NETCDF3)) {
798  "The computational grid is too big to fit in a NetCDF-3 file.\n"
799  "Each 3D variable requires %lu Mb.\n"
800  "Please use '-o_format pnetcdf or -o_format netcdf4_parallel to proceed.",
801  Mx * My * Mz * sizeof(double) / (1024 * 1024));
802  }
803  }
804 
805  m_output_vars = output_variables(m_config->get_string("output.size"));
806 
807 #if (Pism_USE_PROJ==1)
808  {
809  std::string proj_string = m_grid->get_mapping_info().proj;
810  if (not proj_string.empty()) {
811  m_output_vars.insert("lon_bnds");
812  m_output_vars.insert("lat_bnds");
813  }
814  }
815 #endif
816 
817  init_calving();
821  init_snapshots();
823  init_timeseries();
824  init_extras();
825 
826  // a report on whether PISM-PIK modifications of IceModel are in use
827  {
828  std::vector<std::string> pik_methods;
829  if (m_config->get_flag("geometry.part_grid.enabled")) {
830  pik_methods.push_back("part_grid");
831  }
832  if (m_config->get_flag("geometry.remove_icebergs")) {
833  pik_methods.push_back("kill_icebergs");
834  }
835 
836  if (not pik_methods.empty()) {
837  m_log->message(2,
838  "* PISM-PIK mass/geometry methods are in use: %s\n",
839  join(pik_methods, ", ").c_str());
840  }
841  }
842 
843  // initialize diagnostics
844  {
845  // reset: this gives diagnostics a chance to capture the current state of the model at the
846  // beginning of the run
847  for (const auto& d : m_diagnostics) {
848  d.second->reset();
849  }
850 
851  // read in the state (accumulators) if we are re-starting a run
852  if (opts.type == INIT_RESTART) {
854  for (const auto& d : m_diagnostics) {
855  d.second->init(file, opts.record);
856  }
857  }
858  }
859 
861  ForcingOptions surface_input(*m_ctx, "hydrology.surface_input");
862  m_surface_input_for_hydrology->init(surface_input.filename,
863  surface_input.periodic);
864  }
865 
866  if (m_fracture) {
867  if (opts.type == INIT_OTHER) {
868  m_fracture->initialize();
869  } else {
870  // initializing from a file
872 
873  if (opts.type == INIT_RESTART) {
874  m_fracture->restart(file, opts.record);
875  } else if (opts.type == INIT_BOOTSTRAP) {
876  m_fracture->bootstrap(file);
877  }
878  }
879  }
880 }
881 
883 
884  auto frontal_melt = m_config->get_string("frontal_melt.models");
885 
886  if (not frontal_melt.empty()) {
887  if (not m_config->get_flag("geometry.part_grid.enabled")) {
889  "ERROR: frontal melt models require geometry.part_grid.enabled");
890  }
891 
893 
894  m_frontal_melt->init(m_geometry);
895 
896  m_submodels["frontal melt"] = m_frontal_melt.get();
897 
898  if (not m_front_retreat) {
899  m_front_retreat = std::make_shared<FrontRetreat>(m_grid);
900  }
901  }
902 }
903 
905  auto front_retreat_file = m_config->get_string("geometry.front_retreat.prescribed.file");
906 
907  if (not front_retreat_file.empty()) {
908  m_prescribed_retreat = std::make_shared<PrescribedRetreat>(m_grid);
909 
910  m_prescribed_retreat->init();
911 
912  m_submodels["prescribed front retreat"] = m_prescribed_retreat.get();
913  }
914 }
915 
916 //! \brief Initialize calving mechanisms.
918 
919  std::set<std::string> methods = set_split(m_config->get_string("calving.methods"), ',');
920  bool allocate_front_retreat = false;
921 
922  if (member("thickness_calving", methods)) {
923 
925  m_thickness_threshold_calving = std::make_shared<calving::CalvingAtThickness>(m_grid);
926  }
927 
929  methods.erase("thickness_calving");
930 
931  m_submodels["thickness threshold calving"] = m_thickness_threshold_calving.get();
932  }
933 
934 
935  if (member("eigen_calving", methods)) {
936  allocate_front_retreat = true;
937 
938  if (not m_eigen_calving) {
939  m_eigen_calving = std::make_shared<calving::EigenCalving>(m_grid);
940  }
941 
942  m_eigen_calving->init();
943  methods.erase("eigen_calving");
944 
945  m_submodels["eigen calving"] = m_eigen_calving.get();
946  }
947 
948  if (member("vonmises_calving", methods)) {
949  allocate_front_retreat = true;
950 
951  if (not m_vonmises_calving) {
952  m_vonmises_calving = std::make_shared<calving::vonMisesCalving>(
953  m_grid, m_stress_balance->shallow()->flow_law());
954  }
955 
956  m_vonmises_calving->init();
957  methods.erase("vonmises_calving");
958 
959  m_submodels["von Mises calving"] = m_vonmises_calving.get();
960  }
961 
962  if (member("hayhurst_calving", methods)) {
963  allocate_front_retreat = true;
964 
965  if (not m_hayhurst_calving) {
966  m_hayhurst_calving = std::make_shared<calving::HayhurstCalving>(m_grid);
967  }
968 
969  m_hayhurst_calving->init();
970  methods.erase("hayhurst_calving");
971 
972  m_submodels["Hayhurst calving"] = m_hayhurst_calving.get();
973  }
974 
975  if (member("float_kill", methods)) {
976  if (not m_float_kill_calving) {
977  m_float_kill_calving = std::make_shared<calving::FloatKill>(m_grid);
978  }
979 
980  m_float_kill_calving->init();
981  methods.erase("float_kill");
982 
983  m_submodels["float kill calving"] = m_float_kill_calving.get();
984  }
985 
986  if (not methods.empty()) {
988  "PISM ERROR: calving method(s) [%s] are not supported.\n",
989  set_join(methods, ",").c_str());
990  }
991 
992  // allocate front retreat code if necessary
993  if (not m_front_retreat and allocate_front_retreat) {
994  m_front_retreat = std::make_shared<FrontRetreat>(m_grid);
995  }
996 
997  {
998  auto filename = m_config->get_string("calving.rate_scaling.file");
999  if (not filename.empty()) {
1001  "calving.rate_scaling",
1002  "frac_calving_rate",
1003  "1",
1004  "1",
1005  "calving rate scaling factor"));
1006  }
1007  }
1008 }
1009 
1011  if (m_beddef) {
1012  return;
1013  }
1014 
1015  m_log->message(2,
1016  "# Allocating a bed deformation model...\n");
1017 
1018  std::string model = m_config->get_string("bed_deformation.model");
1019 
1020  if (model == "none") {
1021  m_beddef = std::make_shared<bed::Null>(m_grid);
1022  }
1023  else if (model == "iso") {
1024  m_beddef = std::make_shared<bed::PointwiseIsostasy>(m_grid);
1025  }
1026  else if (model == "lc") {
1027  m_beddef = std::make_shared<bed::LingleClark>(m_grid);
1028  }
1029  else if (model == "given") {
1030  m_beddef = std::make_shared<bed::Given>(m_grid);
1031  }
1032 
1033  m_submodels["bed deformation"] = m_beddef.get();
1034 }
1035 
1036 //! Read some runtime (command line) options and alter the
1037 //! corresponding parameters or flags as appropriate.
1039 
1040  m_log->message(3,
1041  "Processing physics-related command-line options...\n");
1042 
1044  m_config->resolve_filenames();
1045 
1046  // Set global attributes using the config database:
1047  m_output_global_attributes["title"] = m_config->get_string("run_info.title");
1048  m_output_global_attributes["institution"] = m_config->get_string("run_info.institution");
1049  m_output_global_attributes["command"] = args_string();
1050 
1051  // warn about some option combinations
1052 
1053  if (m_config->get_number("time_stepping.maximum_time_step") <= 0) {
1054  throw RuntimeError(PISM_ERROR_LOCATION, "time_stepping.maximum_time_step has to be greater than 0.");
1055  }
1056 
1057  if (not m_config->get_flag("geometry.update.enabled") &&
1058  m_config->get_flag("time_stepping.skip.enabled")) {
1059  m_log->message(2,
1060  "PISM WARNING: Both -skip and -no_mass are set.\n"
1061  " -skip only makes sense in runs updating ice geometry.\n");
1062  }
1063 
1064  if (m_config->get_string("calving.methods").find("thickness_calving") != std::string::npos &&
1065  not m_config->get_flag("geometry.part_grid.enabled")) {
1066  m_log->message(2,
1067  "PISM WARNING: Calving at certain terminal ice thickness (-calving thickness_calving)\n"
1068  " without application of partially filled grid cell scheme (-part_grid)\n"
1069  " may lead to (incorrect) non-moving ice shelf front.\n");
1070  }
1071 }
1072 
1073 //! Assembles a list of diagnostics corresponding to an output file size.
1074 std::set<std::string> IceModel::output_variables(const std::string &keyword) {
1075 
1076  std::string variables;
1077 
1078  if (keyword == "none" or
1079  keyword == "small") {
1080  variables = "";
1081  } else if (keyword == "medium") {
1082  variables = m_config->get_string("output.sizes.medium");
1083  } else if (keyword == "big_2d") {
1084  variables = (m_config->get_string("output.sizes.medium") + "," +
1085  m_config->get_string("output.sizes.big_2d"));
1086  } else if (keyword == "big") {
1087  variables = (m_config->get_string("output.sizes.medium") + "," +
1088  m_config->get_string("output.sizes.big_2d") + "," +
1089  m_config->get_string("output.sizes.big"));
1090  }
1091 
1092  return set_split(variables, ',');
1093 }
1094 
1096 
1097  std::string projection = m_grid->get_mapping_info().proj;
1098 
1099  if (m_config->get_flag("grid.recompute_longitude_and_latitude") and
1100  not projection.empty()) {
1101  m_log->message(2,
1102  "* Computing longitude and latitude using projection parameters...\n");
1103 
1104  compute_longitude(projection, m_geometry.longitude);
1105  m_geometry.longitude.metadata()["missing_at_bootstrap"] = "";
1106  compute_latitude(projection, m_geometry.latitude);
1107  m_geometry.latitude.metadata()["missing_at_bootstrap"] = "";
1108  }
1109 }
1110 
1111 } // end of namespace pism
VariableLookupData find_variable(const std::string &short_name, const std::string &std_name) const
Find a variable using its standard name and/or short name.
Definition: File.cc:361
std::string filename() const
Definition: File.cc:307
std::string read_text_attribute(const std::string &var_name, const std::string &att_name) const
Get a text attribute.
Definition: File.cc:693
High-level PISM I/O class.
Definition: File.hh:56
array::Scalar1 ice_area_specific_volume
Definition: Geometry.hh:52
array::Scalar2 ice_thickness
Definition: Geometry.hh:51
array::Scalar longitude
Definition: Geometry.hh:42
array::Scalar latitude
Definition: Geometry.hh:41
std::map< std::string, const Component * > m_submodels
the list of sub-models, for writing model states and obtaining diagnostics
Definition: IceModel.hh:259
void enforce_consistency_of_geometry(ConsistencyFlag flag)
Update the surface elevation and the flow-type mask when the geometry has changed.
Definition: IceModel.cc:293
virtual void allocate_bed_deformation()
virtual void model_state_setup()
Sets the starting values of model state variables.
void init_checkpoints()
Initialize checkpointing (snapshot-on-wallclock-time) mechanism.
std::shared_ptr< stressbalance::StressBalance > m_stress_balance
Definition: IceModel.hh:397
std::shared_ptr< Isochrones > m_isochrones
Definition: IceModel.hh:270
virtual void init_calving()
Initialize calving mechanisms.
std::shared_ptr< ocean::OceanModel > m_ocean
Definition: IceModel.hh:287
std::shared_ptr< surface::SurfaceModel > m_surface
Definition: IceModel.hh:286
const Config::Ptr m_config
Configuration flags and parameters.
Definition: IceModel.hh:243
virtual void compute_lat_lon()
std::shared_ptr< FractureDensity > m_fracture
Definition: IceModel.hh:306
virtual void bootstrap_2d(const File &input_file)
const Time::Ptr m_time
Time manager.
Definition: IceModel.hh:251
Geometry m_geometry
Definition: IceModel.hh:295
std::shared_ptr< YieldStress > m_basal_yield_stress_model
Definition: IceModel.hh:262
std::shared_ptr< calving::IcebergRemover > m_iceberg_remover
Definition: IceModel.hh:272
virtual void initialize_2d()
std::shared_ptr< frontalmelt::FrontalMelt > m_frontal_melt
Definition: IceModel.hh:288
void init_extras()
Initialize the code saving spatially-variable diagnostic quantities.
array::Scalar m_basal_melt_rate
rate of production of basal meltwater (ice-equivalent); no ghosts
Definition: IceModel.hh:302
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
std::shared_ptr< array::Forcing > m_surface_input_for_hydrology
Definition: IceModel.hh:264
virtual void allocate_stressbalance()
Decide which stress balance model to use.
std::shared_ptr< calving::EigenCalving > m_eigen_calving
Definition: IceModel.hh:275
std::unique_ptr< ScalarForcing > m_calving_rate_factor
Definition: IceModel.hh:282
VariableMetadata m_output_global_attributes
stores global attributes saved in a PISM output file
Definition: IceModel.hh:256
const array::Scalar & frontal_melt() const
Definition: IceModel.cc:935
virtual void allocate_iceberg_remover()
std::vector< std::shared_ptr< array::Scalar2 > > m_work2d
Definition: IceModel.hh:393
virtual void process_options()
std::shared_ptr< calving::CalvingAtThickness > m_thickness_threshold_calving
Definition: IceModel.hh:274
std::shared_ptr< calving::FloatKill > m_float_kill_calving
Definition: IceModel.hh:273
virtual void allocate_subglacial_hydrology()
Decide which subglacial hydrology model to use.
std::shared_ptr< PrescribedRetreat > m_prescribed_retreat
Definition: IceModel.hh:278
array::Scalar2 m_velocity_bc_mask
mask to determine Dirichlet boundary locations for the sliding velocity
Definition: IceModel.hh:309
void reset_counters()
Definition: IceModel.cc:144
virtual void prepend_history(const std::string &string)
Get time and user/host name and add it to the given string.
Definition: utilities.cc:115
std::shared_ptr< calving::HayhurstCalving > m_hayhurst_calving
Definition: IceModel.hh:276
virtual void allocate_basal_yield_stress()
Decide which basal yield stress model to use.
std::unique_ptr< GeometryEvolution > m_geometry_evolution
Definition: IceModel.hh:296
virtual void allocate_energy_model()
virtual void restart_2d(const File &input_file, unsigned int record)
Initialize 2D model state fields managed by IceModel from a file (for re-starting).
virtual void time_setup()
Initialize time from an input file or command-line options.
std::shared_ptr< energy::BedThermalUnit > m_btu
Definition: IceModel.hh:266
std::set< array::Array * > m_model_state
Definition: IceModel.hh:417
array::Scalar1 m_ice_thickness_bc_mask
Mask prescribing locations where ice thickness is held constant.
Definition: IceModel.hh:314
std::shared_ptr< AgeModel > m_age_model
Definition: IceModel.hh:269
virtual void init_front_retreat()
virtual void allocate_bedrock_thermal_unit()
Decide which bedrock thermal unit to use.
virtual std::set< std::string > output_variables(const std::string &keyword)
Assembles a list of diagnostics corresponding to an output file size.
virtual void regrid()
Manage regridding based on user options.
const units::System::Ptr m_sys
Unit system.
Definition: IceModel.hh:247
array::Vector2 m_velocity_bc_values
Dirichlet boundary velocities.
Definition: IceModel.hh:311
virtual void allocate_geometry_evolution()
std::map< std::string, Diagnostic::Ptr > m_diagnostics
Requested spatially-variable diagnostics.
Definition: IceModel.hh:419
void init_snapshots()
Initializes the snapshot-saving mechanism.
Definition: output_save.cc:42
std::shared_ptr< ocean::sea_level::SeaLevel > m_sea_level
Definition: IceModel.hh:289
virtual void allocate_age_model()
virtual YieldStressInputs yield_stress_inputs()
Definition: IceModel.cc:378
virtual void init_diagnostics()
virtual void allocate_couplers()
std::unique_ptr< hydrology::Hydrology > m_subglacial_hydrology
Definition: IceModel.hh:261
std::shared_ptr< calving::vonMisesCalving > m_vonmises_calving
Definition: IceModel.hh:277
void init_timeseries()
Initializes the code writing scalar time-series.
Definition: output_ts.cc:45
std::set< std::string > m_output_vars
Definition: IceModel.hh:424
virtual void allocate_isochrones()
virtual void init_frontal_melt()
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
std::shared_ptr< bed::BedDef > m_beddef
Definition: IceModel.hh:291
virtual void allocate_submodels()
Allocate PISM's sub-models implementing some physical processes.
std::shared_ptr< FrontRetreat > m_front_retreat
Definition: IceModel.hh:284
array::Scalar2 m_basal_yield_stress
ghosted
Definition: IceModel.hh:300
std::string proj
Definition: projection.hh:47
virtual std::shared_ptr< Model > create()
Creates a boundary model. Processes command-line options.
Definition: PCFactory.hh:42
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
std::string get_string(const std::string &name) const
Get a string attribute.
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition: Array.hh:65
void copy_from(const Array2D< T > &source)
Definition: Array2D.hh:73
void set(double c)
Result: v[j] <- c for all j.
Definition: Array.cc:707
void regrid(const std::string &filename, io::Default default_value)
Definition: Array.cc:814
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
Definition: Array.cc:553
int as_int(int i, int j) const
Definition: Scalar.hh:45
static std::shared_ptr< BedThermalUnit > FromOptions(std::shared_ptr< const Grid > g, std::shared_ptr< const Context > ctx)
The PISM subglacial hydrology model for a distributed linked-cavity system.
Definition: Distributed.hh:43
A subglacial hydrology model which assumes water pressure equals overburden pressure.
Definition: Routing.hh:81
static Default Nil()
Definition: IO_Flags.hh:97
#define PISM_ERROR_LOCATION
double max(const array::Scalar &input)
Finds maximum over all the values in an array::Scalar object. Ignores ghosts.
Definition: Scalar.cc:165
static std::vector< double > deposition_times(const File &input_file)
Definition: Isochrones.cc:180
Sub-glacial hydrology models and related diagnostics.
Definition: Distributed.cc:29
@ PISM_GUESS
Definition: IO_Flags.hh:56
@ PISM_NETCDF3
Definition: IO_Flags.hh:57
@ PISM_READONLY
open an existing file for reading only
Definition: IO_Flags.hh:72
bool ocean(int M)
An ocean cell (floating ice or ice-free).
Definition: Mask.hh:40
std::shared_ptr< StressBalance > create(const std::string &model, std::shared_ptr< const Grid > grid, bool regional)
Definition: factory.cc:38
InputOptions process_input_options(MPI_Comm com, Config::ConstPtr config)
Definition: Component.cc:43
void compute_latitude(const std::string &projection, array::Scalar &result)
Definition: projection.cc:422
@ INIT_BOOTSTRAP
Definition: Component.hh:56
@ INIT_OTHER
Definition: Component.hh:56
@ INIT_RESTART
Definition: Component.hh:56
std::string set_join(const std::set< std::string > &input, const std::string &separator)
std::string printf(const char *format,...)
void compute_longitude(const std::string &projection, array::Scalar &result)
Definition: projection.cc:419
std::set< std::string > set_split(const std::string &input, char separator)
Transform a separator-separated list (a string) into a set of strings.
bool member(const std::string &string, const std::set< std::string > &set)
void set_config_from_options(units::System::Ptr unit_system, Config &config)
Set configuration parameters using command-line options.
std::string args_string()
Uses argc and argv to create the string with current PISM command-line arguments.
MappingInfo get_projection_info(const File &input_file, const std::string &mapping_name, units::System::Ptr unit_system)
Get projection info from a file.
Definition: projection.cc:198
std::string join(const std::vector< std::string > &strings, const std::string &separator)
Concatenate strings, inserting separator between elements.
std::string filename
Definition: options.hh:33
InitializationType type
initialization type
Definition: Component.hh:61
std::string filename
name of the input file (if applicable)
Definition: Component.hh:63
unsigned int record
index of the record to re-start from
Definition: Component.hh:65