Loading [MathJax]/extensions/tex2jax.js
PISM, A Parallel Ice Sheet Model 2.2.2-d6b3a29ca committed by Constantine Khrulev on 2025-03-28
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DEBMSimplePointwise.cc
Go to the documentation of this file.
1// Copyright (C) 2009--2025 PISM Authors
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 <algorithm>
20#include <cassert>
21#include <cmath>
22
23#include "pism/coupler/surface/DEBMSimplePointwise.hh"
24#include "pism/util/ConfigInterface.hh"
25#include "pism/util/Context.hh"
26#include "pism/util/Time.hh"
27
28/*!
29 * This class implements dEBM-simple, the simple diurnal energy balance model described in
30 *
31 * M. Zeitz, R. Reese, J. Beckmann, U. Krebs-Kanzow, and R. Winkelmann, “Impact of the
32 * melt–albedo feedback on the future evolution of the Greenland Ice Sheet with
33 * PISM-dEBM-simple,” The Cryosphere, vol. 15, Art. no. 12, Dec. 2021.
34 *
35 * See also
36 *
37 * U. Krebs-Kanzow, P. Gierz, and G. Lohmann, “Brief communication: An ice surface melt
38 * scheme including the diurnal cycle of solar radiation,” The Cryosphere, vol. 12, Art.
39 * no. 12, Dec. 2018.
40 *
41 * and chapter 2 of
42 *
43 * K. N. Liou, Introduction to Atmospheric Radiation. Elsevier Science & Technology Books, 2002.
44 *
45 */
46namespace pism {
47namespace surface {
48
49// Disable clang-tidy warnings about "magic numbers":
50// NOLINTBEGIN(readability-magic-numbers)
51
52/*!
53 * The integrand in equation 6 of
54 *
55 * R. Calov and R. Greve, “A semi-analytical solution for the positive degree-day model
56 * with stochastic temperature variations,” Journal of Glaciology, vol. 51, Art. no. 172,
57 * 2005.
58 *
59 * @param[in] sigma standard deviation of daily variation of near-surface air temperature (kelvin)
60 * @param[in] temperature near-surface air temperature in "kelvin above the melting point"
61 */
62double DEBMSimplePointwise::CalovGreveIntegrand(double sigma, double temperature) {
63
64 if (sigma == 0) {
65 return std::max(temperature, 0.0);
66 }
67
68 double Z = temperature / (sqrt(2.0) * sigma);
69 return (sigma / sqrt(2.0 * M_PI)) * exp(-Z * Z) + (temperature / 2.0) * erfc(-Z);
70}
71
72/*!
73 * The hour angle (radians) at which the sun reaches the solar altitude angle `phi`
74 *
75 * Implements equation 11 in Krebs-Kanzow et al solved for h_phi.
76 *
77 * Equation 2 in Zeitz et al should be equivalent but misses "acos(...)".
78 *
79 * The return value is in the range [0, pi].
80 *
81 * @param[in] phi angle (radians)
82 * @param[in] latitude latitude (radians)
83 * @param[in] declination solar declination angle (radians)
84 */
85double DEBMSimplePointwise::hour_angle(double phi, double latitude, double declination) {
86 double cos_h_phi = ((sin(phi) - sin(latitude) * sin(declination)) /
87 (cos(latitude) * cos(declination)));
88 return acos(pism::clip(cos_h_phi, -1.0, 1.0));
89}
90
91/*!
92 * Solar longitude (radians) at current time in the year.
93 *
94 * @param[in] year_fraction year fraction (between 0 and 1)
95 * @param[in] eccentricity eccentricity of the earth’s orbit (no units)
96 * @param[in] perihelion_longitude perihelion longitude (radians) in the geocentric
97 * ecliptic coordinate system
98 *
99 * Implements equation A2 in Zeitz et al. or equivalent equations in Berger1978 (section
100 * 3).
101 */
102double DEBMSimplePointwise::solar_longitude(double year_fraction, double eccentricity,
103 double perihelion_longitude) {
104
105 // Shortcuts to make formulas below easier to read:
106 double E = eccentricity;
107 double E2 = E * E;
108 double E3 = E * E * E;
109 double L_p = perihelion_longitude;
110
111 // Note: lambda = 0 at March equinox (80th day of the year)
112 const double equinox_day_number = 80.0;
113 double delta_lambda = 2.0 * M_PI * (year_fraction - equinox_day_number / 365.0);
114 double beta = sqrt(1.0 - E2);
115
116 double lambda_m = (-2.0 * ((E / 2.0 + E3 / 8.0) * (1.0 + beta) * sin(-L_p) -
117 E2 / 4.0 * (1.0 / 2.0 + beta) * sin(-2.0 * L_p) +
118 E3 / 8.0 * (1.0 / 3.0 + beta) * sin(-3.0 * L_p)) +
119 delta_lambda);
120
121 return (lambda_m +
122 (2.0 * E - E3 / 4.0) * sin(lambda_m - L_p) +
123 (5.0 / 4.0) * E2 * sin(2.0 * (lambda_m - L_p)) +
124 (13.0 / 12.0) * E3 * sin(3.0 * (lambda_m - L_p)));
125}
126
127/*!
128 * The unit-less factor scaling top of atmosphere insolation according to the earth's
129 * distance from the sun.
130 *
131 * The returned value is `(d_bar / d)^2`, where `d_bar` is the average distance from the
132 * earth to the sun and `d` is the *current* distance at a given time.
133 *
134 * Implements equation 2.2.9 from Liou (2002).
135 *
136 * Liou states: "Note that the factor (a/r)^2 never departs from the unity by more than
137 * 3.5%." (`a/r` in Liou is equivalent to `d_bar/d` here.)
138 *
139 * This quantity is equal to `1 / R^2`, where R is the sun-earth distance in units of the
140 * semi-major axis of the earth's orbit.
141 */
143 // These coefficients come from Table 2.2 in Liou 2002
144 double
145 a0 = 1.000110,
146 a1 = 0.034221,
147 a2 = 0.000719,
148 b0 = 0.,
149 b1 = 0.001280,
150 b2 = 0.000077;
151
152 double t = 2. * M_PI * year_fraction;
153
154 return (a0 + b0 +
155 a1 * cos(t) + b1 * sin(t) +
156 a2 * cos(2. * t) + b2 * sin(2. * t));
157}
158
159/*!
160 * The unit-less factor scaling top of atmosphere insolation according to the earth's
161 * distance from the sun. This is the "paleo" version used when the trigonometric
162 * expansion (equation 2.2.9 in Liou 2002) is not valid.
163 *
164 * Implements equation A1 in Zeitz et al.
165 *
166 * See also equation 2.2.5 from Liou (2002).
167 *
168 * This quantity is equal to `1 / R^2`, where R is the sun-earth distance in units of the
169 * semi-major axis of the earth's orbit.
170 *
171 * @param[in] eccentricity eccentricity of the earth's orbit
172 * @param[in] true_anomaly true anomaly of the earth in the heliocentric ecliptic coordinate system
173 */
174double DEBMSimplePointwise::distance_factor_paleo(double eccentricity, double true_anomaly) {
175 double E = eccentricity;
176
177 if (E == 1.0) {
178 // protect from division by zero
180 "invalid eccentricity value: 1.0");
181 }
182
183 return pow((1.0 + E * cos(true_anomaly)) / (1.0 - E * E), 2);
184}
185
186/*!
187 * Solar declination (radian)
188 *
189 * Implements equation 2.2.10 from Liou (2002)
190 */
192 // These coefficients come from Table 2.2 in Liou 2002
193 double
194 a0 = 0.006918,
195 a1 = -0.399912,
196 a2 = -0.006758,
197 a3 = -0.002697,
198 b0 = 0.,
199 b1 = 0.070257,
200 b2 = 0.000907,
201 b3 = 0.000148;
202
203 double t = 2. * M_PI * year_fraction;
204
205 return (a0 + b0 +
206 a1 * cos(t) + b1 * sin(t) +
207 a2 * cos(2. * t) + b2 * sin(2. * t) +
208 a3 * cos(3. * t) + b3 * sin(3. * t));
209}
210
211/*!
212 * Solar declination (radians). This is the "paleo" version used when
213 * the trigonometric expansion (equation 2.2.10 in Liou 2002) is not valid.
214 *
215 * The return value is in the range [-pi/2, pi/2].
216 *
217 * Implements equation in the text just above equation A1 in Zeitz et al.
218 *
219 * See also equation 2.2.4 of Liou (2002).
220 */
222 double solar_longitude) {
223 return asin(sin(obliquity) * sin(solar_longitude));
224}
225
226/*!
227 * Average top of atmosphere insolation (rate) during the daily melt period, in W/m^2.
228 *
229 * This should be equation 5 in Zeitz et al or equation 12 in Krebs-Kanzow et al, but both
230 * of these miss a factor of Delta_t (day length in seconds) in the numerator. (Note that
231 * in equation 5 of Zeitz et al the units of the LHS and the RHS should match, but [LHS] =
232 * W/m^2 and [RHS] = W/(m^2 s).)
233 *
234 * To confirm this, see the derivation of equation 2.2.21 in Liou and note that
235 *
236 * omega = 2 * pi (radian/day)
237 *
238 * or
239 *
240 * omega = (2 * pi / 86400) (radian/second).
241 *
242 * The correct equation should say
243 *
244 * S_Phi = A * B^2 * (h_phi * sin(phi) * sin(delta) + cos(phi) * cos(delta) * sin(h_phi)),
245 *
246 * where
247 *
248 * A = (S0 * Delta_t) / (Delta_t_Phi * pi),
249 * B = d_bar / d.
250 *
251 * Note that we do not know Delta_t_phi but we can use equation 2 in Zeitz et al (or
252 * equation 11 in Krebs-Kanzow et al) to get
253 *
254 * Delta_t_phi = h_phi * Delta_t / pi.
255 *
256 * This gives
257 *
258 * S_Phi = C * B^2 * (h_phi * sin(phi) * sin(delta) + cos(phi) * cos(delta) * sin(h_phi))
259 *
260 * with
261 *
262 * C = (S0 * Delta_t * pi) / (h_phi * Delta_t * pi)
263 *
264 * or
265 *
266 * C = S0 / h_phi.
267 *
268 * @param[in] solar_constant solar constant, W/m^2
269 * @param[in] distance_factor square of the ratio of the mean sun-earth distance to the current sun-earth distance (no units)
270 * @param[in] hour_angle hour angle (radians) when the sun reaches the critical angle Phi
271 * @param[in] latitude latitude (radians)
272 * @param[in] declination declination (radians)
273 *
274 */
275double DEBMSimplePointwise::insolation(double solar_constant, double distance_factor,
276 double hour_angle, double latitude, double declination) {
277 if (hour_angle == 0) {
278 return 0.0;
279 }
280
281 return ((solar_constant / hour_angle) * distance_factor *
282 (hour_angle * sin(latitude) * sin(declination) +
283 cos(latitude) * cos(declination) * sin(hour_angle)));
284}
285
286// NOLINTEND(readability-magic-numbers)
287
289 snow_depth = 0.0;
290 melt = 0.0;
291 runoff = 0.0;
292 smb = 0.0;
293}
294
296 temperature_melt = 0.0;
297 insolation_melt = 0.0;
298 offset_melt = 0.0;
299 total_melt = 0.0;
300}
301
303
304 const Config &config = *ctx.config();
305
306 m_time = ctx.time();
307
308 m_L = config.get_number("constants.fresh_water.latent_heat_of_fusion");
309 m_albedo_min = config.get_number("surface.debm_simple.albedo_min");
310 m_albedo_ocean = config.get_number("surface.debm_simple.albedo_ocean");
311 m_albedo_slope = config.get_number("surface.debm_simple.albedo_slope");
312 m_albedo_max = config.get_number("surface.debm_simple.albedo_max");
313 m_melt_threshold_temp = config.get_number("surface.debm_simple.melting_threshold_temp");
314 m_melt_c1 = config.get_number("surface.debm_simple.c1");
315 m_melt_c2 = config.get_number("surface.debm_simple.c2");
316 m_constant_eccentricity = config.get_number("surface.debm_simple.paleo.eccentricity");
317 m_constant_obliquity = config.get_number("surface.debm_simple.paleo.obliquity", "radian");
318 m_constant_perihelion_longitude = config.get_number("surface.debm_simple.paleo.perihelion_longitude", "radian");
319 m_paleo = config.get_flag("surface.debm_simple.paleo.enabled");
320 m_phi = config.get_number("surface.debm_simple.phi", "radian");
321 m_positive_threshold_temperature = config.get_number("surface.debm_simple.positive_threshold_temp");
322 m_refreeze_fraction = config.get_number("surface.debm_simple.refreeze");
323 m_refreeze_ice_melt = config.get_flag("surface.debm_simple.refreeze_ice_melt");
324 m_solar_constant = config.get_number("surface.debm_simple.solar_constant");
325 m_transmissivity_intercept = config.get_number("surface.debm_simple.tau_a_intercept");
326 m_transmissivity_slope = config.get_number("surface.debm_simple.tau_a_slope");
327
328 m_ice_density = config.get_number("constants.ice.density");
329 m_water_density = config.get_number("constants.fresh_water.density");
330
331 assert(m_albedo_slope < 0.0);
332 assert(m_ice_density > 0.0);
333
334 std::string paleo_file = config.get_string("surface.debm_simple.paleo.file");
335
336 if (not paleo_file.empty()) {
337 m_eccentricity.reset(new ScalarForcing(ctx, "surface.debm_simple.paleo", "eccentricity", "1",
338 "1", "eccentricity of the earth"));
339
340 m_obliquity.reset(new ScalarForcing(ctx, "surface.debm_simple.paleo", "obliquity", "radian",
341 "degree", "obliquity of the earth"));
342
344 new ScalarForcing(ctx, "surface.debm_simple.paleo", "perihelion_longitude", "radian",
345 "degree", "longitude of the perihelion relative to the vernal equinox, "
346 "in the geocentric ecliptic coordinate system"));
347 }
348}
349
350/*! Albedo parameterized as a function of the melt rate
351 *
352 * See equation 7 in Zeitz et al.
353 *
354 * @param[in] melt_rate melt rate (meters (liquid water equivalent) per second)
355 * @param[in] cell_type cell type mask (used to exclude ice free areas)
356 */
357double DEBMSimplePointwise::albedo(double melt_rate, MaskValue cell_type) const {
358 if (cell_type == MASK_ICE_FREE_OCEAN) {
359 return m_albedo_ocean;
360 }
361
362 assert(melt_rate >= 0.0);
363
364 return std::max(m_albedo_max + m_albedo_slope * melt_rate * m_ice_density, //
366}
367
368/*! Atmosphere transmissivity (no units; acts as a scaling factor)
369 *
370 * See appendix A2 in Zeitz et al 2021.
371 *
372 * @param[in] elevation elevation above the geoid (meters)
373 */
376}
377
379 double solar_declination = 0.0;
380 double distance_factor = 0.0;
381
382 double year_fraction = m_time->year_fraction(time);
383 if (m_paleo) {
384 double eccentricity = this->eccentricity(time);
385 double geocentric_perihelion_longitude = this->perihelion_longitude(time);
386
387 double sun_true_longitude =
388 this->solar_longitude(year_fraction, eccentricity, geocentric_perihelion_longitude);
389
390 solar_declination = solar_declination_paleo(obliquity(time), sun_true_longitude);
391
392 // Note: here sun_true_longitude is the true longitude of the sun in the geocentric
393 // ecliptic coordinate system. The perihelion longitude is in the same coordinate
394 // system.
395 //
396 // In the heliocentric ecliptic system
397 //
398 // earth_true_longitude = sun_true_longitude - 180 degrees
399 // heliocentric_perihelion_longitude = geocentric_perihelion_longitude - 180 degrees
400 //
401 // So earth_true_anomaly = earth_true_longitude - heliocentric_perihelion_longitude
402 // = sun_true_longitude - geocentric_perihelion_longitude
403 //
404 double earth_true_anomaly = sun_true_longitude - geocentric_perihelion_longitude;
405
406 distance_factor = distance_factor_paleo(eccentricity, earth_true_anomaly);
407 } else {
408 solar_declination = solar_declination_present_day(year_fraction);
409 distance_factor = distance_factor_present_day(year_fraction);
410 }
411
412 return { solar_declination, distance_factor };
413}
414
415
416/*!
417 * Compute top of atmosphere insolation to report as a diagnostic quantity.
418 *
419 * Do not use this in the model itself: doing so will make it slower because that way we'd
420 * end up computing hour_angle more than once.
421 */
422double DEBMSimplePointwise::insolation_diagnostic(double declination, double distance_factor,
423 double latitude_degrees) const {
424 const double degrees_to_radians = M_PI / 180.0;
425 double latitude_rad = latitude_degrees * degrees_to_radians;
426
427 double h_phi = hour_angle(m_phi, latitude_rad, declination);
428
429 return insolation(m_solar_constant, distance_factor, h_phi, latitude_rad, declination);
430}
431
432/* Melt amount (in m water equivalent) and its components over the time step `dt`
433 *
434 * Implements equation (1) in Zeitz et al.
435 *
436 * See also the equation (6) in Krebs-Kanzow et al.
437 *
438 * @param[in] time current time (seconds)
439 * @param[in] dt time step length (seconds)
440 * @param[in] T_std_deviation standard deviation of the near-surface air temperature (kelvin)
441 * @param[in] T near-surface air temperature (kelvin)
442 * @param[in] surface_elevation surface elevation (meters)
443 * @param[in] latitude latitude (degrees north)
444 * @param[in] albedo current albedo (fraction)
445 */
447 double distance_factor,
448 double dt,
449 double T_std_deviation,
450 double T,
451 double surface_elevation,
452 double latitude,
453 double albedo) const {
454 assert(dt > 0.0);
455
456 const double degrees_to_radians = M_PI / 180.0;
457 double latitude_rad = latitude * degrees_to_radians;
458
459 double transmissivity = atmosphere_transmissivity(surface_elevation);
460 double h_phi = hour_angle(m_phi, latitude_rad, declination);
461 double insolation =
462 this->insolation(m_solar_constant, distance_factor, h_phi, latitude_rad, declination);
463
464 double Teff = CalovGreveIntegrand(T_std_deviation,
466 const double eps = 1.0e-4;
467 if (Teff < eps) {
468 Teff = 0;
469 }
470
471 // Note that in the line below we replace "Delta_t_Phi / Delta_t" with "h_Phi / pi". See
472 // equations 1 and 2 in Zeitz et al.
473 double A = dt * (h_phi / M_PI / (m_water_density * m_L));
474
475 DEBMSimpleMelt result;
476
477 result.insolation_melt = A * (transmissivity * (1.0 - albedo) * insolation);
478 result.temperature_melt = A * m_melt_c1 * Teff;
479 result.offset_melt = A * m_melt_c2;
480
481 double total_melt = (result.insolation_melt + result.temperature_melt +
482 result.offset_melt);
483 // this model should not produce negative melt rates
484 result.total_melt = std::max(total_melt, 0.0);
485
486 if (T < m_melt_threshold_temp) {
487 result.total_melt = 0.0;
488 }
489
490 return result;
491}
492
493/*! @brief Compute the surface mass balance at a location from the amount of melted snow
494 * and the solid accumulation amount in a time interval.
495 *
496 * - a fraction of the melted snow and ice refreezes, conceptualized
497 * as superimposed ice
498 */
499DEBMSimpleChanges DEBMSimplePointwise::step(double ice_thickness, double max_melt,
500 double old_snow_depth, double accumulation) const {
501 DEBMSimpleChanges result;
502
503 double
504 snow_depth = old_snow_depth,
505 snow_melted = 0.0,
506 ice_melted = 0.0;
507
508 assert(ice_thickness >= 0);
509
510 // snow depth cannot exceed total ice_thickness
511 snow_depth = std::min(snow_depth, ice_thickness);
512
513 assert(snow_depth >= 0);
514
515 snow_depth += accumulation;
516
517 if (max_melt <= 0.0) { // The "no melt" case.
518 snow_melted = 0.0;
519 ice_melted = 0.0;
520 } else if (max_melt <= snow_depth) {
521 // Some of the snow melted and some is left; in any case, all of the energy available
522 // for melt was used up in melting snow.
523 snow_melted = max_melt;
524 ice_melted = 0.0;
525 } else {
526 // All (snow_depth meters) of snow melted. Excess melt is available to melt ice.
527 snow_melted = snow_depth;
528 ice_melted = std::min(max_melt - snow_melted, ice_thickness);
529 }
530
531 double ice_created_by_refreeze = m_refreeze_fraction * snow_melted;
533 ice_created_by_refreeze += m_refreeze_fraction * ice_melted;
534 }
535
536 snow_depth = std::max(snow_depth - snow_melted, 0.0);
537
538 double total_melt = (snow_melted + ice_melted);
539 double runoff = total_melt - ice_created_by_refreeze;
540 double smb = accumulation - runoff;
541
542 result.snow_depth = snow_depth - old_snow_depth;
543 result.melt = total_melt;
544 result.runoff = runoff;
545 result.smb = ice_thickness + smb >= 0 ? smb : -ice_thickness;
546
547 assert(ice_thickness + result.smb >= 0);
548
549 return result;
550}
551
552/*!
553 * Eccentricity of the earth’s orbit (no units).
554 */
555double DEBMSimplePointwise::eccentricity(double time) const {
556 if (m_eccentricity != nullptr) {
557 return m_eccentricity->value(time);
558 }
560}
561
562/*!
563 * Returns the obliquity of the ecliptic in radians.
564 */
565double DEBMSimplePointwise::obliquity(double time) const {
566 if (m_obliquity != nullptr) {
567 return m_obliquity->value(time);
568 }
570}
571
572/*!
573 * Returns the longitude of the perihelion (radians) in the geocentric ecliptic coordinate
574 * system.
575 */
577 if (m_perihelion_longitude != nullptr) {
578 double L_p = remainder(m_perihelion_longitude->value(time), 2.0 * M_PI);
579 if (L_p < 0.0) {
580 L_p = L_p + 2 * M_PI;
581 }
582 return L_p;
583 }
585}
586
587} // end of namespace surface
588} // end of namespace pism
double get_number(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
std::string get_string(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
bool get_flag(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
A class for storing and accessing PISM configuration flags and parameters.
std::shared_ptr< const Config > config() const
Definition Context.cc:89
std::shared_ptr< const Time > time() const
Definition Context.cc:101
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
double albedo(double melt_rate, MaskValue cell_type) const
static double insolation(double solar_constant, double distance_factor, double hour_angle, double latitude, double declination)
double m_transmissivity_slope
slope used in the linear parameterization of transmissivity
std::unique_ptr< ScalarForcing > m_eccentricity
std::unique_ptr< ScalarForcing > m_obliquity
double m_refreeze_fraction
refreeze fraction
double m_positive_threshold_temperature
threshold temperature for the computation of temperature-driven melt
static double CalovGreveIntegrand(double sigma, double temperature)
static double solar_longitude(double year_fraction, double eccentricity, double perihelion_longitude)
DEBMSimpleMelt melt(double declination, double distance_factor, double dt, double T_std_deviation, double T, double surface_elevation, double lat, double albedo) const
static double distance_factor_paleo(double eccentricity, double true_anomaly)
double m_albedo_slope
slope used in the linear parameterization of the albedo as a function of melt
double insolation_diagnostic(double declination, double distance_factor, double latitude_degrees) const
bool m_refreeze_ice_melt
refreeze melted ice
double perihelion_longitude(double time) const
double m_solar_constant
the solar constant
static double hour_angle(double phi, double latitude, double declination)
static double distance_factor_present_day(double year_fraction)
double m_phi
minimum solar elevation angle above which melt is possible
static double solar_declination_paleo(double obliquity, double solar_longitude)
double atmosphere_transmissivity(double elevation) const
DEBMSimpleOrbitalParameters orbital_parameters(double time) const
std::unique_ptr< ScalarForcing > m_perihelion_longitude
static double solar_declination_present_day(double year_fraction)
DEBMSimpleChanges step(double ice_thickness, double max_melt, double snow_depth, double accumulation) const
Compute the surface mass balance at a location from the amount of melted snow and the solid accumulat...
std::shared_ptr< const Time > m_time
#define PISM_ERROR_LOCATION
const double phi
Definition exactTestK.c:41
static const double b0
Definition exactTestL.cc:41
T clip(T x, T a, T b)
MaskValue
Definition Mask.hh:30
@ MASK_ICE_FREE_OCEAN
Definition Mask.hh:35