20 #include "pism/util/ScalarForcing.hh"
26 #include <gsl/gsl_spline.h>
28 #include "pism/util/ConfigInterface.hh"
29 #include "pism/util/Context.hh"
30 #include "pism/util/Time.hh"
31 #include "pism/util/error_handling.hh"
32 #include "pism/util/Logger.hh"
33 #include "pism/util/io/File.hh"
34 #include "pism/util/io/io_helpers.hh"
35 #include "pism/util/VariableMetadata.hh"
36 #include "pism/util/io/IO_Flags.hh"
47 double min = *std::min_element(data.begin(), data.end());
48 double max = *std::max_element(data.begin(), data.end());
52 metadata[
"output_units"]);
56 std::string spacer(metadata.
get_name().size(),
' ');
60 " %s \\ min,max = %9.3f,%9.3f (%s)\n",
79 gsl_interp_accel*
acc;
84 const std::string &filename,
85 const std::string &variable_name,
86 const std::string &units,
87 const std::string &output_units,
88 const std::string &long_name,
95 variable[
"units"] = units;
96 variable[
"output_units"] = output_units;
97 variable[
"long_name"] = long_name;
104 ctx.
log()->message(2,
105 " reading %s (%s) from file '%s'...\n",
106 long_name.c_str(), variable_name.c_str(), filename.c_str());
112 std::vector<double> data{};
116 std::string time_name = file.
dimensions(variable_name)[0];
118 std::vector<double> times{};
119 std::vector<double> bounds{};
121 file, time_name, ctx.
time()->units_string(),
123 size_t N = times.size();
128 double v0 = data.front();
129 double v1 = data.back();
131 double b0 = bounds.front();
132 double b1 = bounds.back();
136 double dt1 = times.front() -
b0;
137 double dt2 = b1 - times.back();
140 double alpha = dt1 + dt2 > 0 ? dt2 / (dt1 + dt2) : 0.0;
142 v0 = (1.0 - alpha) * data.back() + alpha * data.front();
158 if (bounds.front() < times.front()) {
162 for (
size_t k = 0;
k < N; ++
k) {
166 if (bounds.back() > times.back()) {
173 forcing_t0 = bounds.front();
174 forcing_t1 = bounds.back();
180 "m_impl->times have to be strictly increasing (this is a bug)");
192 bool extrapolate = ctx.
config()->get_flag(
"input.forcing.time_extrapolation");
194 if (not (extrapolate or periodic)) {
200 long_name.c_str(), variable_name.c_str(), filename.c_str());
206 const std::string &variable_name,
const std::string &units,
207 const std::string &output_units,
const std::string &long_name)
215 auto config = ctx.
config();
217 auto filename = config->get_string(prefix +
".file");
218 bool periodic = config->get_flag(prefix +
".periodic");
220 if (filename.empty()) {
222 "%s.file is required", prefix.c_str());
225 initialize(ctx, filename, variable_name, units, output_units,
226 long_name, periodic);
230 const std::string &filename,
231 const std::string &variable_name,
232 const std::string &units,
233 const std::string &output_units,
234 const std::string &long_name,
243 initialize(ctx, filename, variable_name, units, output_units,
244 long_name, periodic);
276 if (T < m_impl->times.front()) {
311 return integral(a, t1) + v1 * (b - t1);
326 return 0.5 * (v_a + v_b) * dt;
334 for (
size_t k = ai + 1;
k < bi; ++
k) {
364 double N = std::floor((a - t0) / P);
365 double M = std::floor((b - t0) / P);
366 double delta = a - t0 - P * N;
367 double gamma = b - t0 - P * M;
369 double N_periods = M - (N + 1);
371 if (N_periods >= 0.0) {
372 return (
integral(t0 + delta, t0 + P) +
377 return integral(t0 + delta, t0 + gamma) / dt;
std::shared_ptr< const Config > config() const
std::shared_ptr< const Logger > log() const
std::shared_ptr< units::System > unit_system() const
std::shared_ptr< const Time > time() const
std::vector< std::string > dimensions(const std::string &variable_name) const
High-level PISM I/O class.
void message(int threshold, const char format[],...) const __attribute__((format(printf
Print a message to the log.
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
double average(double t, double dt) const
double value(double t) const
void initialize(const Context &ctx, const std::string &filename, const std::string &variable_name, const std::string &units, const std::string &output_units, const std::string &long_name, bool periodic)
ScalarForcing(const Context &ctx, const std::string &option_prefix, const std::string &variable_name, const std::string &units, const std::string &output_units, const std::string &long_name)
double integral(double a, double b) const
std::shared_ptr< System > Ptr
#define PISM_ERROR_LOCATION
double max(const array::Scalar &input)
Finds maximum over all the values in an array::Scalar object. Ignores ghosts.
double min(const array::Scalar &input)
Finds minimum over all the values in an array::Scalar object. Ignores ghosts.
@ PISM_READONLY
open an existing file for reading only
void read_timeseries(const File &file, const VariableMetadata &metadata, const Logger &log, std::vector< double > &data)
Read a time-series variable from a NetCDF file to a vector of doubles.
void read_time_info(const Logger &log, std::shared_ptr< units::System > unit_system, const File &file, const std::string &time_name, const std::string &time_units, std::vector< double > ×, std::vector< double > &bounds)
bool is_increasing(const std::vector< double > &a)
Checks if a vector of doubles is strictly increasing.
static void report_range(const std::vector< double > &data, const units::System::Ptr &unit_system, const VariableMetadata &metadata, const Logger &log)
Report the range of a time-series stored in data.
void check_forcing_duration(const Time &time, double forcing_start, double forcing_end)
std::vector< double > times
std::vector< double > values