PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
SurfaceModel.cc
Go to the documentation of this file.
1// Copyright (C) 2008-2026 Ed Bueler, Constantine Khroulev, Ricarda Winkelmann,
2// Gudfinna Adalgeirsdottir and Andy Aschwanden
3//
4// This file is part of PISM.
5//
6// PISM is free software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the Free Software
8// Foundation; either version 3 of the License, or (at your option) any later
9// version.
10//
11// PISM is distributed in the hope that it will be useful, but WITHOUT ANY
12// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14// details.
15//
16// You should have received a copy of the GNU General Public License
17// along with PISM; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20#include <cassert>
21#include <gsl/gsl_math.h> // GSL_NAN
22#include <memory>
23
24#include "pism/coupler/SurfaceModel.hh"
25#include "pism/coupler/AtmosphereModel.hh"
26#include "pism/util/io/File.hh"
27#include "pism/util/Grid.hh"
28#include "pism/util/MaxTimestep.hh"
29#include "pism/util/pism_utilities.hh"
30#include "pism/util/Context.hh"
31
32namespace pism {
33namespace surface {
34
35std::shared_ptr<array::Scalar> SurfaceModel::allocate_layer_mass(std::shared_ptr<const Grid> grid) {
36 auto result = std::make_shared<array::Scalar>(grid, "surface_layer_mass");
37
38 result->metadata(0)
39 .long_name("mass held in the surface layer")
40 .units("kg");
41
42 result->metadata()["valid_min"] = { 0.0 };
43
44 return result;
45}
46
47std::shared_ptr<array::Scalar> SurfaceModel::allocate_layer_thickness(std::shared_ptr<const Grid> grid) {
48
49 auto result = std::make_shared<array::Scalar>(grid, "surface_layer_thickness");
50
51 result->metadata(0)
52 .long_name("thickness of the surface process layer at the top surface of the ice")
53 .units("m");
54
55 result->metadata()["valid_min"] = { 0.0 };
56
57 return result;
58}
59
60std::shared_ptr<array::Scalar> SurfaceModel::allocate_liquid_water_fraction(std::shared_ptr<const Grid> grid) {
61
62 auto result = std::make_shared<array::Scalar>(grid, "ice_surface_liquid_water_fraction");
63
64 result->metadata(0)
65 .long_name("liquid water fraction of the ice at the top surface")
66 .units("1");
67
68 result->metadata()["valid_range"] = { 0.0, 1.0 };
69
70 return result;
71}
72
73std::shared_ptr<array::Scalar> SurfaceModel::allocate_mass_flux(std::shared_ptr<const Grid> grid) {
74
75 auto result = std::make_shared<array::Scalar>(grid, "climatic_mass_balance");
76
77 result->metadata(0)
78 .long_name("surface mass balance (accumulation/ablation) rate")
79 .units("kg m^-2 second^-1")
80 .output_units("kg m^-2 year^-1")
81 .standard_name("land_ice_surface_specific_mass_balance_flux");
82
83 auto config = grid->ctx()->config();
84 const double smb_max = config->get_number("surface.given.smb_max", "kg m-2 second-1");
85
86 result->metadata()["valid_range"] = { -smb_max, smb_max };
87
88 return result;
89}
90
91std::shared_ptr<array::Scalar>
92SurfaceModel::allocate_temperature(std::shared_ptr<const Grid> grid) {
93
94 auto result = std::make_shared<array::Scalar>(grid, "ice_surface_temp");
95
96 result->metadata(0)
97 .long_name("temperature of the ice at the ice surface but below firn processes")
98 .units("kelvin");
99
100 result->metadata()["valid_range"] = { 0.0, 323.15 }; // [0C, 50C]
101
102 return result;
103}
104
105std::shared_ptr<array::Scalar>
106SurfaceModel::allocate_accumulation(std::shared_ptr<const Grid> grid) {
107
108 auto result = std::make_shared<array::Scalar>(grid, "surface_accumulation_flux");
109
110 result->metadata(0).long_name("surface accumulation (precipitation minus rain)").units("kg m^-2");
111
112 return result;
113}
114
115std::shared_ptr<array::Scalar> SurfaceModel::allocate_melt(std::shared_ptr<const Grid> grid) {
116
117 auto result = std::make_shared<array::Scalar>(grid, "surface_melt_flux");
118
119 result->metadata(0).long_name("surface melt").units("kg m^-2");
120
121 return result;
122}
123
124std::shared_ptr<array::Scalar> SurfaceModel::allocate_runoff(std::shared_ptr<const Grid> grid) {
125
126 auto result = std::make_shared<array::Scalar>(grid, "surface_runoff_flux");
127
128 result->metadata(0).long_name("surface meltwater runoff").units("kg m^-2");
129
130 return result;
131}
132
133SurfaceModel::SurfaceModel(std::shared_ptr<const Grid> grid)
134 : Component(grid) {
135
142
143 // default values
144 m_layer_thickness->set(0.0);
145 m_layer_mass->set(0.0);
146 m_liquid_water_fraction->set(0.0);
147 m_accumulation->set(0.0);
148 m_melt->set(0.0);
149 m_runoff->set(0.0);
150}
151
152SurfaceModel::SurfaceModel(std::shared_ptr<const Grid> g, std::shared_ptr<SurfaceModel> input)
153 : Component(g) {
154 m_input_model = input;
155 // this is a modifier: allocate storage only if necessary (in derived classes)
156}
157
158SurfaceModel::SurfaceModel(std::shared_ptr<const Grid> grid,
159 std::shared_ptr<atmosphere::AtmosphereModel> atmosphere)
160 : SurfaceModel(grid) { // this constructor will allocate storage
161
162 m_atmosphere = atmosphere;
163}
164
165
166//! \brief Returns accumulation
167/*!
168 * Basic surface models currently implemented in PISM do not model accumulation
169 */
173
174//! \brief Returns melt
175/*!
176 * Basic surface models currently implemented in PISM do not model melt
177 */
179 return melt_impl();
180}
181
182//! \brief Returns runoff
183/*!
184 * Basic surface models currently implemented in PISM do not model runoff
185 */
187 return runoff_impl();
188}
189
191 return mass_flux_impl();
192}
193
195 return temperature_impl();
196}
197
198//! \brief Returns the liquid water fraction of the ice at the top ice surface.
199/*!
200 * Most PISM surface models return 0.
201 */
205
206//! \brief Returns mass held in the surface layer.
207/*!
208 * Basic surface models currently implemented in PISM do not model the mass of
209 * the surface layer.
210 */
212 return layer_mass_impl();
213}
214
215//! \brief Returns thickness of the surface layer. Could be used to compute surface
216//! elevation as a sum of elevation of the top surface of the ice and surface layer (firn,
217//! etc) thickness.
218/*!
219 * Basic surface models currently implemented in PISM do not model surface
220 * layer thickness.
221 */
225
227 if (m_input_model) {
228 return m_input_model->accumulation();
229 }
230
231 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "no input model");
232}
233
235 if (m_input_model) {
236 return m_input_model->melt();
237 }
238
239 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "no input model");
240}
241
243 if (m_input_model) {
244 return m_input_model->runoff();
245 }
246
247 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "no input model");
248}
249
251 if (m_input_model) {
252 return m_input_model->mass_flux();
253 }
254
255 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "no input model");
256}
257
259 if (m_input_model) {
260 return m_input_model->temperature();
261 }
262
263 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "no input model");
264}
265
267 if (m_input_model) {
268 return m_input_model->liquid_water_fraction();
269 }
270
272}
273
275 if (m_input_model) {
276 return m_input_model->layer_mass();
277 }
278
279 return *m_layer_mass;
280}
281
283 if (m_input_model) {
284 return m_input_model->layer_thickness();
285 }
286
287 return *m_layer_thickness;
288}
289
290void SurfaceModel::init(const Geometry &geometry) {
291 this->init_impl(geometry);
292}
293
294void SurfaceModel::init_impl(const Geometry &geometry) {
295 if (m_atmosphere) {
296 m_atmosphere->init(geometry);
297 }
298
299 if (m_input_model) {
300 m_input_model->init(geometry);
301 }
302}
303
304void SurfaceModel::update(const Geometry &geometry, double t, double dt) {
305 this->update_impl(geometry, t, dt);
306}
307
308void SurfaceModel::update_impl(const Geometry &geometry, double t, double dt) {
309 if (m_atmosphere) {
310 m_atmosphere->update(geometry, t, dt);
311 }
312
313 if (m_input_model) {
314 m_input_model->update(geometry, t, dt);
315 }
316}
317
318std::set<VariableMetadata> SurfaceModel::state_impl() const {
319 std::set<VariableMetadata> result;
320
321 if (m_atmosphere) {
322 result = pism::combine(result, m_atmosphere->state());
323 }
324
325 if (m_input_model) {
326 result = pism::combine(result, m_input_model->state());
327 }
328
329 return result;
330}
331
333 if (m_atmosphere) {
334 m_atmosphere->write_state(output);
335 }
336
337 if (m_input_model) {
338 m_input_model->write_state(output);
339 }
340}
341
343 if (m_atmosphere) {
344 return m_atmosphere->max_timestep(t);
345 }
346
347 if (m_input_model) {
348 return m_input_model->max_timestep(t);
349 }
350
351 return MaxTimestep("surface model");
352}
353
354/*!
355 * Use the surface mass balance to compute dummy accumulation.
356 *
357 * This is used by surface models that compute the SMB but do not provide accumulation,
358 * melt, and runoff.
359 *
360 * We assume that the positive part of the SMB is accumulation and the negative part is
361 * runoff. This ensures that outputs of PISM's surface models satisfy "SMB = accumulation
362 * - runoff".
363 */
365
366 array::AccessScope list{&result, &smb};
367
368 for (auto p : m_grid->points()) {
369 const int i = p.i(), j = p.j();
370 result(i,j) = std::max(smb(i,j), 0.0);
371 }
372}
373
374/*!
375 * Use the surface mass balance to compute dummy runoff.
376 *
377 * This is used by surface models that compute the SMB but do not provide accumulation,
378 * melt, and runoff.
379 *
380 * We assume that the positive part of the SMB is accumulation and the negative part is
381 * runoff. This ensures that outputs of PISM's surface models satisfy "SMB = accumulation
382 * - runoff".
383 */
385
386 array::AccessScope list{&result, &smb};
387
388 for (auto p : m_grid->points()) {
389 const int i = p.i(), j = p.j();
390 result(i,j) = std::max(-smb(i,j), 0.0);
391 }
392}
393
394/*!
395 * Use the surface mass balance to compute dummy runoff.
396 *
397 * This is used by surface models that compute the SMB but do not provide accumulation,
398 * melt, and runoff.
399 *
400 * We assume that all melt runs off, i.e. runoff = melt, but treat melt as a "derived"
401 * quantity.
402 */
404 dummy_runoff(smb, result);
405}
406
407namespace diagnostics {
408
409// SurfaceModel diagnostics (these don't need to be in the header)
410
411/*! @brief Climatic mass balance */
412class PS_climatic_mass_balance : public Diag<SurfaceModel>
413{
414public:
416protected:
417 std::shared_ptr<array::Array> compute_impl() const;
418};
419
420/*! @brief Ice surface temperature. */
421class PS_ice_surface_temp : public Diag<SurfaceModel>
422{
423public:
425protected:
426 std::shared_ptr<array::Array> compute_impl() const;
427};
428
429/*! @brief Ice liquid water fraction at the ice surface. */
430class PS_liquid_water_fraction : public Diag<SurfaceModel>
431{
432public:
434protected:
435 std::shared_ptr<array::Array> compute_impl() const;
436};
437
438/*! @brief Mass of the surface layer (snow and firn). */
439class PS_layer_mass : public Diag<SurfaceModel>
440{
441public:
442 PS_layer_mass(const SurfaceModel *m);
443protected:
444 std::shared_ptr<array::Array> compute_impl() const;
445};
446
447/*! @brief Surface layer (snow and firn) thickness. */
448class PS_layer_thickness : public Diag<SurfaceModel>
449{
450public:
452protected:
453 std::shared_ptr<array::Array> compute_impl() const;
454};
455
457 : Diag<SurfaceModel>(m) {
458
459 /* set metadata: */
460 m_vars = { { m_sys, "climatic_mass_balance", *m_grid } };
461 m_vars[0]
462 .long_name("surface mass balance (accumulation/ablation) rate")
463 .standard_name("land_ice_surface_specific_mass_balance_flux")
464 .units("kg m^-2 second^-1")
465 .output_units("kg m^-2 year^-1");
466}
467
468std::shared_ptr<array::Array> PS_climatic_mass_balance::compute_impl() const {
469 auto result = allocate<array::Scalar>("climatic_mass_balance");
470
471 result->copy_from(model->mass_flux());
472
473 return result;
474}
475
477
478 auto ismip6 = m_config->get_flag("output.ISMIP6");
479
480 m_vars = { { m_sys, ismip6 ? "litemptop" : "ice_surface_temp", *m_grid } };
481 m_vars[0]
482 .long_name("ice temperature at the top ice surface")
483 .standard_name("temperature_at_top_of_ice_sheet_model")
484 .units("kelvin");
485}
486
487std::shared_ptr<array::Array> PS_ice_surface_temp::compute_impl() const {
488 auto result = allocate<array::Scalar>("ice_surface_temp");
489
490 result->copy_from(model->temperature());
491
492 return result;
493}
494
496 m_vars = { { m_sys, "ice_surface_liquid_water_fraction", *m_grid } };
497 m_vars[0].long_name("ice liquid water fraction at the ice surface").units("1");
498}
499
500std::shared_ptr<array::Array> PS_liquid_water_fraction::compute_impl() const {
501
502 auto result = allocate<array::Scalar>("ice_surface_liquid_water_fraction");
503
504 result->copy_from(model->liquid_water_fraction());
505
506 return result;
507}
508
510 m_vars = { { m_sys, "surface_layer_mass", *m_grid } };
511 m_vars[0].long_name("mass of the surface layer (snow and firn)").units("kg");
512}
513
514std::shared_ptr<array::Array> PS_layer_mass::compute_impl() const {
515
516 auto result = allocate<array::Scalar>("surface_layer_mass");
517
518 result->copy_from(model->layer_mass());
519
520 return result;
521}
522
524 m_vars = { { m_sys, "surface_layer_thickness", *m_grid } };
525 m_vars[0].long_name("thickness of the surface layer (snow and firn)").units("meters");
526}
527
528std::shared_ptr<array::Array> PS_layer_thickness::compute_impl() const {
529
530 auto result = allocate<array::Scalar>("surface_layer_thickness");
531
532 result->copy_from(model->layer_thickness());
533
534 return result;
535}
536
538
539/*! @brief Report surface melt, averaged over the reporting interval */
540class SurfaceMelt : public DiagAverageRate<SurfaceModel>
541{
542public:
545 kind == AMOUNT
546 ? "surface_melt_flux"
547 : "surface_melt_rate",
549 m_melt_mass(m_grid, "melt_mass"),
550 m_kind(kind)
551 {
552
553 std::string
554 name = "surface_melt_flux",
555 long_name = "surface melt, averaged over the reporting interval",
556 standard_name = "surface_snow_and_ice_melt_flux",
557 accumulator_units = "kg m^-2",
558 internal_units = "kg m^-2 second^-1",
559 external_units = "kg m^-2 year^-1";
560 if (kind == MASS) {
561 name = "surface_melt_rate";
562 standard_name = "";
563 accumulator_units = "kg",
564 internal_units = "kg second^-1";
565 external_units = "Gt year^-1" ;
566 }
567
568 m_accumulator.metadata()["units"] = accumulator_units;
569
570 m_vars = { { m_sys, name, *m_grid } };
571 m_vars[0]
572 .long_name(long_name)
573 .standard_name(standard_name)
574 .units(internal_units)
575 .output_units(external_units);
576 m_vars[0]["cell_methods"] = "time: mean";
577 m_vars[0]["_FillValue"] = {to_internal(m_fill_value)};
578 }
579
580protected:
582 const array::Scalar &melt_amount = model->melt();
583
584 if (m_kind == MASS) {
585 double cell_area = m_grid->cell_area();
586
587 array::AccessScope list{&m_melt_mass, &melt_amount};
588
589 for (auto p : m_grid->points()) {
590 const int i = p.i(), j = p.j();
591 m_melt_mass(i, j) = melt_amount(i, j) * cell_area;
592 }
593 return m_melt_mass;
594 }
595
596 return melt_amount;
597 }
598private:
601};
602
603/*! @brief Report surface runoff, averaged over the reporting interval */
604class SurfaceRunoff : public DiagAverageRate<SurfaceModel>
605{
606public:
609 kind == AMOUNT
610 ? "surface_runoff_flux"
611 : "surface_runoff_rate",
613 m_kind(kind),
614 m_runoff_mass(m_grid, "runoff_mass") {
615
616 std::string
617 name = "surface_runoff_flux",
618 long_name = "surface runoff, averaged over the reporting interval",
619 standard_name = "surface_runoff_flux",
620 accumulator_units = "kg m^-2",
621 internal_units = "kg m^-2 second^-1",
622 external_units = "kg m^-2 year^-1";
623 if (kind == MASS) {
624 name = "surface_runoff_rate";
625 standard_name = "",
626 accumulator_units = "kg",
627 internal_units = "kg second^-1";
628 external_units = "Gt year^-1" ;
629 }
630
631 m_accumulator.metadata()["units"] = accumulator_units;
632
633 m_vars = { { m_sys, name, *m_grid } };
634 m_vars[0]
635 .long_name(long_name)
636 .standard_name(standard_name)
637 .units(internal_units)
638 .output_units(external_units);
639 m_vars[0]["cell_methods"] = "time: mean";
640 m_vars[0]["_FillValue"] = {to_internal(m_fill_value)};
641 }
642
643protected:
645 const array::Scalar &runoff_amount = model->runoff();
646
647 if (m_kind == MASS) {
648 double cell_area = m_grid->cell_area();
649
650 array::AccessScope list{&m_runoff_mass, &runoff_amount};
651
652 for (auto p : m_grid->points()) {
653 const int i = p.i(), j = p.j();
654 m_runoff_mass(i, j) = runoff_amount(i, j) * cell_area;
655 }
656 return m_runoff_mass;
657 }
658
659 return runoff_amount;
660 }
661private:
664};
665
666/*! @brief Report accumulation (precipitation minus rain), averaged over the reporting interval */
667class Accumulation : public DiagAverageRate<SurfaceModel>
668{
669public:
672 kind == AMOUNT
673 ? "surface_accumulation_flux"
674 : "surface_accumulation_rate",
676 m_kind(kind),
677 m_accumulation_mass(m_grid, "accumulation_mass") {
678
679 // possible standard name: surface_accumulation_flux
680 std::string
681 name = "surface_accumulation_flux",
682 long_name = "accumulation (precipitation minus rain), averaged over the reporting interval",
683 accumulator_units = "kg m^-2",
684 internal_units = "kg m^-2 second^-1",
685 external_units = "kg m^-2 year^-1";
686 if (kind == MASS) {
687 name = "surface_accumulation_rate";
688 accumulator_units = "kg",
689 internal_units = "kg second^-1";
690 external_units = "Gt year^-1" ;
691 }
692
693 m_accumulator.metadata()["units"] = accumulator_units;
694
695 m_vars = { { m_sys, name, *m_grid } };
696 m_vars[0]
697 .long_name(long_name)
698 .units(internal_units)
699 .output_units(external_units);
700 m_vars[0]["cell_methods"] = "time: mean";
701 m_vars[0]["_FillValue"] = {to_internal(m_fill_value)};
702 }
703
704protected:
706 const array::Scalar &accumulation_amount = model->accumulation();
707
708 if (m_kind == MASS) {
709 double cell_area = m_grid->cell_area();
710
711 array::AccessScope list{&m_accumulation_mass, &accumulation_amount};
712
713 for (auto p : m_grid->points()) {
714 const int i = p.i(), j = p.j();
715 m_accumulation_mass(i, j) = accumulation_amount(i, j) * cell_area;
716 }
717 return m_accumulation_mass;
718 }
719
720 return accumulation_amount;
721 }
722private:
725};
726
727/*!
728 * Integrate a field over the computational domain.
729 *
730 * If the input has units kg/m^2, the output will be in kg.
731 */
732static double integrate(const array::Scalar &input) {
733 auto grid = input.grid();
734
735 double cell_area = grid->cell_area();
736
737 array::AccessScope list{&input};
738
739 double result = 0.0;
740
741 for (auto p : grid->points()) {
742 const int i = p.i(), j = p.j();
743
744 result += input(i, j) * cell_area;
745 }
746
747 return GlobalSum(grid->com, result);
748}
749
750
751//! \brief Reports the total accumulation rate.
752class TotalSurfaceAccumulation : public TSDiag<TSFluxDiagnostic, SurfaceModel>
753{
754public:
756 : TSDiag<TSFluxDiagnostic, SurfaceModel>(m, "surface_accumulation_rate") {
757
758 set_units("kg s^-1", "kg year^-1");
759 m_variable["long_name"] = "surface accumulation rate";
760 }
761
762 double compute() {
763 return integrate(model->accumulation());
764 }
765};
766
767
768//! \brief Reports the total melt rate.
769class TotalSurfaceMelt : public TSDiag<TSFluxDiagnostic, SurfaceModel>
770{
771public:
773 : TSDiag<TSFluxDiagnostic, SurfaceModel>(m, "surface_melt_rate") {
774
775 set_units("kg s^-1", "kg year^-1");
776 m_variable["long_name"] = "surface melt rate";
777 }
778
779 double compute() {
780 return integrate(model->melt());
781 }
782};
783
784
785//! \brief Reports the total top surface ice flux.
786class TotalSurfaceRunoff : public TSDiag<TSFluxDiagnostic, SurfaceModel>
787{
788public:
790 : TSDiag<TSFluxDiagnostic, SurfaceModel>(m, "surface_runoff_rate") {
791
792 set_units("kg s^-1", "kg year^-1");
793 m_variable["long_name"] = "surface runoff rate";
794 }
795
796 double compute() {
797 return integrate(model->runoff());
798 }
799};
800
801} // end of namespace diagnostics
802
804 using namespace diagnostics;
805
806 DiagnosticList result = {
807 {"surface_accumulation_flux", Diagnostic::Ptr(new Accumulation(this, AMOUNT))},
808 {"surface_accumulation_rate", Diagnostic::Ptr(new Accumulation(this, MASS))},
809 {"surface_melt_flux", Diagnostic::Ptr(new SurfaceMelt(this, AMOUNT))},
810 {"surface_melt_rate", Diagnostic::Ptr(new SurfaceMelt(this, MASS))},
811 {"surface_runoff_flux", Diagnostic::Ptr(new SurfaceRunoff(this, AMOUNT))},
812 {"surface_runoff_rate", Diagnostic::Ptr(new SurfaceRunoff(this, MASS))},
813 {"climatic_mass_balance", Diagnostic::Ptr(new PS_climatic_mass_balance(this))},
814 {"ice_surface_temp", Diagnostic::Ptr(new PS_ice_surface_temp(this))},
815 {"ice_surface_liquid_water_fraction", Diagnostic::Ptr(new PS_liquid_water_fraction(this))},
816 {"surface_layer_mass", Diagnostic::Ptr(new PS_layer_mass(this))},
817 {"surface_layer_thickness", Diagnostic::Ptr(new PS_layer_thickness(this))}
818 };
819
820 if (m_config->get_flag("output.ISMIP6")) {
821 result["litemptop"] = Diagnostic::Ptr(new PS_ice_surface_temp(this));
822 }
823
824 if (m_atmosphere) {
825 result = pism::combine(result, m_atmosphere->spatial_diagnostics());
826 }
827
828 if (m_input_model) {
829 result = pism::combine(result, m_input_model->spatial_diagnostics());
830 }
831
832 return result;
833}
834
836 using namespace diagnostics;
837
838 TSDiagnosticList result = {
839 {"surface_accumulation_rate", TSDiagnostic::Ptr(new TotalSurfaceAccumulation(this))},
840 {"surface_melt_rate", TSDiagnostic::Ptr(new TotalSurfaceMelt(this))},
841 {"surface_runoff_rate", TSDiagnostic::Ptr(new TotalSurfaceRunoff(this))},
842 };
843
844 if (m_atmosphere) {
845 return pism::combine(result, m_atmosphere->scalar_diagnostics());
846 }
847
848 if (m_input_model) {
849 return pism::combine(result, m_input_model->scalar_diagnostics());
850 }
851
852 return result;
853}
854
855} // end of namespace surface
856} // end of namespace pism
857
std::shared_ptr< const Grid > grid() const
Definition Component.cc:107
std::shared_ptr< const Config > m_config
configuration database used by this component
Definition Component.hh:160
const std::shared_ptr< const Grid > m_grid
grid used by this component
Definition Component.hh:158
A class defining a common interface for most PISM sub-models.
Definition Component.hh:118
const SurfaceModel * model
A template derived from Diagnostic, adding a "Model".
std::vector< VariableMetadata > m_vars
metadata corresponding to NetCDF variables
double m_fill_value
fill value (used often enough to justify storing it)
const units::System::Ptr m_sys
the unit system
std::shared_ptr< const Config > m_config
Configuration flags and parameters.
double to_internal(double x) const
Definition Diagnostic.cc:62
std::shared_ptr< Diagnostic > Ptr
Definition Diagnostic.hh:67
std::shared_ptr< const Grid > m_grid
the grid
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
void set_units(const std::string &units, const std::string &output_units)
VariableMetadata m_variable
std::shared_ptr< TSDiagnostic > Ptr
Scalar diagnostic reporting a "flux".
VariableMetadata & long_name(const std::string &input)
VariableMetadata & units(const std::string &input)
VariableMetadata & standard_name(const std::string &input)
VariableMetadata & output_units(const std::string &input)
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition Array.hh:66
std::shared_ptr< const Grid > grid() const
Definition Array.cc:134
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
Definition Array.cc:467
const array::Scalar & melt() const
Returns melt.
static std::shared_ptr< array::Scalar > allocate_runoff(std::shared_ptr< const Grid > grid)
virtual const array::Scalar & layer_mass_impl() const
const array::Scalar & liquid_water_fraction() const
Returns the liquid water fraction of the ice at the top ice surface.
const array::Scalar & layer_mass() const
Returns mass held in the surface layer.
void update(const Geometry &geometry, double t, double dt)
std::shared_ptr< atmosphere::AtmosphereModel > m_atmosphere
static std::shared_ptr< array::Scalar > allocate_mass_flux(std::shared_ptr< const Grid > grid)
void dummy_accumulation(const array::Scalar &smb, array::Scalar &result)
virtual void update_impl(const Geometry &geometry, double t, double dt)
std::shared_ptr< array::Scalar > m_melt
void init(const Geometry &geometry)
std::shared_ptr< array::Scalar > m_layer_thickness
const array::Scalar & mass_flux() const
static std::shared_ptr< array::Scalar > allocate_temperature(std::shared_ptr< const Grid > grid)
virtual const array::Scalar & accumulation_impl() const
const array::Scalar & accumulation() const
Returns accumulation.
virtual TSDiagnosticList scalar_diagnostics_impl() const
virtual const array::Scalar & liquid_water_fraction_impl() const
static std::shared_ptr< array::Scalar > allocate_accumulation(std::shared_ptr< const Grid > grid)
virtual MaxTimestep max_timestep_impl(double my_t) const
static std::shared_ptr< array::Scalar > allocate_melt(std::shared_ptr< const Grid > grid)
SurfaceModel(std::shared_ptr< const Grid > g)
std::shared_ptr< array::Scalar > m_runoff
static std::shared_ptr< array::Scalar > allocate_layer_thickness(std::shared_ptr< const Grid > grid)
virtual void write_state_impl(const OutputFile &output) const
The default (empty implementation).
void dummy_melt(const array::Scalar &smb, array::Scalar &result)
virtual std::set< VariableMetadata > state_impl() const
std::shared_ptr< SurfaceModel > m_input_model
static std::shared_ptr< array::Scalar > allocate_layer_mass(std::shared_ptr< const Grid > grid)
const array::Scalar & temperature() const
std::shared_ptr< array::Scalar > m_layer_mass
virtual const array::Scalar & mass_flux_impl() const
virtual DiagnosticList spatial_diagnostics_impl() const
virtual const array::Scalar & runoff_impl() const
std::shared_ptr< array::Scalar > m_accumulation
std::shared_ptr< array::Scalar > m_liquid_water_fraction
virtual void init_impl(const Geometry &geometry)
const array::Scalar & layer_thickness() const
Returns thickness of the surface layer. Could be used to compute surface elevation as a sum of elevat...
const array::Scalar & runoff() const
Returns runoff.
virtual const array::Scalar & melt_impl() const
virtual const array::Scalar & layer_thickness_impl() const
void dummy_runoff(const array::Scalar &smb, array::Scalar &result)
virtual const array::Scalar & temperature_impl() const
static std::shared_ptr< array::Scalar > allocate_liquid_water_fraction(std::shared_ptr< const Grid > grid)
The interface of PISM's surface models.
Accumulation(const SurfaceModel *m, AmountKind kind)
Report accumulation (precipitation minus rain), averaged over the reporting interval.
std::shared_ptr< array::Array > compute_impl() const
std::shared_ptr< array::Array > compute_impl() const
std::shared_ptr< array::Array > compute_impl() const
Mass of the surface layer (snow and firn).
std::shared_ptr< array::Array > compute_impl() const
Surface layer (snow and firn) thickness.
std::shared_ptr< array::Array > compute_impl() const
Ice liquid water fraction at the ice surface.
SurfaceMelt(const SurfaceModel *m, AmountKind kind)
Report surface melt, averaged over the reporting interval.
SurfaceRunoff(const SurfaceModel *m, AmountKind kind)
Report surface runoff, averaged over the reporting interval.
Reports the total top surface ice flux.
#define PISM_ERROR_LOCATION
static double integrate(const array::Scalar &input)
static const double g
Definition exactTestP.cc:36
std::map< std::string, TSDiagnostic::Ptr > TSDiagnosticList
std::map< std::string, Diagnostic::Ptr > DiagnosticList
T combine(const T &a, const T &b)
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)