28#include "pism/util/ConfigInterface.hh"
29#include "pism/util/Context.hh"
30#include "pism/util/Grid.hh"
31#include "pism/util/Logger.hh"
32#include "pism/util/Profiling.hh"
33#include "pism/util/Time.hh"
34#include "pism/util/VariableMetadata.hh"
35#include "pism/util/error_handling.hh"
36#include "pism/util/Interpolation1D.hh"
37#include "pism/util/io/File.hh"
38#include "pism/util/io/IO_Flags.hh"
39#include "pism/util/io/LocalInterpCtx.hh"
40#include "pism/util/io/io_helpers.hh"
41#include "pism/util/pism_utilities.hh"
42#include "pism/util/projection.hh"
64 double *output_array) {
68 unsigned int nlevels = lic.
z->n_output();
71 auto input = [input_array, x_count, z_count](
int X,
int Y,
int Z) {
73 int index = (Y * x_count + X) * z_count + Z;
74 return input_array[index];
77 for (
auto p = grid.points(); p; p.next()) {
78 const int i_global = p.i(), j_global = p.j();
80 const int i = i_global - grid.xs(), j = j_global - grid.ys();
83 const int X_m = lic.
x->left(i), X_p = lic.
x->right(i);
84 const int Y_m = lic.
y->left(j), Y_p = lic.
y->right(j);
86 for (
unsigned int k = 0;
k < nlevels;
k++) {
88 double a_mm = 0.0, a_mp = 0.0, a_pm = 0.0, a_pp = 0.0;
91 const int Z_m = lic.
z->left(
k), Z_p = lic.
z->right(
k);
93 const double alpha_z = lic.
z->alpha(
k);
99 mmm = input(X_m, Y_m, Z_m),
100 mmp = input(X_m, Y_m, Z_p),
101 pmm = input(X_p, Y_m, Z_m),
102 pmp = input(X_p, Y_m, Z_p),
103 mpm = input(X_m, Y_p, Z_m),
104 mpp = input(X_m, Y_p, Z_p),
105 ppm = input(X_p, Y_p, Z_m),
106 ppp = input(X_p, Y_p, Z_p);
109 a_mm = mmm * (1.0 - alpha_z) + mmp * alpha_z;
110 a_mp = pmm * (1.0 - alpha_z) + pmp * alpha_z;
111 a_pm = mpm * (1.0 - alpha_z) + mpp * alpha_z;
112 a_pp = ppm * (1.0 - alpha_z) + ppp * alpha_z;
115 a_mm = input(X_m, Y_m, 0);
116 a_mp = input(X_p, Y_m, 0);
117 a_pm = input(X_m, Y_p, 0);
118 a_pp = input(X_p, Y_p, 0);
122 const double x_alpha = lic.
x->alpha(i);
124 const double y_alpha = lic.
y->alpha(j);
127 const double a_m = a_mm * (1.0 - x_alpha) + a_mp * x_alpha;
128 const double a_p = a_pm * (1.0 - x_alpha) + a_pp * x_alpha;
130 int index = (j * grid.xm() + i) * nlevels +
k;
133 output_array[index] = a_m * (1.0 - y_alpha) + a_p * y_alpha;
152 const std::array<int, 4> &start,
153 const std::array<int, 4> &
count) {
154 auto ndims = dim_types.size();
158 result.
start.resize(ndims);
159 result.
count.resize(ndims);
162 for (
unsigned int j = 0; j < ndims; j++) {
163 switch (dim_types[j]) {
195 std::string name = metadata.
get_name();
204 e.
add_context(
"defining dimension '%s' in '%s'", name.c_str(), file.
name().c_str());
232 time[
"long_name"] =
"time";
234 time[
"units"] = units;
239 e.
add_context(
"defining the time dimension in \"" + file.
name() +
"\"");
256 e.
add_context(
"appending to the time dimension in \"" + file.
name() +
"\"");
281 if (not z_name.empty()) {
283 const std::vector<double> &levels = var.
levels();
285 unsigned int nlevels = std::max(levels.size(), (
size_t)1);
288 bool spatial_dim = not var.
z().
get_string(
"axis").empty();
290 if (nlevels > 1 and spatial_dim) {
291 double dz_max = levels[1] - levels[0];
292 double dz_min = levels.back() - levels.front();
294 for (
unsigned int k = 0;
k < nlevels - 1; ++
k) {
295 double dz = levels[
k + 1] - levels[
k];
296 dz_max = std::max(dz_max, dz);
297 dz_min = std::min(dz_min, dz);
308 const std::vector<double> &data) {
346 std::vector<AxisType> storage, memory = {
Y_AXIS,
X_AXIS };
351 if (first && dimtype ==
T_AXIS) {
359 storage.push_back(dimtype);
360 }
else if (dimtype ==
Z_AXIS) {
361 memory.push_back(dimtype);
363 storage.push_back(dimtype);
371 assert(memory.size() <= 3);
373 return storage != memory;
377 std::shared_ptr<units::System> unit_system) {
378 std::vector<AxisType> result;
379 for (
const auto &dimension : file.
dimensions(var_name)) {
398static void transpose(
const double *input,
const std::vector<AxisType> &input_axes,
399 const std::array<int, 4> &
count,
double *output) {
403 std::vector<unsigned> delta = {1, 1, 1, 1};
405 int N = (
int)input_axes.size();
408 std::vector<unsigned> tmp(N, 1);
409 for (
int k = 0;
k < N; ++
k) {
410 for (
int n =
k + 1;
n < N; ++
n) {
411 tmp[
k] *=
count[input_axes[
n]];
415 for (
int k = 0;
k < N; ++
k) {
416 delta[input_axes[
k]] = tmp[
k];
429 auto OUT = x * delta_x + y * delta_y + z * 1;
432 output[OUT] = input[IN];
398static void transpose(
const double *input,
const std::vector<AxisType> &input_axes, {
…}
443 double tolerance,
const double *buffer,
size_t buffer_length) {
445 if (attribute.size() == 1) {
446 double fill_value = attribute[0];
448 for (
size_t k = 0;
k < buffer_length; ++
k) {
449 if (fabs(buffer[
k] - fill_value) < tolerance) {
452 "Variable '%s' in '%s' contains values matching the _FillValue attribute",
453 variable_name.c_str(), file.
name().c_str());
455 if (not std::isfinite(buffer[
k])) {
458 "Variable '%s' in '%s' contains values that are not finite (NaN or infinity)",
459 variable_name.c_str(), file.
name().c_str());
467 std::shared_ptr<units::System> unit_system,
468 const std::array<int,4> &start,
469 const std::array<int,4> &
count,
479 std::vector<double> tmp(size);
480 file.
read_variable(variable_name, sc.start, sc.count, tmp.data());
483 file.
read_variable(variable_name, sc.start, sc.count, output);
490 e.
add_context(
"reading variable '%s' from '%s'", variable_name.c_str(), file.
name().c_str());
498 auto config = grid.ctx()->config();
503 if (config->get_flag(
"output.use_MKS")) {
507 std::vector<std::string> dims;
519 dims.push_back(config->get_string(
"time.dimension_name"));
529 assert(dims.size() > 1);
553 std::string internal_units = variable[
"units"];
554 if (input_units.empty() and not internal_units.empty()) {
556 "PISM WARNING: Variable '%s' ('%s') does not have the units attribute.\n"
557 " Assuming that it is in '%s'.\n",
559 internal_units.c_str());
560 return internal_units;
570 const File &file,
unsigned int time,
double *output) {
572 const Logger &log = *grid.ctx()->log();
577 if (not var.exists) {
580 variable.
get_string(
"standard_name").c_str(), file.
name().c_str());
592 int input_spatial_dim_count = 0;
593 size_t matching_dim_count = 0;
596 for (
const auto &d : input_dims) {
600 ++input_spatial_dim_count;
603 if (axes.find(dim_type) != axes.end()) {
604 ++matching_dim_count;
608 if (axes.size() != matching_dim_count) {
613 "found the %dD variable %s (%s) in '%s' while trying to read\n"
614 "'%s' ('%s'), which is %d-dimensional.",
615 input_spatial_dim_count, var.name.c_str(),
join(input_dims,
",").c_str(),
617 variable.
get_string(
"long_name").c_str(),
static_cast<int>(axes.size()));
622 size_t nlevels = std::max(variable.
levels().size(), (
size_t)1);
625 {(int)time, grid.xs(), grid.ys(), 0},
626 {1, grid.xm(), grid.ym(), (int)nlevels},
630 const std::string &internal_units = variable[
"units"];
632 input_units =
check_units(variable, input_units, log);
635 size_t size = grid.xm() * grid.ym() * nlevels;
646 const File &file,
const double *input) {
647 auto config = grid.ctx()->config();
652 if (config->get_flag(
"output.use_MKS")) {
660 file.
name().c_str());
670 if (written and time_independent) {
675 unsigned int nlevels = std::max(var.
levels().size(), (
size_t)1);
677 std::string units = var[
"units"], output_units = var[
"output_units"];
679 if (units != output_units) {
680 size_t data_size = grid.xm() * grid.ym() * nlevels;
684 std::vector<double> tmp(data_size);
685 for (
size_t k = 0;
k < data_size; ++
k) {
705 const std::vector<double> &z_internal) {
713 const double x_min = internal.
x0() - internal.
Lx(), x_max = internal.
x0() + internal.
Lx(),
714 y_min = internal.
y0() - internal.
Ly(), y_max = internal.
y0() + internal.
Ly(),
715 input_x_min = input.
x0 - input.
Lx, input_x_max = input.
x0 + input.
Lx,
716 input_y_min = input.
y0 - input.
Ly, input_y_max = input.
y0 + input.
Ly;
722 if (not(x_min >= input_x_min - eps and x_max <= input_x_max + eps and
723 y_min >= input_y_min - eps and y_max <= input_y_max + eps)) {
726 "PISM's computational domain is not a subset of the domain in '%s'\n"
727 "PISM grid: x: [%3.3f, %3.3f] y: [%3.3f, %3.3f] meters\n"
728 "input file grid: x: [%3.3f, %3.3f] y: [%3.3f, %3.3f] meters",
729 input.
filename.c_str(), x_min, x_max, y_min, y_max, input_x_min, input_x_max, input_y_min,
733 if (z_internal.empty()) {
735 "Internal vertical grid has 0 levels. This should never happen.");
738 if (z_internal.size() == 1 and input.
z.size() > 1) {
742 "trying to read in a 2D field but the input file %s contains\n"
743 "a 3D field with %d levels",
744 input.
filename.c_str(),
static_cast<int>(input.
z.size()));
747 if (z_internal.size() > 1 and input.
z.size() <= 1) {
751 "trying to read in a 3D field but the input file %s contains\n"
756 if (z_internal.size() > 1 and (not input.
z.empty())) {
759 const double input_z_min = input.
z.front(), input_z_max = input.
z.back(),
760 z_min = z_internal.front(), z_max = z_internal.back();
762 if (not(z_min >= input.
z_min - eps and z_max <= input.
z_max + eps)) {
765 "PISM's computational domain is not a subset of the domain in '%s'\n"
766 "PISM grid: z: [%3.3f, %3.3f] meters\n"
767 "input file grid: z: [%3.3f, %3.3f] meters",
768 input.
filename.c_str(), z_min, z_max, input_z_min, input_z_max);
775 const Grid& internal_grid,
776 const std::vector<double> &internal_z_levels) {
779 "input x coordinate has to be strictly increasing");
784 "input y coordinate has to be strictly increasing");
789 "input vertical grid has to be strictly increasing");
792 bool allow_extrapolation = internal_grid.
ctx()->config()->get_flag(
"grid.allow_extrapolation");
794 if (not allow_extrapolation) {
811 const Grid &target_grid,
817 const Profiling &profiling = target_grid.
ctx()->profiling();
819 profiling.
begin(
"io.regridding.read");
820 std::vector<double> buffer(interp_context.
buffer_size());
822 interp_context.
count, buffer.data());
823 profiling.
end(
"io.regridding.read");
826 profiling.
begin(
"io.regridding.interpolate");
827 interpolate(target_grid, interp_context, buffer.data(), output);
828 profiling.
end(
"io.regridding.interpolate");
833 std::string internal_units = variable[
"units"];
835 input_units =
check_units(variable, input_units, *target_grid.
ctx()->log());
837 const size_t data_size = target_grid.
xm() * target_grid.
ym() * interp_context.
z->n_output();
868 const std::string &units,
869 std::shared_ptr<units::System> unit_system) {
878 if (dims.size() != 1) {
880 "variable '%s' in '%s' should to have 1 dimension (got %d)",
881 variable_name.c_str(), file.
name().c_str(), (
int)dims.size());
884 const auto &dimension_name = dims[0];
891 units::Unit internal_units(unit_system, units), input_units(unit_system,
"1");
895 if (not input_units_string.empty()) {
896 input_units =
units::Unit(unit_system, input_units_string);
900 "variable '%s' does not have the units attribute", variable_name.c_str());
903 std::vector<double> result(length);
905 file.
read_variable(variable_name, { 0 }, { length }, result.data());
911 e.
add_context(
"reading 1D variable '%s' from '%s'", variable_name.c_str(),
912 file.
name().c_str());
922 const std::vector<double> &data) {
924 std::string name = metadata.
get_name();
931 std::vector<double> tmp = data;
940 e.
add_context(
"writing time-series variable '%s' to '%s'", name.c_str(),
941 file.
name().c_str());
947 const std::string &dimension_name,
948 const std::string &bounds_name,
969std::vector<double>
read_bounds(
const File &file,
const std::string &bounds_variable_name,
970 const std::string &internal_units,
971 std::shared_ptr<units::System> unit_system) {
981 auto dims = file.
dimensions(bounds_variable_name);
983 if (dims.size() != 2) {
987 const auto &dimension_name = dims[0];
988 const auto &bounds_dimension_name = dims[1];
994 "time-bounds variable " + bounds_variable_name +
" has to have exactly 2 bounds per time record");
1008 "coordinate variable " + dimension_name +
" is missing");
1014 if (input_units_string.empty()) {
1016 "variable '%s' does not have the units attribute",
1017 dimension_name.c_str());
1020 input_units =
units::Unit(unit_system, input_units_string);
1023 std::vector<double> result(length * 2);
1025 file.
read_variable(bounds_variable_name, {0, 0}, {(unsigned)length, 2}, result.data());
1031 e.
add_context(
"reading bounds variable '%s' from '%s'", bounds_variable_name.c_str(),
1032 file.
name().c_str());
969std::vector<double>
read_bounds(
const File &file,
const std::string &bounds_variable_name, {
…}
1038 size_t t_start,
const std::vector<double> &data) {
1045 if (not variable_exists) {
1051 std::vector<double> tmp = data;
1058 {(
unsigned int)t_start, 0},
1059 {(
unsigned int)tmp.size() / 2, 2},
1063 e.
add_context(
"writing time-bounds variable '%s' to '%s'", name.c_str(),
1064 file.
name().c_str());
1073 const std::string &time_name,
const std::string &time_units,
1074 std::vector<double> ×, std::vector<double> &bounds) {
1090 if (time_bounds_name.empty()) {
1095 bounds =
io::read_bounds(file, time_bounds_name, time_units, unit_system);
1097 if (2 * N != bounds.size()) {
1099 "each time record has to have 2 bounds");
1102 for (
size_t k = 0;
k < N; ++
k) {
1103 if (not (times[
k] >= bounds[2 *
k + 0] and
1104 times[
k] <= bounds[2 *
k + 1])) {
1106 "each time has to be contained in its time interval");
1113 int file_exists_flag = 0, rank = 0;
1114 MPI_Comm_rank(com, &rank);
1118 if (FILE *f = fopen(filename.c_str(),
"r")) {
1119 file_exists_flag = 1;
1122 file_exists_flag = 0;
1125 MPI_Bcast(&file_exists_flag, 1, MPI_INT, 0, com);
1127 return file_exists_flag == 1;
1131 const std::string &variable_name,
1132 std::shared_ptr<units::System> unit_system) {
1142 unsigned int nattrs = file.
nattributes(variable_name);
1144 for (
unsigned int j = 0; j < nattrs; ++j) {
1145 std::string attribute_name = file.
attribute_name(variable_name, j);
1157 e.
add_context(
"reading attributes of variable '%s' from '%s'",
1158 variable_name.c_str(), file.
name().c_str());
1172 std::string var_name = variable.
get_name();
1176 units = variable[
"units"],
1177 output_units = variable[
"output_units"];
1179 bool use_output_units = units != output_units;
1183 file.
write_attribute(var_name,
"units", use_output_units ? output_units : units);
1186 std::vector<double> bounds(2);
1191 bounds[0] = variable.
get_number(
"valid_min");
1194 bounds[1] = variable.
get_number(
"valid_max");
1198 double fill_value = 0.0;
1200 fill_value = variable.
get_number(
"_FillValue");
1205 if (use_output_units) {
1209 bounds[0] = c(bounds[0]);
1210 bounds[1] = c(bounds[1]);
1211 fill_value = c(fill_value);
1235 if (name ==
"units" or
1236 name ==
"output_units" or
1246 std::string name = d.first;
1247 std::vector<double> values = d.second;
1249 if (
member(name, {
"valid_min",
"valid_max",
"valid_range",
"_FillValue"}) or
1258 e.
add_context(
"writing attributes of variable '%s' to '%s'",
1259 var_name.c_str(), file.
name().c_str());
1271 const std::string &variable_name) {
1275 for (
const auto &d : dims) {
1289 int stat = 0, rank = 0;
1290 MPI_Comm_rank(com, &rank);
1291 std::string backup_filename = file_to_move +
"~";
1293 if (rank == rank_to_use) {
1294 bool exists =
false;
1297 if (FILE *f = fopen(file_to_move.c_str(),
"r")) {
1305 stat = rename(file_to_move.c_str(), backup_filename.c_str());
1309 int global_stat = 0;
1310 MPI_Allreduce(&stat, &global_stat, 1, MPI_INT, MPI_SUM, com);
1312 if (global_stat != 0) {
1314 "PISM ERROR: can't move '%s' to '%s'",
1315 file_to_move.c_str(), backup_filename.c_str());
1324 int stat = 0, rank = 0;
1325 MPI_Comm_rank(com, &rank);
1327 if (rank == rank_to_use) {
1328 bool exists =
false;
1331 if (FILE *f = fopen(file_to_remove.c_str(),
"r")) {
1339 stat = remove(file_to_remove.c_str());
1343 int global_stat = 0;
1344 MPI_Allreduce(&stat, &global_stat, 1, MPI_INT, MPI_SUM, com);
1346 if (global_stat != 0) {
1348 "PISM ERROR: can't remove '%s'", file_to_remove.c_str());
std::string get_string(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
A class for storing and accessing PISM configuration flags and parameters.
std::shared_ptr< const Config > config() const
std::shared_ptr< units::System > unit_system() const
std::shared_ptr< const Time > time() const
bool dimension_exists(const std::string &name) const
Checks if a dimension exists.
void write_distributed_array(const std::string &variable_name, const Grid &grid, unsigned int z_count, bool time_dependent, const double *input) const
void read_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, double *ip) const
void define_dimension(const std::string &name, size_t length) const
std::string attribute_name(const std::string &var_name, unsigned int n) const
AxisType dimension_type(const std::string &name, units::System::Ptr unit_system) const
Get the "type" of a dimension.
void set_variable_was_written(const std::string &name) const
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.
bool variable_exists(const std::string &short_name) const
Checks if a variable exists.
void write_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const double *op) const
void define_variable(const std::string &name, io::Type nctype, const std::vector< std::string > &dims) const
Define a variable.
io::Type attribute_type(const std::string &var_name, const std::string &att_name) const
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.
std::vector< double > read_double_attribute(const std::string &var_name, const std::string &att_name) const
Get a double attribute.
bool get_variable_was_written(const std::string &name) const
unsigned int nattributes(const std::string &var_name) const
unsigned int dimension_length(const std::string &name) const
Get the length of a dimension.
std::vector< std::string > dimensions(const std::string &variable_name) const
std::string read_text_attribute(const std::string &var_name, const std::string &att_name) const
Get a text attribute.
High-level PISM I/O class.
double y0() const
Y-coordinate of the center of the domain.
double Ly() const
Half-width of the computational domain.
double Lx() const
Half-width of the computational domain.
double x0() const
X-coordinate of the center of the domain.
std::shared_ptr< const Context > ctx() const
Return execution context this grid corresponds to.
int xm() const
Width of this processor's sub-domain.
int ym() const
Width of this processor's sub-domain.
Describes the PISM grid and the distribution of data across processors.
std::array< int, 4 > count
std::shared_ptr< Interpolation1D > z
std::array< int, 4 > start
std::shared_ptr< Interpolation1D > x
std::shared_ptr< Interpolation1D > y
void message(int threshold, const char format[],...) const __attribute__((format(printf
Print a message to the log.
void begin(const char *name) const
void end(const char *name) const
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
std::string units_string() const
Internal time units as a string.
std::string calendar() const
Returns the calendar string.
void convert_doubles(double *data, size_t length) const
std::shared_ptr< System > Ptr
#define PISM_ERROR_LOCATION
static StartCountInfo compute_start_and_count(std::vector< AxisType > &dim_types, const std::array< int, 4 > &start, const std::array< int, 4 > &count)
void append_time(const File &file, const Config &config, double time_seconds)
Prepare a file for output.
void read_spatial_variable(const SpatialVariableMetadata &variable, const Grid &grid, const File &file, unsigned int time, double *output)
Read a variable from a file into an array output.
VariableMetadata read_attributes(const File &file, const std::string &variable_name, std::shared_ptr< units::System > unit_system)
static void define_dimensions(const SpatialVariableMetadata &var, const Grid &grid, const File &file)
Define dimensions a variable depends on.
void define_dimension(const File &file, unsigned long int length, const VariableMetadata &metadata)
Define a dimension and the associated coordinate variable. Set attributes.
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::vector< double > read_1d_variable(const File &file, const std::string &variable_name, const std::string &units, std::shared_ptr< units::System > unit_system)
void write_spatial_variable(const SpatialVariableMetadata &metadata, const Grid &grid, const File &file, const double *input)
Write a double array to a file.
void write_attributes(const File &file, const VariableMetadata &variable, io::Type nctype)
Write variable attributes to a NetCDF file.
void define_time_bounds(const VariableMetadata &var, const std::string &dimension_name, const std::string &bounds_name, const File &file, io::Type nctype)
void write_time_bounds(const File &file, const VariableMetadata &metadata, size_t t_start, const std::vector< double > &data)
static void read_distributed_array(const File &file, const std::string &variable_name, std::shared_ptr< units::System > unit_system, const std::array< int, 4 > &start, const std::array< int, 4 > &count, double *output)
Read an array distributed according to the grid.
static std::string check_units(const VariableMetadata &variable, const std::string &input_units, const Logger &log)
void define_spatial_variable(const SpatialVariableMetadata &metadata, const Grid &grid, const File &file, io::Type default_type)
Define a NetCDF variable corresponding to a VariableMetadata object.
static void check_for_missing_values(const File &file, const std::string &variable_name, double tolerance, const double *buffer, size_t buffer_length)
static void check_grid_overlap(const grid::InputGridInfo &input, const Grid &internal, const std::vector< double > &z_internal)
static void interpolate(const Grid &grid, const LocalInterpCtx &lic, double const *input_array, double *output_array)
Bi-(or tri-)linear interpolation.
void check_input_grid(const grid::InputGridInfo &input_grid, const Grid &internal_grid, const std::vector< double > &internal_z_levels)
Check that x, y, and z coordinates of the input grid are strictly increasing.
void write_dimensions(const SpatialVariableMetadata &var, const Grid &grid, const File &file)
void move_if_exists(MPI_Comm com, const std::string &file_to_move, int rank_to_use)
Moves the file aside (file.nc -> file.nc~).
void write_timeseries(const File &file, const VariableMetadata &metadata, size_t t_start, const std::vector< double > &data)
Write a time-series data to a file.
bool file_exists(MPI_Comm com, const std::string &filename)
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)
void remove_if_exists(MPI_Comm com, const std::string &file_to_remove, int rank_to_use)
Check if a file is present are remove it.
void regrid_spatial_variable(const SpatialVariableMetadata &variable, const Grid &target_grid, const LocalInterpCtx &interp_context, const File &file, double *output)
Regrid from a NetCDF file into a distributed array output.
std::string time_dimension(units::System::Ptr unit_system, const File &file, const std::string &variable_name)
static bool transpose(std::vector< AxisType > dimension_types)
static void write_dimension_data(const File &file, const std::string &name, const std::vector< double > &data)
void define_time(const File &file, const Context &ctx)
Prepare a file for output.
void define_timeseries(const VariableMetadata &var, const std::string &dimension_name, const File &file, io::Type nctype)
Define a NetCDF variable corresponding to a time-series.
static std::vector< AxisType > dimension_types(const File &file, const std::string &var_name, std::shared_ptr< units::System > unit_system)
bool is_increasing(const std::vector< double > &a)
Checks if a vector of doubles is strictly increasing.
static std::string calendar(const File *input_file, const Config &config, const Logger &log)
bool member(const std::string &string, const std::set< std::string > &set)
std::string join(const std::vector< std::string > &strings, const std::string &separator)
Concatenate strings, inserting separator between elements.
AxisType axis_type_from_string(const std::string &input)
std::vector< unsigned int > start
std::vector< unsigned int > count