PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
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 try {
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 } catch (RuntimeError &e) {
147 }
148#endif
149}
150
151double IceModel::dt() const {
152 return m_dt;
153}
154
156 m_dt_TempAge = 0.0;
157 m_dt = 0.0;
159
160 {
161 int year_increment = static_cast<int>(m_config->get_number("time_stepping.hit_multiples"));
162
163 if (year_increment > 0) {
164 // start year:
165 auto year = m_time->units().date(m_time->current(), m_time->calendar()).year;
166
167 int last_multiple = year - year % year_increment;
168 // correct last_multiple if 'year' is negative
169 // and not a multiple of year_increment:
170 last_multiple -= year_increment * static_cast<int>(year % year_increment < 0);
171
172 units::DateTime last_date{ last_multiple, 1, 1, 0, 0, 0.0 };
173
174 m_timestep_hit_multiples_last_time = m_time->units().time(last_date, m_time->calendar());
175 } else {
177 }
178 }
179}
180
181
183 // empty; defined here to be able to use more forward-declared classes in IceModel.hh
184}
185
186
187//! Allocate all Arrays defined in IceModel.
188/*!
189 This procedure allocates the memory used to store model state, diagnostic and
190 work vectors and sets metadata.
191
192 Default values should not be set here; please use set_vars_from_options().
193
194 All the memory allocated here is freed by Arrays' destructors.
195*/
197
198 // FIXME: this should do for now, but we should pass a const reference to Geometry to sub-models
199 // as a function argument.
200 m_grid->variables().add(m_geometry.ice_surface_elevation);
201 m_grid->variables().add(m_geometry.ice_thickness);
202 m_grid->variables().add(m_geometry.cell_type);
203 m_grid->variables().add(m_geometry.sea_level_elevation);
204 m_grid->variables().add(m_geometry.longitude);
205 m_grid->variables().add(m_geometry.latitude);
206
207 if (m_config->get_flag("geometry.grounded_cell_fraction")) {
208 m_grid->variables().add(m_geometry.cell_grounded_fraction);
209 }
210
211 if (m_config->get_flag("geometry.part_grid.enabled")) {
213 }
214
215 // yield stress for basal till (plastic or pseudo-plastic model)
216 {
217 // PROPOSED standard_name = land_ice_basal_material_yield_stress
219 .long_name("yield stress for basal till (plastic or pseudo-plastic model)")
220 .units("Pa");
221 m_grid->variables().add(m_basal_yield_stress);
222 }
223
224 {
226 .long_name("temperature at the top surface of the bedrock thermal layer")
227 .units("kelvin");
228 }
229
230 // basal melt rate
232 .long_name(
233 "ice basal melt rate from energy conservation and subshelf melt, in ice thickness per time")
234 .units("m s^-1")
235 .output_units("m year^-1")
236 .standard_name("land_ice_basal_melt_rate");
237 m_basal_melt_rate.metadata()["comment"] = "positive basal melt rate corresponds to ice loss";
238 m_grid->variables().add(m_basal_melt_rate);
239
240 // Sliding velocity (usually SSA) Dirichlet B.C. locations and values
241 {
243 .long_name("Mask prescribing Dirichlet boundary locations for the sliding velocity")
245 .set_time_dependent(false);
246 m_velocity_bc_mask.metadata()["flag_values"] = { 0, 1 };
247 m_velocity_bc_mask.metadata()["flag_meanings"] = "no_data boundary_condition";
248
250 }
251 // SSA Dirichlet B.C. values
252 {
253 double fill_value = m_config->get_number("output.fill_value");
254 const double huge_value = 1e6;
255 // vel_bc
257 "X-component of the SSA velocity boundary conditions");
259 "Y-component of the SSA velocity boundary conditions");
260 for (int j : { 0, 1 }) {
261 m_velocity_bc_values.metadata(j)["valid_range"] = { -huge_value, huge_value };
262 m_velocity_bc_values.metadata(j)["_FillValue"] = { fill_value };
264 }
265 }
266
267 // Ice thickness BC mask
268 {
270 .long_name("Mask specifying locations where ice thickness is held constant")
271 .set_time_dependent(false)
273 m_ice_thickness_bc_mask.metadata()["flag_values"] = {0, 1};
274 m_ice_thickness_bc_mask.metadata()["flag_meanings"] = "no_data boundary_condition";
275
277 }
278
279 // Add some variables to the list of "model state" fields.
287}
288
289//! Update the surface elevation and the flow-type mask when the geometry has changed.
290/*!
291 This procedure should be called whenever necessary to maintain consistency of geometry.
292
293 For instance, it should be called when either ice thickness or bed elevation change.
294 In particular we always want \f$h = H + b\f$ to apply at grounded points, and, on the
295 other hand, we want the mask to reflect that the ice is floating if the flotation
296 criterion applies at a point.
297
298 If `flag == REMOVE_ICEBERGS`, also calls the code which removes icebergs, to avoid
299 stress balance solver problems caused by ice that is not attached to the grounded ice
300 sheet.
301*/
303
304 m_geometry.bed_elevation.copy_from(m_beddef->bed_elevation());
306
307 if (m_iceberg_remover and flag == REMOVE_ICEBERGS) {
308 // The iceberg remover has to use the same mask as the stress balance code, hence the
309 // stress-balance-related threshold here.
310 m_geometry.ensure_consistency(m_config->get_number("stress_balance.ice_free_thickness_standard"));
311
315 // The call above modifies ice thickness and updates the mask accordingly, but we re-compute the
316 // mask (we need to use a different threshold).
317 }
318
319 // This will ensure that ice area specific volume is zero if ice thickness is greater
320 // than zero, then compute new surface elevation and mask.
321 m_geometry.ensure_consistency(m_config->get_number("geometry.ice_free_thickness_standard"));
322
323 if (flag == REMOVE_ICEBERGS) {
324 // clean up partially-filled cells that are not next to ice
327
328 for (auto p : m_grid->points()) {
329 const int i = p.i(), j = p.j();
330
331 if (m_geometry.ice_area_specific_volume(i, j) > 0.0 and
332 not m_geometry.cell_type.next_to_ice(i, j)) {
334 }
335 }
336 }
337}
338
341 if (m_config->get_flag("geometry.update.use_basal_melt_rate")) {
343 }
344
346 result.geometry = &m_geometry;
348 result.enthalpy = &m_energy_model->enthalpy();
349 result.age = m_age_model ? &m_age_model->age() : nullptr;
350
351 result.water_column_pressure = &m_ocean->average_water_column_pressure();
352
353 if (m_config->get_flag("stress_balance.ssa.dirichlet_bc")) {
354 result.bc_mask = &m_velocity_bc_mask;
356 }
357
358 if (m_config->get_flag("fracture_density.enabled")) {
359 result.fracture_density = &m_fracture->density();
360 }
361
362 return result;
363}
364
366 energy::Inputs result;
367
368 result.basal_frictional_heating = &m_stress_balance->basal_frictional_heating();
369 result.basal_heat_flux = &m_btu->flux_through_top_surface(); // bedrock thermal layer
370 result.cell_type = &m_geometry.cell_type; // geometry
371 result.ice_thickness = &m_geometry.ice_thickness; // geometry
372 result.shelf_base_temp = &m_ocean->shelf_base_temperature(); // ocean model
373 result.till_water_thickness = &m_subglacial_hydrology->till_water_thickness();
374 result.surface_liquid_fraction = &m_surface->liquid_water_fraction(); // surface model
375 result.surface_temp = &m_surface->temperature(); // surface model
376
377 result.volumetric_heating_rate = &m_stress_balance->volumetric_strain_heating();
378 result.u3 = &m_stress_balance->velocity_u();
379 result.v3 = &m_stress_balance->velocity_v();
380 result.w3 = &m_stress_balance->velocity_w();
381
382 result.check(); // make sure all data members were set
383
384 return result;
385}
386
388 YieldStressInputs result;
389
390 result.geometry = &m_geometry;
391 result.till_water_thickness = &m_subglacial_hydrology->till_water_thickness();
392 result.subglacial_water_thickness = &m_subglacial_hydrology->subglacial_water_thickness();
393
394 return result;
395}
396
397//! The contents of the main PISM time-step.
398/*!
399During the time-step we perform the following actions:
400 */
401double IceModel::step(bool do_mass_continuity,
402 bool do_skip) {
403
405
406 const Profiling &profiling = m_ctx->profiling();
407
408 double current_time = m_time->current();
409
410 //! \li call pre_step_hook() to let derived classes do more
412
413 //! \li update the velocity field; in some cases the whole three-dimensional
414 //! field is updated and in some cases just the vertically-averaged
415 //! horizontal velocity is updated
416
417 // always "update" ice velocity (possibly trivially); only update
418 // SSA and only update velocities at depth if suggested by temp and age
419 // stability criterion; note *lots* of communication is avoided by skipping
420 // SSA (and temp/age)
421
422 const bool updateAtDepth = (m_skip_countdown == 0);
423
424 // Combine basal melt rate in grounded (computed during the energy
425 // step) and floating (provided by an ocean model) areas.
426 //
427 // Basal melt rate may be used by a stress balance model to compute vertical velocity of
428 // ice.
429 {
431 m_ocean->shelf_base_mass_flux(),
432 m_energy_model->basal_melt_rate(),
434 }
435
436 try {
437 profiling.begin("stress_balance");
438 m_stress_balance->update(stress_balance_inputs(), updateAtDepth);
439 profiling.end("stress_balance");
440 } catch (RuntimeError &e) {
441 std::string output_file = save_state_on_error("_stressbalance_failed", {});
442
443 e.add_context("performing a time step. (Note: Model state was saved to '%s'.)",
444 output_file.c_str());
445 throw;
446 }
447
448
449 m_stdout_flags += m_stress_balance->stdout_report();
450
451 m_stdout_flags += (updateAtDepth ? "v" : "V");
452
453 //! \li determine the time step according to a variety of stability criteria
454 auto dt_info = max_timestep(m_skip_countdown);
455 double dt = dt_info.dt;
456
457 m_adaptive_timestep_reason = dt_info.reason;
458 m_skip_countdown = dt_info.skip_counter;
459
460 //! \li update the yield stress for the plastic till model (if appropriate)
462 profiling.begin("basal_yield_stress");
463 m_basal_yield_stress_model->update(yield_stress_inputs(), current_time, dt);
464 profiling.end("basal_yield_stress");
465 m_basal_yield_stress.copy_from(m_basal_yield_stress_model->basal_material_yield_stress());
466 m_stdout_flags += "y";
467 } else {
468 m_stdout_flags += "$";
469 }
470
471 m_dt_TempAge += dt;
472
473 //! \li update the age of the ice (if appropriate)
474 if (m_age_model and updateAtDepth) {
475 AgeModelInputs inputs;
477 inputs.u3 = &m_stress_balance->velocity_u();
478 inputs.v3 = &m_stress_balance->velocity_v();
479 inputs.w3 = &m_stress_balance->velocity_w();
480
481 profiling.begin("age");
482 m_age_model->update(m_t_TempAge, m_dt_TempAge, inputs);
483 profiling.end("age");
484 m_stdout_flags += "a";
485 } else {
486 m_stdout_flags += "$";
487 }
488
489 //! \li update the enthalpy (or temperature) field according to the conservation of
490 //! energy model based (especially) on the new velocity field; see
491 //! energy_step()
492 if (updateAtDepth) { // do the energy step
493 profiling.begin("energy");
495 profiling.end("energy");
496 m_stdout_flags += "E";
497 } else {
498 m_stdout_flags += "$";
499 }
500
501 //! \li update the fracture density field; see update_fracture_density()
502 if (m_config->get_flag("fracture_density.enabled")) {
503 profiling.begin("fracture_density");
505 profiling.end("fracture_density");
506 }
507
508 //! \li update the thickness of the ice according to the mass conservation model and calving
509 //! parameterizations
510
511 if (do_mass_continuity) {
512 // reset the conservation error field:
513 m_geometry_evolution->reset();
514
515 profiling.begin("mass_transport");
516 {
517 // Note that there are three adaptive time-stepping criteria. Two of them (using max.
518 // diffusion and 2D CFL) are limiting the mass-continuity time-step and the third (3D
519 // CFL) limits the energy and age time-steps.
520
521 // The mass-continuity time-step is usually smaller, and the skipping mechanism lets us
522 // do several mass-continuity steps for each energy step.
523
524 // When -no_mass is set, mass-continuity-related time-step restrictions are disabled,
525 // making "skipping" unnecessary.
526
527 // This is why the following two lines appear here and are executed only if
528 // do_mass_continuity is true.
529 if (do_skip and m_skip_countdown > 0) {
531 }
532
533 try {
535 dt,
536 m_stress_balance->advective_velocity(),
537 m_stress_balance->diffusive_flux(),
539 } catch (RuntimeError &e) {
540 std::string output_file = save_state_on_error("_mass_transport_failed",
541 {"flux_staggered", "flux_divergence"});
542
543 e.add_context("performing a mass transport time step (dt=%f s). (Note: Model state was saved to '%s'.)",
544 dt, output_file.c_str());
545 throw;
546 }
547
548 m_geometry_evolution->apply_flux_divergence(m_geometry);
549
551 }
552 profiling.end("mass_transport");
553
554 // calving, frontal melt, and discharge accounting
555 profiling.begin("front_retreat");
556 front_retreat_step(current_time, dt);
557 profiling.end("front_retreat");
558
559 m_stdout_flags += "h";
560 } else {
561 m_stdout_flags += "$";
562 }
563
564 profiling.begin("sea_level");
565 m_sea_level->update(m_geometry, current_time, dt);
566 profiling.end("sea_level");
567
568 profiling.begin("ocean");
569 {
570 ocean::Inputs inputs;
571 inputs.geometry = &m_geometry;
572 m_ocean->update(inputs, current_time, dt);
573 }
574 profiling.end("ocean");
575
576 // The sea level elevation might have changed, so we need to update the mask, etc. Note
577 // that THIS MAY PRODUCE ICEBERGS, but we assume that the surface model does not care.
579
580 //! \li Update surface and ocean models.
581 profiling.begin("surface");
582 m_surface->update(m_geometry, current_time, dt);
583 profiling.end("surface");
584
585
586 if (do_mass_continuity) {
587 // compute and apply effective surface and basal mass balance
588
589 m_geometry_evolution->source_term_step(m_geometry, dt,
591 m_surface->mass_flux(),
593 m_geometry_evolution->apply_mass_fluxes(m_geometry);
594
595 // add removed icebergs to discharge due to calving
596 {
597 auto &old_H = *m_work2d[0], &old_Href = *m_work2d[1];
598
599 {
600 old_H.copy_from(m_geometry.ice_thickness);
601 old_Href.copy_from(m_geometry.ice_area_specific_volume);
602 }
603
604 // the last call has to remove icebergs
606
607 bool add_values = true;
610 old_H, old_Href,
611 add_values,
613 }
614 }
615
616 if (m_isochrones) {
617 m_isochrones->update(current_time, dt,
618 m_stress_balance->velocity_u(),
619 m_stress_balance->velocity_v(),
621 m_geometry_evolution->top_surface_mass_balance(),
622 m_geometry_evolution->bottom_surface_mass_balance());
623 }
624
625 //! \li update the state variables in the subglacial hydrology model (typically
626 //! water thickness and sometimes pressure)
627 profiling.begin("basal_hydrology");
628 hydrology_step(current_time, dt);
629 profiling.end("basal_hydrology");
630
631 //! \li compute the bed deformation, which depends on current thickness, bed elevation,
632 //! and sea level
633 if (m_beddef) {
634 int topg_state_counter = m_beddef->bed_elevation().state_counter();
635
636 profiling.begin("bed_deformation");
639 current_time, dt);
640 profiling.end("bed_deformation");
641
642 m_new_bed_elevation = m_beddef->bed_elevation().state_counter() != topg_state_counter;
643 } else {
644 m_new_bed_elevation = false;
645 }
646
647 if (m_config->get_flag("time_stepping.assume_bed_elevation_changed")) {
648 m_new_bed_elevation = true;
649 }
650
653 m_stdout_flags += "b";
654 } else {
655 m_stdout_flags += " ";
656 }
657
658 //! \li call post_step_hook() to let derived classes do more
660
661 // Done with the step; now adopt the new time. Note that this has to happen before we
662 // update m_t_TempAge below.
663 m_time->step(dt);
664
665 if (updateAtDepth) {
666 m_t_TempAge = m_time->current();
667 m_dt_TempAge = 0.0;
668 }
669
670 // Check if the ice thickness exceeded the height of the computational box and stop if it did.
671 if (max(m_geometry.ice_thickness) > m_grid->Lz()) {
672 auto o_file = save_state_on_error("_max_thickness", {});
673
675 "Ice thickness exceeds the height of the computational box (%7.4f m).\n"
676 "The model state was saved to '%s'. To continue this simulation,\n"
677 "run with\n"
678 "-i %s -bootstrap -regrid_file %s -allow_extrapolation -Lz N [other options]\n"
679 "where N > %7.4f.",
680 m_grid->Lz(), o_file.c_str(), o_file.c_str(), o_file.c_str(), m_grid->Lz());
681 }
682
683 // end the flag line
685
686 return dt;
687}
688
689/*!
690 * Note: don't forget to update IceRegionalModel::hydrology_step() if necessary.
691 */
692void IceModel::hydrology_step(double t, double dt) {
693 hydrology::Inputs inputs;
694
695 array::Scalar &sliding_speed = *m_work2d[0];
696 compute_magnitude(m_stress_balance->advective_velocity(), sliding_speed);
697
698 inputs.no_model_mask = nullptr;
699 inputs.geometry = &m_geometry;
700 inputs.surface_input_rate = nullptr;
702 inputs.ice_sliding_speed = &sliding_speed;
703
708 } else if (m_config->get_flag("hydrology.surface_input_from_runoff")) {
709 // convert [kg m-2] to [kg m-2 s-1]
710 array::Scalar &surface_input_rate = *m_work2d[1];
711 surface_input_rate.copy_from(m_surface->runoff());
712 surface_input_rate.scale(1.0 / dt);
713 inputs.surface_input_rate = &surface_input_rate;
714 }
715
716 m_subglacial_hydrology->update(t, dt, inputs);
717}
718
719//! Virtual. Does nothing in `IceModel`. Derived classes can do more computation in each time step.
721 // empty
722}
723
724//! Virtual. Does nothing in `IceModel`. Derived classes can do more computation in each time step.
726 // empty
727}
728
729/**
730 * Run the time-stepping loop from the current model time to `time`.
731 *
732 * This should be called by the coupler controlling PISM when it is
733 * running alongside a GCM.
734 *
735 * @param run_end model time (in seconds) to run to
736 *
737 * @return 0 on success
738 */
740
741 m_time->set_end(run_end);
742
743 return run();
744}
745
746
747/**
748 * Run the time-stepping loop from the current time until the time
749 * specified by the IceModel::grid::time object.
750 *
751 * This is the method used by PISM in the "standalone" mode.
752 */
754 const Profiling &profiling = m_ctx->profiling();
755
756 bool do_mass_conserve = m_config->get_flag("geometry.update.enabled");
757 bool do_energy = set_member(m_config->get_string("energy.model"), {"cold", "enthalpy"});
758 bool do_skip = m_config->get_flag("time_stepping.skip.enabled");
759
760 // Enforce consistency *and* remove icebergs. During time-stepping we remove icebergs at
761 // the end of the time step, so we need to ensure that ice geometry is "OK" before the
762 // first step.
764
765 // Update spatially-variable diagnostics at the beginning of the run.
767
768 // Update scalar time series to remember the state at the beginning of the run.
769 // This is needed to compute rates of change of the ice mass, volume, etc.
770 {
771 const double time = m_time->current();
772 for (const auto &d : m_available_scalar_diagnostics) {
773 d.second->update(time, time);
774 }
775 }
776
777 m_log->message(2, "running forward ...\n");
778
779 m_stdout_flags.erase(); // clear it out
780 print_summary_line(true, do_energy, 0.0, 0.0, 0.0, 0.0, 0.0);
781 print_summary(do_energy, 0.0 /* time step length is not known yet */); // report starting state
782
783 m_t_TempAge = m_time->current();
784 m_dt_TempAge = 0.0;
785
786 IceModelTerminationReason termination_reason = PISM_DONE;
787 // main loop for time evolution
788 // IceModel::step calls Time::step(dt), ensuring that this while loop
789 // will terminate
790 profiling.stage_begin("time-stepping loop");
791 while (m_time->current() < m_time->end()) {
792
793 m_stdout_flags.erase(); // clear it out
794
795 m_dt = step(do_mass_conserve, do_skip);
796
797 update_diagnostics(m_time->current(), dt());
798
799 // report a summary for major steps or the last one
800 bool updateAtDepth = m_skip_countdown == 0;
801 bool tempAgeStep = updateAtDepth and (m_age_model or do_energy);
802
803 double time_resolution = m_config->get_number("time_stepping.resolution");
804 const bool show_step = tempAgeStep or fabs(m_time->current() - m_time->end()) < time_resolution;
805 print_summary(show_step, dt());
806
807 // update viewers before writing extras because writing extras resets diagnostics
809
810 // writing these fields here ensures that we do it after the last time-step
811 profiling.begin("io");
814 bool stop_after_chekpoint = write_checkpoint();
815 profiling.end("io");
816
817 if (stop_after_chekpoint) {
818 termination_reason = PISM_CHEKPOINT;
819 break;
820 }
821
822 if (process_signals() != 0) {
823 termination_reason = PISM_SIGNAL;
824 break;
825 }
826 } // end of the time-stepping loop
827 profiling.stage_end("time-stepping loop");
828
829 return termination_reason;
830}
831
832//! Manage the initialization of the IceModel object.
833/*!
834Please see the documenting comments of the functions called below to find
835explanations of their intended uses.
836 */
838 // Get the start time in seconds and ensure that it is consistent
839 // across all processors.
841
842 const Profiling &profiling = m_ctx->profiling();
843
844 InputOptions input_options = process_input_options(m_ctx->com(), m_config);
845
846 profiling.begin("initialization");
847
848 //! The IceModel initialization sequence is this:
849
850 //! 1) Warn about some option combinations
851 {
852 if (not m_config->get_flag("geometry.update.enabled") &&
853 m_config->get_flag("time_stepping.skip.enabled")) {
854 m_log->message(2,
855 "PISM WARNING: time_stepping.skip.enabled is 'true' and\n"
856 " geometry.update.enabled is 'false'\n"
857 " skipping time steps makes sense only with evolving geometry.\n");
858 }
859 }
860
861 // 2) Report run duration
862 {
863 bool use_calendar = m_config->get_flag("output.runtime.time_use_calendar");
864
865 if (use_calendar) {
866 m_log->message(2, "* Run time: [%s, %s] (%s years, using the '%s' calendar)\n",
867 m_time->date(m_time->start()).c_str(), m_time->date(m_time->end()).c_str(),
868 m_time->run_length().c_str(), m_time->calendar().c_str());
869 } else {
870 std::string time_units = m_config->get_string("output.runtime.time_unit_name");
871
872 double start = m_time->convert_time_interval(m_time->start(), time_units),
873 end = m_time->convert_time_interval(m_time->end(), time_units), length = end - start;
874
875 m_log->message(2, "* Run time: [%f %s, %f %s] (%f %s)\n", start, time_units.c_str(), end,
876 time_units.c_str(), length, time_units.c_str());
877 }
878 }
879
880 //! 3) Memory allocation:
882
883 //! 4) Allocate PISM components modeling some physical processes.
885
886 //! 6) Initialize coupler models and fill the model state variables
887 //! (from a PISM output file, from a bootstrapping file using some
888 //! modeling choices or using formulas). Calls IceModel::regrid()
889 model_state_setup(input_options);
890
891 //! 7) Report grid parameters:
892 m_log->message(2, "Computational domain and grid:\n");
893 m_grid->report_parameters();
894
895 //! 8) Miscellaneous stuff: set up the bed deformation model, initialize the
896 //! basal till model, initialize snapshots. This has to happen *after*
897 //! regridding.
898 misc_setup(input_options, report_type);
899
900 profiling.end("initialization");
901}
902
904 return m_geometry;
905}
906
910
912 return this->m_stress_balance.get();
913}
914
916 return m_ocean.get();
917}
918
920 return m_btu.get();
921}
922
926
930
932 return m_beddef.get();
933}
934
935/*!
936 * Return thickness change due to calving (over the last time step).
937 */
941
942/*!
943 * Return thickness change due to frontal melt (over the last time step).
944 */
948
949/*!
950 * Return thickness change due to forced retreat (over the last time step).
951 */
955
956IceModel::ThicknessChanges::ThicknessChanges(const std::shared_ptr<const Grid> &grid)
957 : calving(grid, "thickness_change_due_to_calving"),
958 frontal_melt(grid, "thickness_change_due_to_frontal_melt"),
959 forced_retreat(grid, "thickness_change_due_to_forced_retreat") {
960 // empty
961}
962
963void IceModel::set_python_ocean_model(std::shared_ptr<ocean::PyOceanModel> model) {
964 m_ocean = std::make_shared<ocean::PyOceanModelAdapter>(m_grid, model);
965 m_submodels["ocean model"] = m_ocean.get();
966}
967
968} // 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:365
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:692
void enforce_consistency_of_geometry(ConsistencyFlag flag)
Update the surface elevation and the flow-type mask when the geometry has changed.
Definition IceModel.cc:302
const Geometry & geometry() const
Definition IceModel.cc:903
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:753
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:725
const ocean::OceanModel * ocean_model() const
Definition IceModel.cc:915
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:339
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:182
Geometry m_geometry
Definition IceModel.hh:333
virtual void update_fracture_density(double dt)
const GeometryEvolution & geometry_evolution() const
Definition IceModel.cc:907
const stressbalance::StressBalance * stress_balance() const
Definition IceModel.cc:911
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:923
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:945
const array::Scalar & forced_retreat() const
Definition IceModel.cc:952
std::vector< std::shared_ptr< array::Scalar2 > > m_work2d
Definition IceModel.hh:437
double dt() const
Definition IceModel.cc:151
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:196
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:155
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:837
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:931
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:401
virtual void update_viewers()
Update the runtime graphical viewers.
Definition viewers.cc:58
const array::Scalar & calving() const
Definition IceModel.cc:938
virtual void pre_step_hook()
Virtual. Does nothing in IceModel. Derived classes can do more computation in each time step.
Definition IceModel.cc:720
unsigned int m_skip_countdown
Definition IceModel.hh:362
IceModelTerminationReason run_to(double run_end)
Definition IceModel.cc:739
virtual YieldStressInputs yield_stress_inputs()
Definition IceModel.cc:387
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:927
std::unique_ptr< hydrology::Hydrology > m_subglacial_hydrology
Definition IceModel.hh:299
const energy::BedThermalUnit * bedrock_thermal_model() const
Definition IceModel.cc:919
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:963
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
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:956
const Geometry * geometry
Definition OceanModel.hh:34