PISM, A Parallel Ice Sheet Model 2.3.2-fa1174726 committed by Constantine Khrulev on 2026-04-08
Loading...
Searching...
No Matches
IceModel.cc
Go to the documentation of this file.
1// Copyright (C) 2004-2026 Jed Brown, 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#include <cmath>
20#include <cstring>
21#include <algorithm>
22#include <memory>
23#include <petscsys.h>
24
25#include "pism/icemodel/IceModel.hh"
26
27#include "pism/basalstrength/YieldStress.hh"
28#include "pism/frontretreat/util/IcebergRemover.hh"
29#include "pism/energy/BedThermalUnit.hh"
30#include "pism/hydrology/Hydrology.hh"
31#include "pism/stressbalance/StressBalance.hh"
32#include "pism/util/Grid.hh"
33#include "pism/util/Config.hh"
34#include "pism/util/Diagnostic.hh"
35#include "pism/util/error_handling.hh"
36#include "pism/coupler/SeaLevel.hh"
37#include "pism/coupler/OceanModel.hh"
38#include "pism/coupler/SurfaceModel.hh"
39#include "pism/earth/BedDef.hh"
40#include "pism/util/pism_signal.h"
41#include "pism/util/Vars.hh"
42#include "pism/util/Profiling.hh"
43#include "pism/util/pism_utilities.hh"
44#include "pism/age/AgeModel.hh"
45#include "pism/age/Isochrones.hh"
46#include "pism/energy/EnergyModel.hh"
47#include "pism/util/io/File.hh"
48#include "pism/util/array/Forcing.hh"
49#include "pism/fracturedensity/FractureDensity.hh"
50#include "pism/coupler/util/options.hh" // ForcingOptions
51#include "pism/coupler/ocean/PyOceanModel.hh"
52#include "pism/util/io/SynchronousOutputWriter.hh"
53#include "pism/util/io/IO_Flags.hh"
54
55#if (Pism_USE_YAC == 1)
56#include "pism/util/io/YacOutputWriter.hh"
57#endif
58
59namespace pism {
60
61IceModel::IceModel(std::shared_ptr<Grid> grid, const std::shared_ptr<Context> &context)
62 : m_grid(grid),
63 m_config(context->config()),
64 m_ctx(context),
65 m_sys(context->unit_system()),
66 m_log(context->log()),
67 m_time(context->time()),
68 m_output_global_attributes("PISM_GLOBAL", m_sys),
69 m_geometry(m_grid),
70 m_new_bed_elevation(true),
71 m_basal_yield_stress(m_grid, "tauc"),
72 m_basal_melt_rate(m_grid, "bmelt"),
73 m_bedtoptemp(m_grid, "bedtoptemp"),
74 m_velocity_bc_mask(m_grid, "vel_bc_mask"),
75 m_velocity_bc_values(m_grid, "_bc"), // u_bc and v_bc
76 m_ice_thickness_bc_mask(grid, "thk_bc_mask"),
77 m_step_counter(0),
78 m_thickness_change(grid),
79 m_scalar_times(new std::vector<double>()) {
80
83
84 pism_signal = 0;
85 signal(SIGTERM, pism_signal_handler);
86 signal(SIGUSR1, pism_signal_handler);
87 signal(SIGUSR2, pism_signal_handler);
88
89 m_surface = nullptr;
90 m_ocean = nullptr;
91 m_beddef = nullptr;
92
93 m_btu = nullptr;
94 m_energy_model = nullptr;
95
96 // Set global attributes:
97 m_output_global_attributes["Conventions"] = "CF-1.6";
99 m_output_global_attributes["title"] = m_config->get_string("run_info.title");
100 m_output_global_attributes["institution"] = m_config->get_string("run_info.institution");
102
103 m_fracture = nullptr;
104
106
107 // allocate temporary storage
108 {
109 // 2d work vectors
110 for (int j = 0; j < m_n_work2d; j++) {
111 m_work2d.push_back(
112 std::make_shared<array::Scalar2>(m_grid, pism::printf("work_vector_%d", j)));
113 }
114 }
115
116 auto surface_input_file = m_config->get_string("hydrology.surface_input.file");
117 if (not surface_input_file.empty()) {
118 ForcingOptions surface_input(*m_ctx, "hydrology.surface_input");
119 int buffer_size = static_cast<int>(m_config->get_number("input.forcing.buffer_size"));
120
121 File file(m_grid->com, surface_input.filename, io::PISM_NETCDF3, io::PISM_READONLY);
122
124 std::make_shared<array::Forcing>(m_grid, file, "water_input_rate",
125 "", // no standard name
126 buffer_size, surface_input.periodic);
128 .long_name("water input rate for the subglacial hydrology model")
129 .units("kg m^-2 s^-1")
130 .output_units("kg m^-2 year^-1");
131 m_surface_input_for_hydrology->metadata()["valid_min"] = { 0.0 };
132 }
133
134 m_output_writer = std::make_shared<SynchronousOutputWriter>(m_grid->com, *m_config);
137
138#if (Pism_USE_YAC == 1)
139 if (pism::yac_component_defined("pism_output")) {
140 auto yac_writer = std::make_shared<YacOutputWriter>(m_grid->com, *m_config);
141
142 m_snapshot_writer = yac_writer;
143 m_spatial_writer = yac_writer;
144 }
145#endif
146}
147
148double IceModel::dt() const {
149 return m_dt;
150}
151
153 m_dt_TempAge = 0.0;
154 m_dt = 0.0;
156
157 {
158 int year_increment = static_cast<int>(m_config->get_number("time_stepping.hit_multiples"));
159
160 if (year_increment > 0) {
161 // start year:
162 auto year = m_time->units().date(m_time->current(), m_time->calendar()).year;
163
164 int last_multiple = year - year % year_increment;
165 // correct last_multiple if 'year' is negative
166 // and not a multiple of year_increment:
167 last_multiple -= year_increment * static_cast<int>(year % year_increment < 0);
168
169 units::DateTime last_date{ last_multiple, 1, 1, 0, 0, 0.0 };
170
171 m_timestep_hit_multiples_last_time = m_time->units().time(last_date, m_time->calendar());
172 } else {
174 }
175 }
176}
177
178
180 // empty; defined here to be able to use more forward-declared classes in IceModel.hh
181}
182
183
184//! Allocate all Arrays defined in IceModel.
185/*!
186 This procedure allocates the memory used to store model state, diagnostic and
187 work vectors and sets metadata.
188
189 Default values should not be set here; please use set_vars_from_options().
190
191 All the memory allocated here is freed by Arrays' destructors.
192*/
194
195 // FIXME: this should do for now, but we should pass a const reference to Geometry to sub-models
196 // as a function argument.
197 m_grid->variables().add(m_geometry.ice_surface_elevation);
198 m_grid->variables().add(m_geometry.ice_thickness);
199 m_grid->variables().add(m_geometry.cell_type);
200 m_grid->variables().add(m_geometry.sea_level_elevation);
201 m_grid->variables().add(m_geometry.longitude);
202 m_grid->variables().add(m_geometry.latitude);
203
204 if (m_config->get_flag("geometry.grounded_cell_fraction")) {
205 m_grid->variables().add(m_geometry.cell_grounded_fraction);
206 }
207
208 if (m_config->get_flag("geometry.part_grid.enabled")) {
210 }
211
212 // yield stress for basal till (plastic or pseudo-plastic model)
213 {
214 // PROPOSED standard_name = land_ice_basal_material_yield_stress
216 .long_name("yield stress for basal till (plastic or pseudo-plastic model)")
217 .units("Pa");
218 m_grid->variables().add(m_basal_yield_stress);
219 }
220
221 {
223 .long_name("temperature at the top surface of the bedrock thermal layer")
224 .units("kelvin");
225 }
226
227 // basal melt rate
229 .long_name(
230 "ice basal melt rate from energy conservation and subshelf melt, in ice thickness per time")
231 .units("m s^-1")
232 .output_units("m year^-1")
233 .standard_name("land_ice_basal_melt_rate");
234 m_basal_melt_rate.metadata()["comment"] = "positive basal melt rate corresponds to ice loss";
235 m_grid->variables().add(m_basal_melt_rate);
236
237 // Sliding velocity (usually SSA) Dirichlet B.C. locations and values
238 {
240 .long_name("Mask prescribing Dirichlet boundary locations for the sliding velocity")
242 .set_time_dependent(false);
243 m_velocity_bc_mask.metadata()["flag_values"] = { 0, 1 };
244 m_velocity_bc_mask.metadata()["flag_meanings"] = "no_data boundary_condition";
245
247 }
248 // SSA Dirichlet B.C. values
249 {
250 double fill_value = m_config->get_number("output.fill_value");
251 const double huge_value = 1e6;
252 // vel_bc
254 "X-component of the SSA velocity boundary conditions");
256 "Y-component of the SSA velocity boundary conditions");
257 for (int j : { 0, 1 }) {
258 m_velocity_bc_values.metadata(j)["valid_range"] = { -huge_value, huge_value };
259 m_velocity_bc_values.metadata(j)["_FillValue"] = { fill_value };
261 }
262 }
263
264 // Ice thickness BC mask
265 {
267 .long_name("Mask specifying locations where ice thickness is held constant")
268 .set_time_dependent(false)
270 m_ice_thickness_bc_mask.metadata()["flag_values"] = {0, 1};
271 m_ice_thickness_bc_mask.metadata()["flag_meanings"] = "no_data boundary_condition";
272
274 }
275
276 // Add some variables to the list of "model state" fields.
284}
285
286//! Update the surface elevation and the flow-type mask when the geometry has changed.
287/*!
288 This procedure should be called whenever necessary to maintain consistency of geometry.
289
290 For instance, it should be called when either ice thickness or bed elevation change.
291 In particular we always want \f$h = H + b\f$ to apply at grounded points, and, on the
292 other hand, we want the mask to reflect that the ice is floating if the flotation
293 criterion applies at a point.
294
295 If `flag == REMOVE_ICEBERGS`, also calls the code which removes icebergs, to avoid
296 stress balance solver problems caused by ice that is not attached to the grounded ice
297 sheet.
298*/
300
301 m_geometry.bed_elevation.copy_from(m_beddef->bed_elevation());
303
304 if (m_iceberg_remover and flag == REMOVE_ICEBERGS) {
305 // The iceberg remover has to use the same mask as the stress balance code, hence the
306 // stress-balance-related threshold here.
307 m_geometry.ensure_consistency(m_config->get_number("stress_balance.ice_free_thickness_standard"));
308
312 // The call above modifies ice thickness and updates the mask accordingly, but we re-compute the
313 // mask (we need to use a different threshold).
314 }
315
316 // This will ensure that ice area specific volume is zero if ice thickness is greater
317 // than zero, then compute new surface elevation and mask.
318 m_geometry.ensure_consistency(m_config->get_number("geometry.ice_free_thickness_standard"));
319
320 if (flag == REMOVE_ICEBERGS) {
321 // clean up partially-filled cells that are not next to ice
324
325 for (auto p : m_grid->points()) {
326 const int i = p.i(), j = p.j();
327
328 if (m_geometry.ice_area_specific_volume(i, j) > 0.0 and
329 not m_geometry.cell_type.next_to_ice(i, j)) {
331 }
332 }
333 }
334}
335
338 if (m_config->get_flag("geometry.update.use_basal_melt_rate")) {
340 }
341
343 result.geometry = &m_geometry;
345 result.enthalpy = &m_energy_model->enthalpy();
346 result.age = m_age_model ? &m_age_model->age() : nullptr;
347
348 result.water_column_pressure = &m_ocean->average_water_column_pressure();
349
350 if (m_config->get_flag("stress_balance.ssa.dirichlet_bc")) {
351 result.bc_mask = &m_velocity_bc_mask;
353 }
354
355 if (m_config->get_flag("fracture_density.enabled")) {
356 result.fracture_density = &m_fracture->density();
357 }
358
359 return result;
360}
361
363 energy::Inputs result;
364
365 result.basal_frictional_heating = &m_stress_balance->basal_frictional_heating();
366 result.basal_heat_flux = &m_btu->flux_through_top_surface(); // bedrock thermal layer
367 result.cell_type = &m_geometry.cell_type; // geometry
368 result.ice_thickness = &m_geometry.ice_thickness; // geometry
369 result.shelf_base_temp = &m_ocean->shelf_base_temperature(); // ocean model
370 result.till_water_thickness = &m_subglacial_hydrology->till_water_thickness();
371 result.surface_liquid_fraction = &m_surface->liquid_water_fraction(); // surface model
372 result.surface_temp = &m_surface->temperature(); // surface model
373
374 result.volumetric_heating_rate = &m_stress_balance->volumetric_strain_heating();
375 result.u3 = &m_stress_balance->velocity_u();
376 result.v3 = &m_stress_balance->velocity_v();
377 result.w3 = &m_stress_balance->velocity_w();
378
379 result.check(); // make sure all data members were set
380
381 return result;
382}
383
385 YieldStressInputs result;
386
387 result.geometry = &m_geometry;
388 result.till_water_thickness = &m_subglacial_hydrology->till_water_thickness();
389 result.subglacial_water_thickness = &m_subglacial_hydrology->subglacial_water_thickness();
390
391 return result;
392}
393
394//! The contents of the main PISM time-step.
395/*!
396During the time-step we perform the following actions:
397 */
398double IceModel::step(bool do_mass_continuity,
399 bool do_skip) {
400
402
403 const Profiling &profiling = m_ctx->profiling();
404
405 double current_time = m_time->current();
406
407 //! \li call pre_step_hook() to let derived classes do more
409
410 //! \li update the velocity field; in some cases the whole three-dimensional
411 //! field is updated and in some cases just the vertically-averaged
412 //! horizontal velocity is updated
413
414 // always "update" ice velocity (possibly trivially); only update
415 // SSA and only update velocities at depth if suggested by temp and age
416 // stability criterion; note *lots* of communication is avoided by skipping
417 // SSA (and temp/age)
418
419 const bool updateAtDepth = (m_skip_countdown == 0);
420
421 // Combine basal melt rate in grounded (computed during the energy
422 // step) and floating (provided by an ocean model) areas.
423 //
424 // Basal melt rate may be used by a stress balance model to compute vertical velocity of
425 // ice.
426 {
428 m_ocean->shelf_base_mass_flux(),
429 m_energy_model->basal_melt_rate(),
431 }
432
433 try {
434 profiling.begin("stress_balance");
435 m_stress_balance->update(stress_balance_inputs(), updateAtDepth);
436 profiling.end("stress_balance");
437 } catch (RuntimeError &e) {
438 std::string output_file = save_state_on_error("_stressbalance_failed", {});
439
440 e.add_context("performing a time step. (Note: Model state was saved to '%s'.)",
441 output_file.c_str());
442 throw;
443 }
444
445
446 m_stdout_flags += m_stress_balance->stdout_report();
447
448 m_stdout_flags += (updateAtDepth ? "v" : "V");
449
450 //! \li determine the time step according to a variety of stability criteria
451 auto dt_info = max_timestep(m_skip_countdown);
452 double dt = dt_info.dt;
453
454 m_adaptive_timestep_reason = dt_info.reason;
455 m_skip_countdown = dt_info.skip_counter;
456
457 //! \li update the yield stress for the plastic till model (if appropriate)
459 profiling.begin("basal_yield_stress");
460 m_basal_yield_stress_model->update(yield_stress_inputs(), current_time, dt);
461 profiling.end("basal_yield_stress");
462 m_basal_yield_stress.copy_from(m_basal_yield_stress_model->basal_material_yield_stress());
463 m_stdout_flags += "y";
464 } else {
465 m_stdout_flags += "$";
466 }
467
468 m_dt_TempAge += dt;
469
470 //! \li update the age of the ice (if appropriate)
471 if (m_age_model and updateAtDepth) {
472 AgeModelInputs inputs;
474 inputs.u3 = &m_stress_balance->velocity_u();
475 inputs.v3 = &m_stress_balance->velocity_v();
476 inputs.w3 = &m_stress_balance->velocity_w();
477
478 profiling.begin("age");
479 m_age_model->update(m_t_TempAge, m_dt_TempAge, inputs);
480 profiling.end("age");
481 m_stdout_flags += "a";
482 } else {
483 m_stdout_flags += "$";
484 }
485
486 //! \li update the enthalpy (or temperature) field according to the conservation of
487 //! energy model based (especially) on the new velocity field; see
488 //! energy_step()
489 if (updateAtDepth) { // do the energy step
490 profiling.begin("energy");
492 profiling.end("energy");
493 m_stdout_flags += "E";
494 } else {
495 m_stdout_flags += "$";
496 }
497
498 //! \li update the fracture density field; see update_fracture_density()
499 if (m_config->get_flag("fracture_density.enabled")) {
500 profiling.begin("fracture_density");
502 profiling.end("fracture_density");
503 }
504
505 //! \li update the thickness of the ice according to the mass conservation model and calving
506 //! parameterizations
507
508 if (do_mass_continuity) {
509 // reset the conservation error field:
510 m_geometry_evolution->reset();
511
512 profiling.begin("mass_transport");
513 {
514 // Note that there are three adaptive time-stepping criteria. Two of them (using max.
515 // diffusion and 2D CFL) are limiting the mass-continuity time-step and the third (3D
516 // CFL) limits the energy and age time-steps.
517
518 // The mass-continuity time-step is usually smaller, and the skipping mechanism lets us
519 // do several mass-continuity steps for each energy step.
520
521 // When -no_mass is set, mass-continuity-related time-step restrictions are disabled,
522 // making "skipping" unnecessary.
523
524 // This is why the following two lines appear here and are executed only if
525 // do_mass_continuity is true.
526 if (do_skip and m_skip_countdown > 0) {
528 }
529
530 try {
532 dt,
533 m_stress_balance->advective_velocity(),
534 m_stress_balance->diffusive_flux(),
536 } catch (RuntimeError &e) {
537 std::string output_file = save_state_on_error("_mass_transport_failed",
538 {"flux_staggered", "flux_divergence"});
539
540 e.add_context("performing a mass transport time step (dt=%f s). (Note: Model state was saved to '%s'.)",
541 dt, output_file.c_str());
542 throw;
543 }
544
545 m_geometry_evolution->apply_flux_divergence(m_geometry);
546
548 }
549 profiling.end("mass_transport");
550
551 // calving, frontal melt, and discharge accounting
552 profiling.begin("front_retreat");
553 front_retreat_step(current_time, dt);
554 profiling.end("front_retreat");
555
556 m_stdout_flags += "h";
557 } else {
558 m_stdout_flags += "$";
559 }
560
561 profiling.begin("sea_level");
562 m_sea_level->update(m_geometry, current_time, dt);
563 profiling.end("sea_level");
564
565 profiling.begin("ocean");
566 {
567 ocean::Inputs inputs;
568 inputs.geometry = &m_geometry;
569 m_ocean->update(inputs, current_time, dt);
570 }
571 profiling.end("ocean");
572
573 // The sea level elevation might have changed, so we need to update the mask, etc. Note
574 // that THIS MAY PRODUCE ICEBERGS, but we assume that the surface model does not care.
576
577 //! \li Update surface and ocean models.
578 profiling.begin("surface");
579 m_surface->update(m_geometry, current_time, dt);
580 profiling.end("surface");
581
582
583 if (do_mass_continuity) {
584 // compute and apply effective surface and basal mass balance
585
586 m_geometry_evolution->source_term_step(m_geometry, dt,
588 m_surface->mass_flux(),
590 m_geometry_evolution->apply_mass_fluxes(m_geometry);
591
592 // add removed icebergs to discharge due to calving
593 {
594 auto &old_H = *m_work2d[0], &old_Href = *m_work2d[1];
595
596 {
597 old_H.copy_from(m_geometry.ice_thickness);
598 old_Href.copy_from(m_geometry.ice_area_specific_volume);
599 }
600
601 // the last call has to remove icebergs
603
604 bool add_values = true;
607 old_H, old_Href,
608 add_values,
610 }
611 }
612
613 if (m_isochrones) {
614 m_isochrones->update(current_time, dt,
615 m_stress_balance->velocity_u(),
616 m_stress_balance->velocity_v(),
618 m_geometry_evolution->top_surface_mass_balance(),
619 m_geometry_evolution->bottom_surface_mass_balance());
620 }
621
622 //! \li update the state variables in the subglacial hydrology model (typically
623 //! water thickness and sometimes pressure)
624 profiling.begin("basal_hydrology");
625 hydrology_step(current_time, dt);
626 profiling.end("basal_hydrology");
627
628 //! \li compute the bed deformation, which depends on current thickness, bed elevation,
629 //! and sea level
630 if (m_beddef) {
631 int topg_state_counter = m_beddef->bed_elevation().state_counter();
632
633 profiling.begin("bed_deformation");
636 current_time, dt);
637 profiling.end("bed_deformation");
638
639 m_new_bed_elevation = m_beddef->bed_elevation().state_counter() != topg_state_counter;
640 } else {
641 m_new_bed_elevation = false;
642 }
643
644 if (m_config->get_flag("time_stepping.assume_bed_elevation_changed")) {
645 m_new_bed_elevation = true;
646 }
647
650 m_stdout_flags += "b";
651 } else {
652 m_stdout_flags += " ";
653 }
654
655 //! \li call post_step_hook() to let derived classes do more
657
658 // Done with the step; now adopt the new time. Note that this has to happen before we
659 // update m_t_TempAge below.
660 m_time->step(dt);
661
662 if (updateAtDepth) {
663 m_t_TempAge = m_time->current();
664 m_dt_TempAge = 0.0;
665 }
666
667 // Check if the ice thickness exceeded the height of the computational box and stop if it did.
668 if (max(m_geometry.ice_thickness) > m_grid->Lz()) {
669 auto o_file = save_state_on_error("_max_thickness", {});
670
672 "Ice thickness exceeds the height of the computational box (%7.4f m).\n"
673 "The model state was saved to '%s'. To continue this simulation,\n"
674 "run with\n"
675 "-i %s -bootstrap -regrid_file %s -allow_extrapolation -Lz N [other options]\n"
676 "where N > %7.4f.",
677 m_grid->Lz(), o_file.c_str(), o_file.c_str(), o_file.c_str(), m_grid->Lz());
678 }
679
680 // end the flag line
682
683 return dt;
684}
685
686/*!
687 * Note: don't forget to update IceRegionalModel::hydrology_step() if necessary.
688 */
689void IceModel::hydrology_step(double t, double dt) {
690 hydrology::Inputs inputs;
691
692 array::Scalar &sliding_speed = *m_work2d[0];
693 compute_magnitude(m_stress_balance->advective_velocity(), sliding_speed);
694
695 inputs.no_model_mask = nullptr;
696 inputs.geometry = &m_geometry;
697 inputs.surface_input_rate = nullptr;
699 inputs.ice_sliding_speed = &sliding_speed;
700
705 } else if (m_config->get_flag("hydrology.surface_input_from_runoff")) {
706 // convert [kg m-2] to [kg m-2 s-1]
707 array::Scalar &surface_input_rate = *m_work2d[1];
708 surface_input_rate.copy_from(m_surface->runoff());
709 surface_input_rate.scale(1.0 / dt);
710 inputs.surface_input_rate = &surface_input_rate;
711 }
712
713 m_subglacial_hydrology->update(t, dt, inputs);
714}
715
716//! Virtual. Does nothing in `IceModel`. Derived classes can do more computation in each time step.
718 // empty
719}
720
721//! Virtual. Does nothing in `IceModel`. Derived classes can do more computation in each time step.
723 // empty
724}
725
726/**
727 * Run the time-stepping loop from the current model time to `time`.
728 *
729 * This should be called by the coupler controlling PISM when it is
730 * running alongside a GCM.
731 *
732 * @param run_end model time (in seconds) to run to
733 *
734 * @return 0 on success
735 */
737
738 m_time->set_end(run_end);
739
740 return run();
741}
742
743
744/**
745 * Run the time-stepping loop from the current time until the time
746 * specified by the IceModel::grid::time object.
747 *
748 * This is the method used by PISM in the "standalone" mode.
749 */
751 const Profiling &profiling = m_ctx->profiling();
752
753 bool do_mass_conserve = m_config->get_flag("geometry.update.enabled");
754 bool do_energy = set_member(m_config->get_string("energy.model"), {"cold", "enthalpy"});
755 bool do_skip = m_config->get_flag("time_stepping.skip.enabled");
756
757 // Enforce consistency *and* remove icebergs. During time-stepping we remove icebergs at
758 // the end of the time step, so we need to ensure that ice geometry is "OK" before the
759 // first step.
761
762 // Update spatially-variable diagnostics at the beginning of the run.
764
765 // Update scalar time series to remember the state at the beginning of the run.
766 // This is needed to compute rates of change of the ice mass, volume, etc.
767 {
768 const double time = m_time->current();
769 for (const auto &d : m_available_scalar_diagnostics) {
770 d.second->update(time, time);
771 }
772 }
773
774 m_log->message(2, "running forward ...\n");
775
776 m_stdout_flags.erase(); // clear it out
777 print_summary_line(true, do_energy, 0.0, 0.0, 0.0, 0.0, 0.0);
778 print_summary(do_energy, 0.0 /* time step length is not known yet */); // report starting state
779
780 m_t_TempAge = m_time->current();
781 m_dt_TempAge = 0.0;
782
783 IceModelTerminationReason termination_reason = PISM_DONE;
784 // main loop for time evolution
785 // IceModel::step calls Time::step(dt), ensuring that this while loop
786 // will terminate
787 profiling.stage_begin("time-stepping loop");
788 while (m_time->current() < m_time->end()) {
789
790 m_stdout_flags.erase(); // clear it out
791
792 m_dt = step(do_mass_conserve, do_skip);
793
794 update_diagnostics(m_time->current(), dt());
795
796 // report a summary for major steps or the last one
797 bool updateAtDepth = m_skip_countdown == 0;
798 bool tempAgeStep = updateAtDepth and (m_age_model or do_energy);
799
800 double time_resolution = m_config->get_number("time_stepping.resolution");
801 const bool show_step = tempAgeStep or fabs(m_time->current() - m_time->end()) < time_resolution;
802 print_summary(show_step, dt());
803
804 // update viewers before writing extras because writing extras resets diagnostics
806
807 // writing these fields here ensures that we do it after the last time-step
808 profiling.begin("io");
811 bool stop_after_chekpoint = write_checkpoint();
812 profiling.end("io");
813
814 if (stop_after_chekpoint) {
815 termination_reason = PISM_CHEKPOINT;
816 break;
817 }
818
819 if (process_signals() != 0) {
820 termination_reason = PISM_SIGNAL;
821 break;
822 }
823 } // end of the time-stepping loop
824 profiling.stage_end("time-stepping loop");
825
826 return termination_reason;
827}
828
829//! Manage the initialization of the IceModel object.
830/*!
831Please see the documenting comments of the functions called below to find
832explanations of their intended uses.
833 */
835 // Get the start time in seconds and ensure that it is consistent
836 // across all processors.
838
839 const Profiling &profiling = m_ctx->profiling();
840
841 InputOptions input_options = process_input_options(m_ctx->com(), m_config);
842
843 profiling.begin("initialization");
844
845 //! The IceModel initialization sequence is this:
846
847 //! 1) Warn about some option combinations
848 {
849 if (not m_config->get_flag("geometry.update.enabled") &&
850 m_config->get_flag("time_stepping.skip.enabled")) {
851 m_log->message(2,
852 "PISM WARNING: time_stepping.skip.enabled is 'true' and\n"
853 " geometry.update.enabled is 'false'\n"
854 " skipping time steps makes sense only with evolving geometry.\n");
855 }
856 }
857
858 // 2) Report run duration
859 {
860 bool use_calendar = m_config->get_flag("output.runtime.time_use_calendar");
861
862 if (use_calendar) {
863 m_log->message(2, "* Run time: [%s, %s] (%s years, using the '%s' calendar)\n",
864 m_time->date(m_time->start()).c_str(), m_time->date(m_time->end()).c_str(),
865 m_time->run_length().c_str(), m_time->calendar().c_str());
866 } else {
867 std::string time_units = m_config->get_string("output.runtime.time_unit_name");
868
869 double start = m_time->convert_time_interval(m_time->start(), time_units),
870 end = m_time->convert_time_interval(m_time->end(), time_units), length = end - start;
871
872 m_log->message(2, "* Run time: [%f %s, %f %s] (%f %s)\n", start, time_units.c_str(), end,
873 time_units.c_str(), length, time_units.c_str());
874 }
875 }
876
877 //! 3) Memory allocation:
879
880 //! 4) Allocate PISM components modeling some physical processes.
882
883 //! 6) Initialize coupler models and fill the model state variables
884 //! (from a PISM output file, from a bootstrapping file using some
885 //! modeling choices or using formulas). Calls IceModel::regrid()
886 model_state_setup(input_options);
887
888 //! 7) Report grid parameters:
889 m_log->message(2, "Computational domain and grid:\n");
890 m_grid->report_parameters();
891
892 //! 8) Miscellaneous stuff: set up the bed deformation model, initialize the
893 //! basal till model, initialize snapshots. This has to happen *after*
894 //! regridding.
895 misc_setup(input_options, report_type);
896
897 profiling.end("initialization");
898}
899
901 return m_geometry;
902}
903
907
909 return this->m_stress_balance.get();
910}
911
913 return m_ocean.get();
914}
915
917 return m_btu.get();
918}
919
923
927
929 return m_beddef.get();
930}
931
932/*!
933 * Return thickness change due to calving (over the last time step).
934 */
938
939/*!
940 * Return thickness change due to frontal melt (over the last time step).
941 */
945
946/*!
947 * Return thickness change due to forced retreat (over the last time step).
948 */
952
953IceModel::ThicknessChanges::ThicknessChanges(const std::shared_ptr<const Grid> &grid)
954 : calving(grid, "thickness_change_due_to_calving"),
955 frontal_melt(grid, "thickness_change_due_to_frontal_melt"),
956 forced_retreat(grid, "thickness_change_due_to_forced_retreat") {
957 // empty
958}
959
960void IceModel::set_python_ocean_model(std::shared_ptr<ocean::PyOceanModel> model) {
961 m_ocean = std::make_shared<ocean::PyOceanModelAdapter>(m_grid, model);
962 m_submodels["ocean model"] = m_ocean.get();
963}
964
965} // end of namespace pism
const array::Array3D * w3
Definition AgeModel.hh:41
const array::Array3D * v3
Definition AgeModel.hh:40
const array::Array3D * u3
Definition AgeModel.hh:39
const array::Scalar * ice_thickness
Definition AgeModel.hh:38
High-level PISM I/O class.
Definition File.hh:57
array::Scalar1 sea_level_elevation
Definition Geometry.hh:48
array::Scalar cell_grounded_fraction
Definition Geometry.hh:56
void ensure_consistency(double ice_free_thickness_threshold)
Definition Geometry.cc:116
array::Scalar2 ice_surface_elevation
Definition Geometry.hh:57
array::Scalar1 ice_area_specific_volume
Definition Geometry.hh:52
array::CellType2 cell_type
Definition Geometry.hh:55
array::Scalar2 ice_thickness
Definition Geometry.hh:51
array::Scalar longitude
Definition Geometry.hh:42
array::Scalar2 bed_elevation
Definition Geometry.hh:47
array::Scalar latitude
Definition Geometry.hh:41
std::string m_adaptive_timestep_reason
Definition IceModel.hh:364
std::map< std::string, const Component * > m_submodels
the list of sub-models, for writing model states and obtaining diagnostics
Definition IceModel.hh:297
virtual energy::Inputs energy_model_inputs()
Definition IceModel.cc:362
virtual int process_signals()
Catch signals -USR1, -USR2 and -TERM.
Definition utilities.cc:48
virtual void hydrology_step(double t, double dt)
Definition IceModel.cc:689
void enforce_consistency_of_geometry(ConsistencyFlag flag)
Update the surface elevation and the flow-type mask when the geometry has changed.
Definition IceModel.cc:299
const Geometry & geometry() const
Definition IceModel.cc:900
void compute_geometry_change(const array::Scalar &thickness, const array::Scalar &Href, const array::Scalar &thickness_old, const array::Scalar &Href_old, bool add_values, array::Scalar &output)
double m_start_time
Definition IceModel.hh:524
std::shared_ptr< stressbalance::StressBalance > m_stress_balance
Definition IceModel.hh:439
std::shared_ptr< Isochrones > m_isochrones
Definition IceModel.hh:308
IceModelTerminationReason run()
Definition IceModel.cc:750
std::shared_ptr< ocean::OceanModel > m_ocean
Definition IceModel.hh:325
virtual void post_step_hook()
Virtual. Does nothing in IceModel. Derived classes can do more computation in each time step.
Definition IceModel.cc:722
const ocean::OceanModel * ocean_model() const
Definition IceModel.cc:912
std::shared_ptr< surface::SurfaceModel > m_surface
Definition IceModel.hh:324
void write_snapshot()
Writes a snapshot of the model state (if necessary)
unsigned int m_step_counter
Definition IceModel.hh:368
virtual stressbalance::Inputs stress_balance_inputs()
Definition IceModel.cc:336
std::shared_ptr< FractureDensity > m_fracture
Definition IceModel.hh:344
std::shared_ptr< Config > m_config
Configuration flags and parameters.
Definition IceModel.hh:278
ThicknessChanges m_thickness_change
Definition IceModel.hh:454
double m_dt_TempAge
enthalpy/temperature and age time-steps
Definition IceModel.hh:360
virtual ~IceModel()
Definition IceModel.cc:179
Geometry m_geometry
Definition IceModel.hh:333
virtual void update_fracture_density(double dt)
const GeometryEvolution & geometry_evolution() const
Definition IceModel.cc:904
const stressbalance::StressBalance * stress_balance() const
Definition IceModel.cc:908
bool m_new_bed_elevation
Definition IceModel.hh:335
static const int m_n_work2d
Definition IceModel.hh:436
std::shared_ptr< YieldStress > m_basal_yield_stress_model
Definition IceModel.hh:300
std::shared_ptr< calving::IcebergRemover > m_iceberg_remover
Definition IceModel.hh:310
double m_timestep_hit_multiples_last_time
Definition IceModel.hh:515
std::shared_ptr< Context > m_ctx
Execution context.
Definition IceModel.hh:280
std::shared_ptr< Logger > m_log
Logger.
Definition IceModel.hh:284
array::Scalar m_basal_melt_rate
rate of production of basal meltwater (ice-equivalent); no ghosts
Definition IceModel.hh:340
std::shared_ptr< array::Forcing > m_surface_input_for_hydrology
Definition IceModel.hh:302
double m_t_TempAge
time of last update for enthalpy/temperature
Definition IceModel.hh:358
array::Scalar m_bedtoptemp
temperature at the top surface of the bedrock thermal layer
Definition IceModel.hh:342
const energy::EnergyModel * energy_balance_model() const
Definition IceModel.cc:920
virtual void update_diagnostics(double t, double dt)
std::shared_ptr< OutputWriter > m_snapshot_writer
Definition IceModel.hh:289
std::string save_state_on_error(const std::string &suffix, const std::set< std::string > &additional_variables)
Definition output.cc:250
VariableMetadata m_output_global_attributes
stores global attributes saved in a PISM output file
Definition IceModel.hh:293
std::shared_ptr< OutputWriter > m_spatial_writer
Definition IceModel.hh:290
std::shared_ptr< Time > m_time
Time manager.
Definition IceModel.hh:286
const array::Scalar & frontal_melt() const
Definition IceModel.cc:942
const array::Scalar & forced_retreat() const
Definition IceModel.cc:949
std::vector< std::shared_ptr< array::Scalar2 > > m_work2d
Definition IceModel.hh:437
double dt() const
Definition IceModel.cc:148
void write_spatial_diagnostics()
Write spatially-variable diagnostic quantities.
bool write_checkpoint()
Write a checkpoint (i.e. an intermediate result of a run).
virtual void allocate_storage()
Allocate all Arrays defined in IceModel.
Definition IceModel.cc:193
array::Scalar2 m_velocity_bc_mask
mask to determine Dirichlet boundary locations for the sliding velocity
Definition IceModel.hh:347
void reset_counters()
Definition IceModel.cc:152
std::string m_stdout_flags
Definition IceModel.hh:366
std::unique_ptr< GeometryEvolution > m_geometry_evolution
Definition IceModel.hh:334
virtual void energy_step(double t, double dt)
Manage the solution of the energy equation, and related parallel communication.
Definition energy.cc:60
virtual void combine_basal_melt_rate(const Geometry &geometry, const array::Scalar &shelf_base_mass_flux, const array::Scalar &grounded_basal_melt_rate, array::Scalar &result)
Combine basal melt rate in grounded and floating areas.
Definition energy.cc:85
virtual void front_retreat_step(double t, double dt)
void init(DiagnosticReport report_type=DIAG_NONE)
Manage the initialization of the IceModel object.
Definition IceModel.cc:834
std::shared_ptr< energy::BedThermalUnit > m_btu
Definition IceModel.hh:304
virtual void model_state_setup(InputOptions input_options)
Sets the starting values of model state variables.
std::set< array::Array * > m_model_state
Definition IceModel.hh:459
array::Scalar1 m_ice_thickness_bc_mask
Mask prescribing locations where ice thickness is held constant.
Definition IceModel.hh:352
std::shared_ptr< AgeModel > m_age_model
Definition IceModel.hh:307
const bed::BedDef * bed_deformation_model() const
Definition IceModel.cc:928
std::map< std::string, TSDiagnostic::Ptr > m_available_scalar_diagnostics
Available scalar diagnostics.
Definition IceModel.hh:463
array::Vector2 m_velocity_bc_values
Dirichlet boundary velocities.
Definition IceModel.hh:349
IceModel(std::shared_ptr< Grid > grid, const std::shared_ptr< Context > &context)
Definition IceModel.cc:61
std::shared_ptr< ocean::sea_level::SeaLevel > m_sea_level
Definition IceModel.hh:327
virtual void print_summary_line(bool printPrototype, bool tempAndAge, double delta_t, double volume, double area, double meltfrac, double max_diffusivity)
Print a line to stdout which summarizes the state of the modeled ice sheet at the end of the time ste...
Definition printout.cc:164
std::shared_ptr< OutputWriter > m_output_writer
Definition IceModel.hh:288
virtual double step(bool do_mass_continuity, bool do_skip)
The contents of the main PISM time-step.
Definition IceModel.cc:398
virtual void update_viewers()
Update the runtime graphical viewers.
Definition viewers.cc:58
const array::Scalar & calving() const
Definition IceModel.cc:935
virtual void pre_step_hook()
Virtual. Does nothing in IceModel. Derived classes can do more computation in each time step.
Definition IceModel.cc:717
unsigned int m_skip_countdown
Definition IceModel.hh:362
IceModelTerminationReason run_to(double run_end)
Definition IceModel.cc:736
virtual YieldStressInputs yield_stress_inputs()
Definition IceModel.cc:384
virtual void misc_setup(InputOptions input_options, DiagnosticReport report_type)
Miscellaneous initialization tasks plus tasks that need the fields that can come from regridding.
const YieldStress * basal_yield_stress_model() const
Definition IceModel.cc:924
std::unique_ptr< hydrology::Hydrology > m_subglacial_hydrology
Definition IceModel.hh:299
const energy::BedThermalUnit * bedrock_thermal_model() const
Definition IceModel.cc:916
virtual void print_summary(bool tempAndAge, double dt)
Definition printout.cc:89
void set_python_ocean_model(std::shared_ptr< ocean::PyOceanModel > model)
Definition IceModel.cc:960
double m_dt
mass continuity time step, s
Definition IceModel.hh:356
std::shared_ptr< energy::EnergyModel > m_energy_model
Definition IceModel.hh:305
const std::shared_ptr< Grid > m_grid
Computational grid.
Definition IceModel.hh:276
std::shared_ptr< bed::BedDef > m_beddef
Definition IceModel.hh:329
virtual TimesteppingInfo max_timestep(unsigned int counter)
Use various stability criteria to determine the time step for an evolution run.
virtual void allocate_submodels()
Allocate PISM's sub-models implementing some physical processes.
array::Scalar2 m_basal_yield_stress
ghosted
Definition IceModel.hh:338
void begin(const char *name) const
Definition Profiling.cc:75
void end(const char *name) const
Definition Profiling.cc:91
void stage_end(const char *name) const
Definition Profiling.cc:119
void stage_begin(const char *name) const
Definition Profiling.cc:103
void add_context(const std::string &message)
Add a message providing some context. This way we can (sort of) get a stack trace even though C++ exc...
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
VariableMetadata & long_name(const std::string &input)
VariableMetadata & units(const std::string &input)
VariableMetadata & standard_name(const std::string &input)
std::string get_string(const std::string &name) const
Get a string attribute.
VariableMetadata & output_units(const std::string &input)
VariableMetadata & set_output_type(io::Type type)
VariableMetadata & set_time_dependent(bool flag)
const array::Scalar * till_water_thickness
const array::Scalar * subglacial_water_thickness
const Geometry * geometry
The PISM basal yield stress model interface (virtual base class)
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition Array.hh:66
void copy_from(const Array2D< T > &source)
Definition Array2D.hh:101
void set_interpolation_type(InterpolationType type)
Definition Array.cc:181
void scale(double alpha)
Result: v <- v * alpha. Calls VecScale.
Definition Array.cc:227
void set(double c)
Result: v[j] <- c for all j.
Definition Array.cc:659
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
Definition Array.cc:467
bool next_to_ice(int i, int j) const
Ice-free margin (at least one of four neighbors has ice).
Definition CellType.hh:87
PISM bed deformation model (base class).
Definition BedDef.hh:37
Given the temperature of the top of the bedrock, for the duration of one time-step,...
const array::Scalar * surface_liquid_fraction
const array::Scalar1 * ice_thickness
const array::Array3D * w3
const array::Array3D * v3
const array::Scalar * shelf_base_temp
const array::Scalar * basal_heat_flux
const array::Scalar * basal_frictional_heating
const array::Scalar * till_water_thickness
const array::Array3D * u3
const array::Scalar * surface_temp
const array::CellType * cell_type
const array::Array3D * volumetric_heating_rate
const Geometry * geometry
Definition Hydrology.hh:37
const array::Scalar * ice_sliding_speed
Definition Hydrology.hh:41
const array::Scalar * surface_input_rate
Definition Hydrology.hh:39
const array::Scalar1 * no_model_mask
Definition Hydrology.hh:35
const array::Scalar * basal_melt_rate
Definition Hydrology.hh:40
A very rudimentary PISM ocean model.
Definition OceanModel.hh:38
const array::Scalar1 * fracture_density
const array::Scalar * basal_yield_stress
const array::Scalar * bc_mask
const array::Array3D * age
const array::Scalar * water_column_pressure
const array::Array3D * enthalpy
const array::Scalar * basal_melt_rate
const array::Vector * bc_values
The class defining PISM's interface to the shallow stress balance code.
#define PISM_ERROR_LOCATION
@ PISM_NETCDF3
Definition IO_Flags.hh:58
@ PISM_READONLY
open an existing file for reading only
Definition IO_Flags.hh:69
double get_time(MPI_Comm comm)
DiagnosticReport
Definition IceModel.hh:117
std::string printf(const char *format,...)
IceModelTerminationReason
Definition IceModel.hh:115
@ PISM_SIGNAL
Definition IceModel.hh:115
@ PISM_DONE
Definition IceModel.hh:115
@ PISM_CHEKPOINT
Definition IceModel.hh:115
bool yac_component_defined(const std::string &name)
std::string version()
std::string args_string()
Uses argc and argv to create the string with current PISM command-line arguments.
InputOptions process_input_options(MPI_Comm com, std::shared_ptr< const Config > config)
Definition Component.cc:45
bool set_member(const std::string &string, const std::set< std::string > &set)
volatile sig_atomic_t pism_signal
Definition pism_signal.c:23
void pism_signal_handler(int sig)
Definition pism_signal.c:25
std::string filename
Definition options.hh:33
ThicknessChanges(const std::shared_ptr< const Grid > &grid)
Definition IceModel.cc:953
const Geometry * geometry
Definition OceanModel.hh:34