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