PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
PSVerification.cc
Go to the documentation of this file.
1/* Copyright (C) 2014, 2015, 2016, 2017, 2018, 2023, 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
20#include <algorithm>
21#include <vector>
22
23#include "pism/verification/PSVerification.hh"
24#include "pism/coupler/AtmosphereModel.hh"
25#include "pism/rheology/PatersonBuddCold.hh"
26#include "pism/util/EnthalpyConverter.hh"
27#include "pism/util/Time.hh"
28#include "pism/util/Config.hh"
29
30#include "pism/verification/tests/exactTestsABCD.h"
31#include "pism/verification/tests/exactTestsFG.hh"
32#include "pism/verification/tests/exactTestH.h"
33#include "pism/verification/tests/exactTestL.hh"
34
35#include "pism/util/error_handling.hh"
36#include "pism/util/Grid.hh"
37#include "pism/util/MaxTimestep.hh"
38#include "pism/util/Context.hh"
39
40namespace pism {
41namespace surface {
42
43const double Verification::ablationRateOutside = 0.02; // m year-1
44const double Verification::secpera = 3.15569259747e7;
45
46const double Verification::ST = 1.67e-5;
47const double Verification::Tmin = 223.15; // K
48const double Verification::LforFG = 750000; // m
49const double Verification::ApforG = 200; // m
50
51Verification::Verification(std::shared_ptr<const Grid> g,
52 std::shared_ptr<EnthalpyConverter> EC, int test)
53 : PSFormulas(g), m_testname(test), m_EC(EC) {
54 // empty
55}
56
57void Verification::init_impl(const Geometry &geometry) {
58 // Make sure that ice surface temperature and climatic mass balance
59 // get initialized at the beginning of the run (as far as I can tell
60 // this affects zero-length runs only).
61 update(geometry, time().current(), 0);
62}
63
64std::set<VariableMetadata> Verification::state_impl() const {
65 return array::metadata({ m_mass_flux.get(), m_temperature.get() });
66}
67
68void Verification::write_state_impl(const OutputFile &output) const {
69 m_mass_flux->write(output);
70 m_temperature->write(output);
71}
72
74 (void) t;
75 return MaxTimestep("verification surface model");
76}
77
78/** Initialize climate inputs of tests K and O.
79 *
80 * @return 0 on success
81 */
83
84 m_mass_flux->set(0.0);
85 m_temperature->set(223.15);
86}
87
88/** Update the test L climate input (once).
89 *
90 * Unlike other `update_...()` methods, this one uses [kg m-2 s-1]
91 * as units of the climatic_mass_balance.
92 *
93 * @return 0 on success
94 */
96 double A0, T0;
97
98 double n = m_config->get_number("stress_balance.sia.Glen_exponent");
100
101 // compute T so that A0 = A(T) = Acold exp(-Qcold/(R T)) (i.e. for PatersonBuddCold);
102 // set all temps to this constant
103 A0 = 1.0e-16/secpera; // = 3.17e-24 1/(Pa^3 s); (EISMINT value) flow law parameter
104 T0 = tgaIce.tempFromSoftness(A0);
105
106 m_temperature->set(T0);
107
108 const double
109 ice_density = m_config->get_number("constants.ice.density"),
110 a0 = units::convert(m_sys, 0.3, "m year^-1", "m second^-1"),
111 L = 750e3,
112 Lsqr = L * L;
113
115 for (auto p : m_grid->points()) {
116 const int i = p.i(), j = p.j();
117
118 double r = grid::radius(*m_grid, i, j);
119 (*m_mass_flux)(i, j) = a0 * (1.0 - (2.0 * r * r / Lsqr));
120
121 (*m_mass_flux)(i, j) *= ice_density; // convert to [kg m-2 s-1]
122 }
123}
124
126
127 // initialize temperature; the value used does not matter
128 m_temperature->set(273.15);
129
130 // initialize mass balance:
131 m_mass_flux->set(0.0);
132}
133
134void Verification::update_impl(const Geometry &geometry, double t, double dt) {
135 (void) geometry;
136 (void) dt;
137
138 switch (m_testname) {
139 case 'A':
140 case 'B':
141 case 'C':
142 case 'D':
143 case 'H':
144 update_ABCDH(t);
145 break;
146 case 'F':
147 case 'G':
148 update_FG(t);
149 break;
150 case 'K':
151 case 'O':
152 update_KO();
153 break;
154 case 'L':
155 {
156 update_L();
157 // return here; note update_L() uses correct units
158 return;
159 }
160 case 'V':
161 update_V();
162 break;
163 default:
164 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Test %c is not implemented.", m_testname);
165 }
166
167 // convert from [m second-1] to [kg m-2 s-1]
168 m_mass_flux->scale(m_config->get_number("constants.ice.density"));
169}
170
171/** Update climate inputs for tests A, B, C, D, E, H.
172 *
173 * @return 0 on success
174 */
175void Verification::update_ABCDH(double time) {
176 double A0, T0, accum;
177
178 double f = m_config->get_number("constants.ice.density") / m_config->get_number("bed_deformation.mantle_density");
179
180 double n = m_config->get_number("stress_balance.sia.Glen_exponent");
182
183 // compute T so that A0 = A(T) = Acold exp(-Qcold/(R T)) (i.e. for PatersonBuddCold);
184 // set all temps to this constant
185 A0 = 1.0e-16/secpera; // = 3.17e-24 1/(Pa^3 s); (EISMINT value) flow law parameter
186 T0 = tgaIce.tempFromSoftness(A0);
187
188 m_temperature->set(T0);
189
191 ParallelSection loop(m_grid->com);
192 try {
193 for (auto p : m_grid->points()) {
194 const int i = p.i(), j = p.j();
195
196 const double r = grid::radius(*m_grid, i, j);
197 switch (m_testname) {
198 case 'A':
199 accum = exactA(r).M;
200 break;
201 case 'B':
202 accum = exactB(time, r).M;
203 break;
204 case 'C':
205 accum = exactC(time, r).M;
206 break;
207 case 'D':
208 accum = exactD(time, r).M;
209 break;
210 case 'H':
211 accum = exactH(f, time, r).M;
212 break;
213 default:
214 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "test must be A, B, C, D, or H, got %c",
215 m_testname);
216 }
217 (*m_mass_flux)(i, j) = accum;
218 }
219 } catch (...) {
220 loop.failed();
221 }
222 loop.check();
223}
224
225void Verification::update_FG(double time) {
226
227 const double t = m_testname == 'F' ? 0.0 : time;
228 const double A = m_testname == 'F' ? 0.0 : ApforG;
229
231
232 for (auto p : m_grid->points()) {
233 const int i = p.i(), j = p.j();
234
235 // avoid singularity at origin
236 const double r = std::max(grid::radius(*m_grid, i, j), 1.0);
237
238 (*m_temperature)(i, j) = Tmin + ST * r;
239
240 if (r > LforFG - 1.0) {
241 // if (essentially) outside of sheet
242 (*m_mass_flux)(i, j) = - ablationRateOutside / secpera;
243 } else {
244 (*m_mass_flux)(i, j) = exactFG(t, r, m_grid->z(), A).M;
245 }
246 }
247}
248
249} // end of namespace surface
250} // end of namespace pism
const units::System::Ptr m_sys
unit system used by this component
Definition Component.hh:162
const Time & time() const
Definition Component.cc:111
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
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
void failed()
Indicates a failure of a parallel section.
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition Array.hh:66
double tempFromSoftness(double A) const
Return the temperature T corresponding to a given value A=A(T).
Cold case of Paterson-Budd.
std::shared_ptr< array::Scalar > m_temperature
Definition Formulas.hh:50
std::shared_ptr< array::Scalar > m_mass_flux
Definition Formulas.hh:49
void update(const Geometry &geometry, double t, double dt)
static const double ablationRateOutside
virtual std::set< VariableMetadata > state_impl() const
MaxTimestep max_timestep_impl(double t) const
static const double ApforG
Verification(std::shared_ptr< const Grid > g, std::shared_ptr< EnthalpyConverter > EC, int test)
void update_impl(const Geometry &geometry, double t, double dt)
void write_state_impl(const OutputFile &output) const
The default (empty implementation).
void init_impl(const Geometry &geometry)
static const double LforFG
std::shared_ptr< EnthalpyConverter > m_EC
static const double secpera
#define PISM_ERROR_LOCATION
struct TestHParameters exactH(const double f, const double t, const double r)
Definition exactTestH.c:76
static const double L
Definition exactTestL.cc:40
#define n
Definition exactTestM.c:37
struct TestABCDParameters exactB(const double t, const double r)
struct TestABCDParameters exactD(const double t, const double r)
struct TestABCDParameters exactA(double r)
struct TestABCDParameters exactC(const double t, const double r)
std::set< VariableMetadata > metadata(std::initializer_list< const Array * > vecs)
Definition Array.cc:1244
double radius(const Grid &grid, int i, int j)
Returns the distance from the point (i,j) to the origin.
Definition Grid.cc:1367
double convert(System::Ptr system, double input, const std::string &spec1, const std::string &spec2)
Convert a quantity from unit1 to unit2.
Definition Units.cc:70
static const double g
Definition exactTestP.cc:36
TestFGParameters exactFG(double t, double r, const std::vector< double > &z, double Cp)