24#include "pism/util/array/Forcing.hh"
25#include "pism/util/io/File.hh"
26#include "pism/util/pism_utilities.hh"
27#include "pism/util/Time.hh"
28#include "pism/util/Grid.hh"
29#include "pism/util/ConfigInterface.hh"
31#include "pism/util/error_handling.hh"
32#include "pism/util/io/io_helpers.hh"
33#include "pism/util/Logger.hh"
34#include "pism/util/Interpolation1D.hh"
35#include "pism/util/Context.hh"
36#include "pism/util/array/Array_impl.hh"
37#include "pism/util/VariableMetadata.hh"
38#include "pism/util/io/IO_Flags.hh"
39#include "pism/util/InputInterpolation.hh"
63 std::shared_ptr<petsc::DM>
da;
85 std::shared_ptr<Interpolation1D>
interp;
115 const std::string &short_name,
116 const std::string &standard_name,
117 unsigned int max_buffer_size,
120 : array::
Scalar(grid, short_name, 0),
123 unsigned int n_records = file.
nrecords(short_name, standard_name,
124 grid->ctx()->unit_system());
131 if (interpolation_type ==
LINEAR) {
137 buffer_size = std::min(n_records, max_buffer_size);
149 const std::string &short_name,
152 std::shared_ptr<Forcing> result(
new Forcing(
grid, short_name, 1,
157 result->set_record(0);
160 result->m_data->time = {0.0};
161 result->m_data->n_records = 1;
162 result->m_data->first = 0;
165 double eps = 0.5 * result->m_data->dt_min;
166 result->m_data->time_range = {-eps, eps};
172 unsigned int buffer_size,
174 : array::
Scalar(grid, short_name, 0),
190 m_data->
dt_min = config->get_number(
"time_stepping.resolution");
202 PISM_CHK(ierr,
"DMCreateGlobalVector");
220 PISM_CHK(ierr,
"DMDAVecGetArrayDOF");
233 PISM_CHK(ierr,
"DMDAVecRestoreArrayDOF");
241 auto time = ctx->time();
248 if (not var.exists) {
257 if (not one_record) {
258 std::vector<double> times{};
259 std::vector<double> bounds{};
260 io::read_time_info(ctx->unit_system(), file, time_name, time->units_string(), times, bounds);
270 for (
unsigned int k = 0;
k < times.size(); ++
k) {
271 times[
k] = bounds[2*
k + 0];
278 bool extrapolate = ctx->config()->get_flag(
"input.forcing.time_extrapolation");
279 if (not (extrapolate or periodic)) {
318 auto ctx =
grid()->ctx();
328 "the buffer is too small to contain periodic data");
336 auto V = file.
find_variable(variable.get_name(), variable[
"standard_name"]);
340 for (
unsigned int j = 0; j < n_records; ++j) {
344 auto time = ctx->time();
345 auto log = ctx->log();
346 log->message(5,
" %s: reading entry #%02d, time %s...\n", name.c_str(), j,
369 alpha = dt1 + dt2 > 0 ? dt2 / (dt1 + dt2) : 0.0;
374 int last = buffer_required - 2;
379 double **a2 =
array();
381 for (
auto p =
grid()->points(); p; p.next()) {
382 const int i = p.i(), j = p.j();
384 a2[j][i] = (1.0 - alpha) * a3[j][i][last] + alpha * a3[j][i][first];
403 const double dt = 1.0;
417 const double dt = 1.0;
455 if (t >= t0 and t + dt <= t1) {
462 unsigned int first = I.
left(0), last = I.
right(1), N = last - first + 1;
468 "cannot read %d records of %s (buffer size: %d)", N,
480 if (start >= time_size) {
482 "Forcing::update(int start): start = %d is invalid", start);
485 unsigned int missing = std::min(
buffer_size(), time_size - start);
487 if (start ==
static_cast<unsigned int>(
m_data->
first)) {
497 kept = last - start + 1;
520 " reading \"%s\" into buffer\n"
521 " (short_name = %s): %d records, time %s through %s...\n",
524 t->date(
m_data->
time[start + missing - 1]).c_str());
532 auto V = file.
find_variable(variable.get_name(), variable[
"standard_name"]);
536 for (
unsigned int j = 0; j < missing; ++j) {
537 interp->regrid(variable, file, (
int)(start + j), *
grid(),
vec());
539 log->message(5,
" %s: reading entry #%02d, year %s...\n",
m_impl->
name.c_str(), start + j,
562 for (
auto p =
m_impl->
grid->points(); p; p.next()) {
563 const int i = p.i(), j = p.j();
566 a3[j][i][
k] = a3[j][i][
k + number];
576 double **a2 =
array();
578 for (
auto p =
m_impl->
grid->points(); p; p.next()) {
579 const int i = p.i(), j = p.j();
580 a3[j][i][
n] = a2[j][i];
602 size_t L = gsl_interp_bsearch(
m_data->
time.data(), t, 0, time_size - 1);
607 if (R >= time_size - 1) {
614 R = std::min(R + 1, time_size - 1);
642 double **a2 =
array();
644 for (
auto p =
m_impl->
grid->points(); p; p.next()) {
645 const int i = p.i(), j = p.j();
646 auto *column = a3[j][i];
648 a2[j][i] = column[
L] + alpha * (column[R] - column[
L]);
674 std::map<size_t, double> weights{};
687 double N_periods = 0.0;
691 double N = std::floor((a - t0) / P);
692 double M = std::floor((b - t0) / P);
694 N_periods = M - (N + 1);
695 delta = (a - t0) - P * N;
696 gamma = (b - t0) - P * M;
699 if (N_periods >= 0.0) {
700 assert(t0 + delta < t0 + P);
703 std::map<size_t, double> W2{};
711 std::map<size_t, double> W3{};
721 for (
const auto &w : W2) {
722 weights[w.first] += N_periods * w.second;
725 for (
const auto &w : W3) {
726 weights[w.first] += w.second;
729 assert(t0 + delta < t0 + gamma);
738 double **a2 =
array();
741 for (
auto p =
m_impl->
grid->points(); p; p.next()) {
742 const int i = p.i(), j = p.j();
745 for (
const auto &weight : weights) {
746 size_t k = weight.first;
747 double w = weight.second;
748 a2[j][i] += w * a3[j][i][
k];
766 std::vector<double> times_requested(ts.size());
771 for (
unsigned int k = 0;
k < ts.size(); ++
k) {
772 double t = ts[
k] - T0;
774 t -= std::floor(t / P) * P;
776 times_requested[
k] = T0 + t;
779 times_requested = ts;
785 times_requested.data(),
786 times_requested.size()));
VariableLookupData find_variable(const std::string &short_name, const std::string &std_name) const
Find a variable using its standard name and/or short name.
unsigned int nrecords() const
Get the number of records. Uses the length of an unlimited dimension.
unsigned int dimension_length(const std::string &name) const
Get the length of a dimension.
High-level PISM I/O class.
const std::vector< int > & right() const
const std::vector< int > & left() const
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
virtual void begin_access() const =0
virtual void end_access() const =0
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
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
const std::string & get_name() const
Get the name of an Array object.
std::shared_ptr< const Grid > grid() const
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
MaxTimestep max_timestep(double t) const
Given the time t determines the maximum possible time-step this Forcing allows.
void begin_access() const
Checks if an Array is allocated and calls DAVecGetArray.
void average(double t, double dt)
void discard(int N)
Discard the first N records, shifting the rest of them towards the "beginning".
void init_periodic_data(const File &file)
void set_record(int n)
Sets the record number n to the contents of the (internal) Vec v.
void init(const std::string &filename, bool periodic)
void allocate(unsigned int buffer_size, InterpolationType interpolation_type)
void end_access() const
Checks if an Array is allocated and calls DAVecRestoreArray.
Forcing(std::shared_ptr< const Grid > grid, const File &file, const std::string &short_name, const std::string &standard_name, unsigned int max_buffer_size, bool periodic, InterpolationType interpolation_type=PIECEWISE_CONSTANT)
void init_interpolation(const std::vector< double > &ts)
Compute weights for the piecewise-constant interpolation. This is used both for time-series and "snap...
static std::shared_ptr< Forcing > Constant(std::shared_ptr< const Grid > grid, const std::string &short_name, double value)
void update(double t, double dt)
Read some data to make sure that the interval (t, t + dt) is covered.
unsigned int buffer_size() const
2D time-dependent inputs (for climate forcing, etc)
#define PISM_CHK(errcode, name)
#define PISM_ERROR_LOCATION
@ PISM_READONLY
open an existing file for reading only
void read_time_info(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)
std::string time_dimension(units::System::Ptr unit_system, const File &file, const std::string &variable_name)
std::map< size_t, double > integration_weights(const double *x, size_t x_size, InterpolationType type, double a, double b)
void check_forcing_duration(const Time &time, double forcing_start, double forcing_end)
std::shared_ptr< const Grid > grid
The computational grid.
InterpolationType interpolation_type
bool report_range
If true, report range when regridding.
unsigned int da_stencil_width
stencil width supported by the DA
std::vector< SpatialVariableMetadata > metadata
Metadata (NetCDF variable attributes)
double period_start
start of the period, in seconds
unsigned int n_records
number of records currently kept in memory
std::vector< double > time
all the times available in filename
std::string filename
name of the file to read (regrid) from
double period
forcing period, in seconds
InterpolationType interp_type
temporal interpolation type
double dt_min
minimum time step length in max_timestep(), in seconds
std::array< double, 2 > time_range
the range of times covered by data in filename
std::shared_ptr< Interpolation1D > interp
temporal interpolation code
unsigned int buffer_size
maximum number of records stored in memory
std::shared_ptr< petsc::DM > da
DM with dof equal to buffer_size.
petsc::Vec v
a 3D Vec used to store records
double *** array
pointer used to access records stored in memory