Loading [MathJax]/extensions/tex2jax.js
PISM, A Parallel Ice Sheet Model 2.2.1-cd005eec8 committed by Constantine Khrulev on 2025-03-07
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SteadyState.cc
Go to the documentation of this file.
1/* Copyright (C) 2019, 2020, 2021, 2023, 2024, 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 "pism/hydrology/SteadyState.hh"
21
22#include <gsl/gsl_interp.h> // gsl_interp_bsearch
23
24#include "pism/hydrology/EmptyingProblem.hh"
25
26#include "pism/util/Time.hh" // time().current()
27#include "pism/util/Profiling.hh"
28#include "pism/util/Context.hh"
29#include "pism/util/MaxTimestep.hh"
30
31/* FIXMEs
32 *
33 * - At some later date I might want to support water input rates coming from the model.
34 * In that case I will have to accumulate input at every time step and then use the
35 * average (in time) when it's time to update the model.
36 *
37 * - IceModel::step() updates ice geometry before calling IceModel::hydrology_step(). This
38 * means that a hydrology model has to be able to provide its outputs before the first
39 * update() call. We save subglacial water flux to ensure that this is true for
40 * re-started runs, but in runs started using bootstrapping the first time step will see
41 * "bootstrapped" hydrology outputs (in this case: zero flux).
42 *
43 * - In this context (i.e. computing water flux using piecewise-in-time forcing data) it
44 * makes sense to update the flux at the beginning of an "update interval". In the case
45 * described above (water input coming from the model) we would want to update at the
46 * *end* of an interval.
47 *
48 */
49
50namespace pism {
51namespace hydrology {
52
54 m_log->message(2,
55 "* Initializing the \"steady state\" subglacial hydrology model ...\n");
56}
57
58SteadyState::SteadyState(std::shared_ptr<const Grid> grid)
59 : NullTransport(grid) {
60
61 m_time_name = m_config->get_string("time.dimension_name") + "_hydrology_steady";
62 m_t_last = time().current();
63 m_update_interval = m_config->get_number("hydrology.steady.flux_update_interval", "seconds");
64 m_t_eps = 1.0;
65 m_bootstrap = false;
66
68
69 if (m_config->get_flag("hydrology.add_water_input_to_till_storage")) {
71 "'steady' hydrology requires hydrology.add_water_input_to_till_storage == false");
72 }
73
74 if (m_config->get_string("hydrology.surface_input.file").empty()) {
76 "'steady' hydrology requires hydrology.surface_input.file");
77 }
78}
79
80void SteadyState::update_impl(double t, double dt, const Inputs& inputs) {
81 NullTransport::update_impl(t, dt, inputs);
82
83 double t_next = m_t_last + max_timestep(m_t_last).value();
84
85 if (t >= t_next or std::abs(t_next - t) < m_t_eps or
87
88 m_log->message(3, " Updating the steady-state subglacial water flux...\n");
89
90 profiling().begin("steady_emptying");
91
92 m_emptying_problem->update(*inputs.geometry,
93 inputs.no_model_mask,
95
96 profiling().end("steady_emptying");
98
99 m_t_last = t;
100 m_bootstrap = false;
101 }
102}
103
104std::map<std::string, Diagnostic::Ptr> SteadyState::diagnostics_impl() const {
105 auto hydro_diagnostics = NullTransport::diagnostics_impl();
106
107 return combine(m_emptying_problem->diagnostics(), hydro_diagnostics);
108}
109
111
112 // compute the maximum time step coming from the forcing (water input rate)
113 double dt_forcing = 0.0;
114 if (not m_time.empty()) {
115
116 // the right end point of the last time interval in the forcing file
117 double t_last = m_time_bounds.back();
118
119 double t_next = 0.0;
120 if (t < m_time[0]) {
121 // Allow stepping until the left end point of the first interval.
122 t_next = m_time[0];
123 } else if (t >= t_last) {
124 // Went past the right end point of the last forcing intervals: no time step
125 // restriction from forcing.
126 t_next = t + m_update_interval;
127 } else {
128 // find the index k such that m_time[k] <= t < m_time[k + 1]
129 size_t k = gsl_interp_bsearch(m_time.data(), t, 0, m_time.size());
130
131 assert(m_time[k] <= t);
132 assert(k + 1 == m_time.size() or t < m_time[k + 1]);
133
134 t_next = m_time_bounds[2 * k + 1];
135
136 if (std::abs(t_next - t) < m_t_eps) {
137 // reached t_next; use the right end point of the next interval
138 if (k + 1 < m_time.size()) {
139 t_next = m_time_bounds[2 * (k + 1) + 1];
140 } else {
141 // No time step restriction from forcing. We set dt_forcing to m_update_interval
142 // because dt_interval below will not exceed this, effectively selecting
143 // dt_interval.
144 t_next = t + m_update_interval;
145 }
146 }
147 }
148
149 dt_forcing = t_next - t;
150
151 assert(dt_forcing > 0.0);
152 } else {
153 dt_forcing = m_update_interval;
154 }
155
156 // compute the maximum time step using the update interval
157 double dt_interval = 0.0;
158 {
159 if (t < m_t_last) {
161 "time %f is less than the previous time %f",
162 t, m_t_last);
163 }
164
165 // Find the smallest time of the form m_t_last + k * m_update_interval that is greater
166 // than t
167 double k = ceil((t - m_t_last) / m_update_interval);
168
169 double
170 t_next = m_t_last + k * m_update_interval;
171
172 dt_interval = t_next - t;
173
174 if (dt_interval < m_t_eps) {
175 dt_interval = m_update_interval;
176 }
177 }
178
179 double dt = std::min(dt_forcing, dt_interval);
180
181 auto dt_null = NullTransport::max_timestep_impl(t);
182 if (dt_null.finite()) {
183 dt = std::min(dt, dt_null.value());
184 }
185
186 return MaxTimestep(dt, "hydrology 'steady'");
187}
188
191
192 if (not output.variable_exists(m_time_name)) {
194
195 output.write_attribute(m_time_name, "long_name",
196 "time of the last update of the steady state subglacial water flux");
197 output.write_attribute(m_time_name, "calendar", time().calendar());
198 output.write_attribute(m_time_name, "units", time().units_string());
199 }
200
201 m_Q.define(output, io::PISM_DOUBLE);
202}
203
204void SteadyState::write_model_state_impl(const File& output) const {
206
207 output.write_variable(m_time_name, {0}, {1}, &m_t_last);
208 m_Q.write(output);
209}
210
211void SteadyState::restart_impl(const File &input_file, int record) {
212 NullTransport::restart_impl(input_file, record);
213
214 init_time(m_config->get_string("hydrology.surface_input.file"));
215
216 // Read m_t_last
217 {
218 if (input_file.variable_exists(m_time_name)) {
219 input_file.read_variable(m_time_name, {0}, {1}, &m_t_last);
220 } else {
221 m_t_last = time().current();
222 }
223 }
224
225 m_Q.read(input_file, record);
226
227 regrid("hydrology 'steady'", m_Q, REGRID_WITHOUT_REGRID_VARS);
228}
229
230void SteadyState::bootstrap_impl(const File &input_file,
231 const array::Scalar &ice_thickness) {
232 NullTransport::bootstrap_impl(input_file, ice_thickness);
233
234 init_time(m_config->get_string("hydrology.surface_input.file"));
235
236 // Read m_t_last
237 {
238 if (input_file.variable_exists(m_time_name)) {
239 input_file.read_variable(m_time_name, {0}, {1}, &m_t_last);
240 } else {
241 m_t_last = time().current();
242 }
243 }
244
245 // Read water flux
246 if (input_file.variable_exists(m_Q.metadata().get_name())) {
247 // Regrid from the input file.
248 m_Q.regrid(input_file, io::Default::Nil());
249
250 // Allow regridding from a different file.
251 regrid("hydrology 'steady'", m_Q, REGRID_WITHOUT_REGRID_VARS);
252 } else {
253 // No water flux in the input file; try regridding from a different file.
254 auto n = m_Q.state_counter();
255
256 regrid("hydrology 'steady'", m_Q, REGRID_WITHOUT_REGRID_VARS);
257
258 if (n == m_Q.state_counter()) {
259 // Regridding did not fill m_Q: we need to bootstrap during the first update_impl()
260 // call.
261 m_bootstrap = true;
262 }
263 }
264}
265
267 const array::Scalar &W,
268 const array::Scalar &P) {
269 NullTransport::init_impl(W_till, W, P);
270
271 m_Q.set(0.0);
272
273 m_bootstrap = true;
274}
275
276
277/*!
278 * Read time bounds corresponding to the water input rate in the forcing file.
279 *
280 * These times are used to compute the maximum time step the model can take while still
281 * capturing temporal variability of the forcing.
282 */
283void SteadyState::init_time(const std::string &input_file) {
284
285 std::string variable_name = "water_input_rate";
286
287 File file(m_grid->com, input_file, io::PISM_GUESS, io::PISM_READONLY);
288
289 auto time_name = io::time_dimension(m_grid->ctx()->unit_system(),
290 file, variable_name);
291
292 if (time_name.empty()) {
293 // Water input rate is time-independent. m_time and m_time_bounds are left empty.
294 return;
295 }
296
297 std::string bounds_name = file.read_text_attribute(time_name, "bounds");
298
299 if (bounds_name.empty()) {
300 // no time bounds attribute
302 "Variable '%s' does not have the time_bounds attribute.\n"
303 "Cannot use time-dependent water input rate without time bounds.",
304 time_name.c_str());
305 }
306
307 // read time bounds data from a file
309 io::read_bounds(file, bounds_name, time().units_string(), m_grid->ctx()->unit_system());
310
311 // time bounds data overrides the time variable: we make t[j] be the
312 // left end-point of the j-th interval
313 m_time.resize(m_time_bounds.size() / 2);
314 for (unsigned int k = 0; k < m_time.size(); ++k) {
315 m_time[k] = m_time_bounds[2*k];
316 }
317
318 if (not is_increasing(m_time)) {
320 "time bounds in %s are invalid", input_file.c_str());
321 }
322}
323
324} // end of namespace hydrology
325} // end of namespace pism
const Time & time() const
Definition Component.cc:109
std::shared_ptr< const Grid > grid() const
Definition Component.cc:105
const Config::ConstPtr m_config
configuration database used by this component
Definition Component.hh:158
const Logger::ConstPtr m_log
logger (for easy access)
Definition Component.hh:162
const std::shared_ptr< const Grid > m_grid
grid used by this component
Definition Component.hh:156
void regrid(const std::string &module_name, array::Array &variable, RegriddingFlag flag=NO_REGRID_WITHOUT_REGRID_VARS)
Definition Component.cc:159
const Profiling & profiling() const
Definition Component.cc:113
MaxTimestep max_timestep(double t) const
Reports the maximum time-step the model can take at time t.
Definition Component.cc:183
void read_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, double *ip) const
Definition File.cc:699
bool variable_exists(const std::string &short_name) const
Checks if a variable exists.
Definition File.cc:378
void write_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const double *op) const
Definition File.cc:712
void define_variable(const std::string &name, io::Type nctype, const std::vector< std::string > &dims) const
Define a variable.
Definition File.cc:543
void write_attribute(const std::string &var_name, const std::string &att_name, io::Type nctype, const std::vector< double > &values) const
Write a multiple-valued double attribute.
Definition File.cc:590
std::string read_text_attribute(const std::string &var_name, const std::string &att_name) const
Get a text attribute.
Definition File.cc:645
High-level PISM I/O class.
Definition File.hh:55
double value() const
Get the value of the maximum time step.
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
void begin(const char *name) const
Definition Profiling.cc:75
void end(const char *name) const
Definition Profiling.cc:91
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
double current() const
Current time, in seconds.
Definition Time.cc:461
std::string get_name() const
void copy_from(const Array2D< T > &source)
Definition Array2D.hh:73
void read(const std::string &filename, unsigned int time)
Definition Array.cc:731
void define(const File &file, io::Type default_type) const
Define variables corresponding to an Array in a file opened using file.
Definition Array.cc:463
void write(const std::string &filename) const
Definition Array.cc:722
int state_counter() const
Get the object state counter.
Definition Array.cc:127
void set(double c)
Result: v[j] <- c for all j.
Definition Array.cc:629
void regrid(const std::string &filename, io::Default default_value)
Definition Array.cc:736
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
Definition Array.cc:476
array::Scalar m_surface_input_rate
Definition Hydrology.hh:179
virtual void define_model_state_impl(const File &output) const
The default (empty implementation).
Definition Hydrology.cc:467
virtual std::map< std::string, Diagnostic::Ptr > diagnostics_impl() const
Definition Hydrology.cc:443
virtual void write_model_state_impl(const File &output) const
The default (empty implementation).
Definition Hydrology.cc:471
const Geometry * geometry
Definition Hydrology.hh:37
const array::Scalar1 * no_model_mask
Definition Hydrology.hh:35
virtual void restart_impl(const File &input_file, int record)
virtual void init_impl(const array::Scalar &W_till, const array::Scalar &W, const array::Scalar &P)
virtual void bootstrap_impl(const File &input_file, const array::Scalar &ice_thickness)
virtual void update_impl(double t, double dt, const Inputs &inputs)
Solves an implicit step of a highly-simplified ODE.
virtual MaxTimestep max_timestep_impl(double t) const
double m_update_interval
Update interval in seconds.
void init_time(const std::string &input_file)
void write_model_state_impl(const File &output) const
The default (empty implementation).
double m_t_last
time of the last water flux update
void update_impl(double t, double dt, const Inputs &inputs)
Solves an implicit step of a highly-simplified ODE.
std::vector< double > m_time_bounds
Time bounds corresponding to records in the input file.
MaxTimestep max_timestep_impl(double t) const
std::string m_time_name
Name of the variable used to store the last update time.
void restart_impl(const File &input_file, int record)
bool m_bootstrap
Set to true in bootstrap_impl() if update_impl() has to bootstrap m_Q.
std::map< std::string, Diagnostic::Ptr > diagnostics_impl() const
std::shared_ptr< EmptyingProblem > m_emptying_problem
void define_model_state_impl(const File &output) const
The default (empty implementation).
std::vector< double > m_time
Times corresponding to records in the input file.
void initialization_message() const
SteadyState(std::shared_ptr< const Grid > g)
void bootstrap_impl(const File &input_file, const array::Scalar &ice_thickness)
void init_impl(const array::Scalar &W_till, const array::Scalar &W, const array::Scalar &P)
double m_t_eps
Temporal resolution to use when checking whether it's time to update.
static Default Nil()
Definition IO_Flags.hh:93
#define PISM_ERROR_LOCATION
#define n
Definition exactTestM.c:37
@ PISM_GUESS
Definition IO_Flags.hh:56
@ PISM_READONLY
open an existing file for reading only
Definition IO_Flags.hh:68
@ PISM_DOUBLE
Definition IO_Flags.hh:52
std::vector< double > read_bounds(const File &file, const std::string &bounds_variable_name, const std::string &internal_units, std::shared_ptr< units::System > unit_system)
std::string time_dimension(units::System::Ptr unit_system, const File &file, const std::string &variable_name)
bool is_increasing(const std::vector< double > &a)
Checks if a vector of doubles is strictly increasing.
static const double k
Definition exactTestP.cc:42
static std::string calendar(const File *input_file, const Config &config, const Logger &log)
Definition Time.cc:146
T combine(const T &a, const T &b)