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/interpolation.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"
62 std::shared_ptr<petsc::DM>
da;
84 std::shared_ptr<Interpolation>
interp;
114 const std::string &short_name,
115 const std::string &standard_name,
116 unsigned int max_buffer_size,
119 : array::
Scalar(grid, short_name, 0),
122 unsigned int n_records = file.
nrecords(short_name, standard_name,
123 grid->ctx()->unit_system());
130 if (interpolation_type ==
LINEAR) {
148 const std::string &short_name,
151 std::shared_ptr<Forcing> result(
new Forcing(
grid, short_name, 1,
156 result->set_record(0);
159 result->m_data->time = {0.0};
160 result->m_data->n_records = 1;
161 result->m_data->first = 0;
164 double eps = 0.5 * result->m_data->dt_min;
165 result->m_data->time_range = {-eps, eps};
171 unsigned int buffer_size,
173 : array::
Scalar(grid, short_name, 0),
186 m_data->
dt_min = config->get_number(
"time_stepping.resolution");
198 PISM_CHK(ierr,
"DMCreateGlobalVector");
216 PISM_CHK(ierr,
"DMDAVecGetArrayDOF");
229 PISM_CHK(ierr,
"DMDAVecRestoreArrayDOF");
237 auto time = ctx->time();
244 if (not var.exists) {
253 if (not one_record) {
254 std::vector<double> times{};
255 std::vector<double> bounds{};
257 file, time_name, time->units_string(),
268 for (
unsigned int k = 0;
k < times.size(); ++
k) {
269 times[
k] = bounds[2*
k + 0];
276 bool extrapolate = ctx->config()->get_flag(
"input.forcing.time_extrapolation");
277 if (not (extrapolate or periodic)) {
316 auto ctx =
grid()->ctx();
326 "the buffer is too small to contain periodic data");
334 auto V = file.
find_variable(variable.get_name(), variable[
"standard_name"]);
340 for (
unsigned int j = 0; j < n_records; ++j) {
349 auto time = ctx->time();
350 auto log = ctx->log();
351 log->message(5,
" %s: reading entry #%02d, time %s...\n", name.c_str(), j,
374 alpha = dt1 + dt2 > 0 ? dt2 / (dt1 + dt2) : 0.0;
379 int last = buffer_required - 2;
384 double **a2 =
array();
386 for (
auto p =
grid()->points(); p; p.next()) {
387 const int i = p.i(), j = p.j();
389 a2[j][i] = (1.0 - alpha) * a3[j][i][last] + alpha * a3[j][i][first];
408 const double dt = 1.0;
422 const double dt = 1.0;
460 if (t >= t0 and t + dt <= t1) {
467 unsigned int first =
I.left(0), last =
I.right(1), N = last - first + 1;
473 "cannot read %d records of %s (buffer size: %d)", N,
483 unsigned int time_size = (int)
m_data->
time.size();
485 if (start >= time_size) {
487 "Forcing::update(int start): start = %d is invalid", start);
492 if (start ==
static_cast<unsigned int>(
m_data->
first)) {
502 kept = last - start + 1;
525 " reading \"%s\" into buffer\n"
526 " (short_name = %s): %d records, time %s through %s...\n",
529 t->date(
m_data->
time[start + missing - 1]).c_str());
540 auto V = file.
find_variable(variable.get_name(), variable[
"standard_name"]);
545 for (
unsigned int j = 0; j < missing; ++j) {
552 log->message(5,
" %s: reading entry #%02d, year %s...\n",
m_impl->
name.c_str(), start + j,
575 for (
auto p =
m_impl->
grid->points(); p; p.next()) {
576 const int i = p.i(), j = p.j();
579 a3[j][i][
k] = a3[j][i][
k + number];
589 double **a2 =
array();
591 for (
auto p =
m_impl->
grid->points(); p; p.next()) {
592 const int i = p.i(), j = p.j();
593 a3[j][i][
n] = a2[j][i];
615 size_t L = gsl_interp_bsearch(
m_data->
time.data(), t, 0, time_size - 1);
620 if (R >= time_size - 1) {
655 double **a2 =
array();
657 for (
auto p =
m_impl->
grid->points(); p; p.next()) {
658 const int i = p.i(), j = p.j();
687 std::map<size_t, double> weights{};
700 double N_periods = 0.0;
704 double N = std::floor((a - t0) / P);
705 double M = std::floor((b - t0) / P);
707 N_periods = M - (N + 1);
708 delta = (a - t0) - P * N;
709 gamma = (b - t0) - P * M;
712 if (N_periods >= 0.0) {
713 assert(t0 + delta < t0 + P);
716 std::map<size_t, double> W2{};
724 std::map<size_t, double> W3{};
734 for (
const auto &w : W2) {
735 weights[w.first] += N_periods * w.second;
738 for (
const auto &w : W3) {
739 weights[w.first] += w.second;
742 assert(t0 + delta < t0 + gamma);
751 double **a2 =
array();
754 for (
auto p =
m_impl->
grid->points(); p; p.next()) {
755 const int i = p.i(), j = p.j();
758 for (
const auto &
weight : weights) {
761 a2[j][i] += w * a3[j][i][
k];
779 std::vector<double> times_requested(ts.size());
784 for (
unsigned int k = 0;
k < ts.size(); ++
k) {
785 double t = ts[
k] - T0;
787 t -= std::floor(t / P) * P;
789 times_requested[
k] = T0 + t;
792 times_requested = ts;
798 times_requested.data(),
799 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.
std::array< int, 4 > count
std::array< int, 4 > start
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
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.
virtual void end_access() const
Checks if an Array is allocated and calls DAVecRestoreArray.
virtual void begin_access() const
Checks if an Array is allocated and calls DAVecGetArray.
const std::vector< double > & levels() const
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)
unsigned int buffer_size()
void update(double t, double dt)
Read some data to make sure that the interval (t, t + dt) is covered.
Wrapper around VecGetArray and VecRestoreArray.
#define PISM_CHK(errcode, name)
#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.
static Vector3 column(const double A[3][3], size_t k)
void regrid_spatial_variable(SpatialVariableMetadata &variable, const Grid &internal_grid, const LocalInterpCtx &lic, const File &file, double *output)
Regrid from a NetCDF file into a distributed array output.
@ PISM_READONLY
open an existing file for reading only
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)
std::string time_dimension(units::System::Ptr unit_system, const File &file, const std::string &variable_name)
static int weight(int M_ij, int M_n, double h_ij, double h_n)
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
unsigned int buffer_size
maximum number of records stored in memory
std::shared_ptr< Interpolation > interp
temporal interpolation code
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