27 #include "pism/util/ConfigInterface.hh"
28 #include "pism/util/Context.hh"
29 #include "pism/util/Grid.hh"
30 #include "pism/util/Logger.hh"
31 #include "pism/util/Profiling.hh"
32 #include "pism/util/Time.hh"
33 #include "pism/util/VariableMetadata.hh"
34 #include "pism/util/error_handling.hh"
35 #include "pism/util/interpolation.hh"
36 #include "pism/util/io/File.hh"
37 #include "pism/util/io/IO_Flags.hh"
38 #include "pism/util/io/LocalInterpCtx.hh"
39 #include "pism/util/io/io_helpers.hh"
40 #include "pism/util/pism_utilities.hh"
41 #include "pism/util/projection.hh"
63 double *output_array) {
70 unsigned int nlevels = lic.
z->n_output();
73 int x_count = lic.
count[X], z_count = lic.
count[Z];
76 const int i_global = p.i(), j_global = p.j();
78 const int i = i_global - grid.
xs(), j = j_global - grid.
ys();
81 const int X_m = lic.
x->left(i), X_p = lic.
x->right(i), Y_m = lic.
y->left(j),
82 Y_p = lic.
y->right(j);
84 for (
unsigned int k = 0;
k < nlevels;
k++) {
86 double a_mm = 0.0, a_mp = 0.0, a_pm = 0.0, a_pp = 0.0;
89 const int Z_m = lic.
z->left(
k), Z_p = lic.
z->right(
k);
91 const double alpha_z = lic.
z->alpha(
k);
96 const int mmm = (Y_m * x_count + X_m) * z_count + Z_m,
97 mmp = (Y_m * x_count + X_m) * z_count + Z_p,
98 mpm = (Y_m * x_count + X_p) * z_count + Z_m,
99 mpp = (Y_m * x_count + X_p) * z_count + Z_p,
100 pmm = (Y_p * x_count + X_m) * z_count + Z_m,
101 pmp = (Y_p * x_count + X_m) * z_count + Z_p,
102 ppm = (Y_p * x_count + X_p) * z_count + Z_m,
103 ppp = (Y_p * x_count + X_p) * z_count + Z_p;
106 a_mm = input_array[mmm] * (1.0 - alpha_z) + input_array[mmp] * alpha_z;
107 a_mp = input_array[mpm] * (1.0 - alpha_z) + input_array[mpp] * alpha_z;
108 a_pm = input_array[pmm] * (1.0 - alpha_z) + input_array[pmp] * alpha_z;
109 a_pp = input_array[ppm] * (1.0 - alpha_z) + input_array[ppp] * alpha_z;
112 a_mm = input_array[Y_m * x_count + X_m];
113 a_mp = input_array[Y_m * x_count + X_p];
114 a_pm = input_array[Y_p * x_count + X_m];
115 a_pp = input_array[Y_p * x_count + X_p];
119 const double x_alpha = lic.
x->alpha(i);
121 const double y_alpha = lic.
y->alpha(j);
124 const double a_m = a_mm * (1.0 - x_alpha) + a_mp * x_alpha;
125 const double a_p = a_pm * (1.0 - x_alpha) + a_pp * x_alpha;
127 int index = (j * grid.
xm() + i) * nlevels +
k;
130 output_array[index] = a_m * (1.0 - y_alpha) + a_p * y_alpha;
139 std::vector<unsigned int>
imap;
143 std::array<int, 4> start_in,
144 std::array<int, 4> count_in) {
146 auto x_start = start_in[
X_AXIS];
147 auto x_count = count_in[
X_AXIS];
148 auto y_start = start_in[
Y_AXIS];
149 auto y_count = count_in[
Y_AXIS];
150 auto z_start = start_in[
Z_AXIS];
151 auto z_count = count_in[
Z_AXIS];
155 auto ndims = dim_types.size();
158 result.
start.resize(ndims);
159 result.
count.resize(ndims);
160 result.
imap.resize(ndims);
163 for (
unsigned int j = 0; j < ndims; j++) {
170 result.
imap[j] = x_count * y_count * z_count;
173 result.
start[j] = y_start;
174 result.
count[j] = y_count;
175 result.
imap[j] = x_count * z_count;
178 result.
start[j] = x_start;
179 result.
count[j] = x_count;
180 result.
imap[j] = z_count;
184 result.
start[j] = z_start;
185 result.
count[j] = z_count;
197 std::string name = metadata.
get_name();
234 time[
"long_name"] =
"time";
236 time[
"units"] = units;
288 if (not z_name.empty()) {
290 const std::vector<double> &levels = var.
levels();
292 unsigned int nlevels =
std::max(levels.size(), (
size_t)1);
296 bool spatial_dim = not var.
z().
get_string(
"axis").empty();
298 if (nlevels > 1 and spatial_dim) {
299 double dz_max = levels[1] - levels[0];
300 double dz_min = levels.back() - levels.front();
302 for (
unsigned int k = 0;
k < nlevels - 1; ++
k) {
303 double dz = levels[
k + 1] - levels[
k];
316 const std::vector<double> &data) {
319 file.
write_variable(name, { 0 }, { (
unsigned int)data.size() }, data.data());
355 std::vector<AxisType> storage, memory = {
Y_AXIS,
X_AXIS };
360 if (first && dimtype ==
T_AXIS) {
368 storage.push_back(dimtype);
369 }
else if (dimtype ==
Z_AXIS) {
370 memory.push_back(dimtype);
372 storage.push_back(dimtype);
380 assert(memory.size() <= 3);
382 return storage != memory;
386 std::shared_ptr<units::System> unit_system) {
387 std::vector<AxisType> result;
388 for (
const auto &dimension : file.
dimensions(var_name)) {
396 unsigned int z_count,
unsigned int t_start,
double *output) {
401 { (int)t_start, grid.
xs(), grid.
ys(), 0 },
402 { 1, grid.
xm(), grid.
ym(), (int)z_count });
411 e.
add_context(
"reading variable '%s' from '%s'", var_name.c_str(), file.
filename().c_str());
423 const std::string &variable_name,
424 const Grid &internal_grid,
428 auto unit_system = internal_grid.
ctx()->unit_system();
432 auto dim_types =
dimension_types(file, variable_name, internal_grid.
ctx()->unit_system());
439 file.
read_variable(variable_name, sc.start, sc.count, buffer.data());
445 if (attribute.size() == 1) {
446 double fill_value = attribute[0], epsilon = 1e-12;
448 for (
const auto &value : buffer) {
449 if (fabs(value - fill_value) < epsilon) {
452 variable_name.c_str(), file.
filename().c_str());
460 e.
add_context(
"reading variable '%s' from '%s'", variable_name.c_str(),
469 auto config = grid.
ctx()->config();
474 if (config->get_flag(
"output.use_MKS")) {
478 std::vector<std::string> dims;
490 dims.push_back(config->get_string(
"time.dimension_name"));
500 assert(dims.size() > 1);
529 const File &file,
unsigned int time,
double *output) {
536 if (not var.exists) {
551 int input_spatial_dim_count = 0;
552 size_t matching_dim_count = 0;
555 for (
const auto &d : input_dims) {
559 ++input_spatial_dim_count;
562 if (axes.find(dim_type) != axes.end()) {
563 ++matching_dim_count;
567 if (axes.size() != matching_dim_count) {
572 "found the %dD variable %s (%s) in '%s' while trying to read\n"
573 "'%s' ('%s'), which is %d-dimensional.",
574 input_spatial_dim_count, var.name.c_str(),
join(input_dims,
",").c_str(),
576 variable.
get_string(
"long_name").c_str(),
static_cast<int>(axes.size()));
586 const std::string &internal_units = variable[
"units"];
588 if (input_units.empty() and not internal_units.empty()) {
589 const std::string &long_name = variable[
"long_name"];
591 "PISM WARNING: Variable '%s' ('%s') does not have the units attribute.\n"
592 " Assuming that it is in '%s'.\n",
593 variable.
get_name().c_str(), long_name.c_str(), internal_units.c_str());
594 input_units = internal_units;
598 size_t size = grid.
xm() * grid.
ym() * nlevels;
603 if (att.size() == 1) {
604 double fill_value = att[0];
605 for (
size_t k = 0;
k < size; ++
k) {
606 if (output[
k] == fill_value) {
609 "Some values of the variable '%s' in '%s' match the _FillValue attribute.",
610 var.name.c_str(), file.
filename().c_str());
625 const File &file,
const double *input) {
626 auto config = grid.
ctx()->config();
631 if (config->get_flag(
"output.use_MKS")) {
648 if (not time_dependent) {
661 std::string units = var[
"units"], output_units = var[
"output_units"];
663 if (units != output_units) {
664 size_t data_size = grid.
xm() * grid.
ym() * nlevels;
668 std::vector<double> tmp(data_size);
669 for (
size_t k = 0;
k < data_size; ++
k) {
688 const std::vector<double> &z_internal) {
696 const double x_min =
internal.x0() -
internal.Lx(), x_max =
internal.x0() +
internal.Lx(),
697 y_min =
internal.y0() -
internal.Ly(), y_max =
internal.y0() +
internal.Ly(),
698 input_x_min = input.
x0 - input.
Lx, input_x_max = input.
x0 + input.
Lx,
699 input_y_min = input.
y0 - input.
Ly, input_y_max = input.
y0 + input.
Ly;
705 if (not(x_min >= input_x_min - eps and x_max <= input_x_max + eps and
706 y_min >= input_y_min - eps and y_max <= input_y_max + eps)) {
709 "PISM's computational domain is not a subset of the domain in '%s'\n"
710 "PISM grid: x: [%3.3f, %3.3f] y: [%3.3f, %3.3f] meters\n"
711 "input file grid: x: [%3.3f, %3.3f] y: [%3.3f, %3.3f] meters",
712 input.
filename.c_str(), x_min, x_max, y_min, y_max, input_x_min, input_x_max, input_y_min,
716 if (z_internal.empty()) {
718 "Internal vertical grid has 0 levels. This should never happen.");
721 if (z_internal.size() == 1 and input.
z.size() > 1) {
725 "trying to read in a 2D field but the input file %s contains\n"
726 "a 3D field with %d levels",
727 input.
filename.c_str(),
static_cast<int>(input.
z.size()));
730 if (z_internal.size() > 1 and input.
z.size() <= 1) {
734 "trying to read in a 3D field but the input file %s contains\n"
739 if (z_internal.size() > 1 and (not input.
z.empty())) {
742 const double input_z_min = input.
z.front(), input_z_max = input.
z.back(),
743 z_min = z_internal.front(), z_max = z_internal.back();
745 if (not(z_min >= input.
z_min - eps and z_max <= input.
z_max + eps)) {
748 "PISM's computational domain is not a subset of the domain in '%s'\n"
749 "PISM grid: z: [%3.3f, %3.3f] meters\n"
750 "input file grid: z: [%3.3f, %3.3f] meters",
751 input.
filename.c_str(), z_min, z_max, input_z_min, input_z_max);
758 const Grid& internal_grid,
759 const std::vector<double> &internal_z_levels) {
762 "input x coordinate has to be strictly increasing");
767 "input y coordinate has to be strictly increasing");
772 "input vertical grid has to be strictly increasing");
775 bool allow_extrapolation = internal_grid.
ctx()->config()->get_flag(
"grid.allow_extrapolation");
777 if (not allow_extrapolation) {
794 const Grid &internal_grid,
799 auto variable_name = var_info.
name;
801 const Profiling &profiling = internal_grid.
ctx()->profiling();
803 profiling.
begin(
"io.regridding.read");
805 profiling.
end(
"io.regridding.read");
808 profiling.
begin(
"io.regridding.interpolate");
809 regrid(internal_grid, lic, buffer.data(), output);
810 profiling.
end(
"io.regridding.interpolate");
815 std::string internal_units = variable[
"units"];
817 if (input_units.empty() and not internal_units.empty()) {
818 const Logger &log = *internal_grid.
ctx()->log();
820 "PISM WARNING: Variable '%s' ('%s') does not have the units attribute.\n"
821 " Assuming that it is in '%s'.\n",
823 internal_units.c_str());
824 input_units = internal_units;
827 const size_t data_size = internal_grid.
xm() * internal_grid.
ym() * lic.
z->n_output();
861 std::vector<double> &data) {
863 std::string name = metadata.
get_name();
867 std::string long_name = metadata[
"long_name"], standard_name = metadata[
"standard_name"];
871 if (not var.exists) {
876 if (dims.size() != 1) {
878 "variable '%s' in '%s' should to have 1 dimension (got %d)",
879 name.c_str(), file.
filename().c_str(), (
int)dims.size());
882 auto dimension_name = dims[0];
891 file.
read_variable(var.name, { 0 }, { length }, data.data());
894 units::Unit internal_units(system, metadata[
"units"]), input_units(system,
"1");
898 bool input_has_units = not input_units_string.empty();
900 if (input_has_units) {
901 input_units =
units::Unit(system, input_units_string);
904 if (metadata.
has_attribute(
"units") && not input_has_units) {
905 std::string units_string = internal_units.format();
907 "PISM WARNING: Variable '%s' ('%s') does not have the units attribute.\n"
908 " Assuming that it is in '%s'.\n",
909 name.c_str(), long_name.c_str(), units_string.c_str());
910 input_units = internal_units;
916 e.
add_context(
"reading time-series variable '%s' from '%s'", name.c_str(),
927 const std::vector<double> &data) {
929 std::string name = metadata.
get_name();
936 std::vector<double> tmp = data;
942 file.
write_variable(name, {(
unsigned int)t_start}, {(
unsigned int)tmp.size()}, tmp.data());
945 e.
add_context(
"writing time-series variable '%s' to '%s'", name.c_str(),
952 const std::string &dimension_name,
953 const std::string &bounds_name,
977 std::vector<double> &data) {
979 std::string name = metadata.
get_name();
983 units::Unit internal_units(system, metadata[
"units"]);
990 std::vector<std::string> dims = file.
dimensions(name);
992 if (dims.size() != 2) {
997 &dimension_name = dims[0],
998 &bounds_name = dims[1];
1004 "time-bounds variable " + name +
" has to have exactly 2 bounds per time record");
1013 data.resize(2*length);
1022 "time coordinate variable " + dimension_name +
" is missing");
1025 bool input_has_units =
false;
1029 if (input_units_string.empty()) {
1030 input_has_units =
false;
1033 input_has_units =
true;
1036 if (metadata.
has_attribute(
"units") && not input_has_units) {
1037 std::string units_string = internal_units.
format();
1039 "PISM WARNING: Variable '%s' does not have the units attribute.\n"
1040 " Assuming that it is in '%s'.\n",
1041 dimension_name.c_str(),
1042 units_string.c_str());
1043 input_units = internal_units;
1051 e.
add_context(
"reading time bounds variable '%s' from '%s'", name.c_str(),
1058 size_t t_start,
const std::vector<double> &data) {
1065 if (not variable_exists) {
1071 std::vector<double> tmp = data;
1078 {(
unsigned int)t_start, 0},
1079 {(
unsigned int)tmp.size() / 2, 2},
1083 e.
add_context(
"writing time-bounds variable '%s' to '%s'", name.c_str(),
1093 std::shared_ptr<units::System> unit_system,
1095 const std::string &time_name,
1096 const std::string &time_units,
1097 std::vector<double> ×,
1098 std::vector<double> &bounds) {
1103 time_variable[
"units"] = time_units;
1109 "times have to be strictly increasing");
1118 if (time_bounds_name.empty()) {
1120 "please provide time bounds for '%s'",
1125 bounds_variable[
"units"] = time_units;
1129 if (2 * N != bounds.size()) {
1131 "each time record has to have 2 bounds");
1134 for (
size_t k = 0;
k < N; ++
k) {
1135 if (not (times[
k] >= bounds[2 *
k + 0] and
1136 times[
k] <= bounds[2 *
k + 1])) {
1138 "each time has to be contained in its time interval");
1145 int file_exists_flag = 0, rank = 0;
1146 MPI_Comm_rank(com, &rank);
1150 if (FILE *f = fopen(filename.c_str(),
"r")) {
1151 file_exists_flag = 1;
1154 file_exists_flag = 0;
1157 MPI_Bcast(&file_exists_flag, 1, MPI_INT, 0, com);
1159 return file_exists_flag == 1;
1163 const std::string &variable_name,
1172 unsigned int nattrs = file.
nattributes(variable_name);
1174 for (
unsigned int j = 0; j < nattrs; ++j) {
1175 std::string attribute_name = file.
attribute_name(variable_name, j);
1187 e.
add_context(
"reading attributes of variable '%s' from '%s'",
1188 variable_name.c_str(), file.
filename().c_str());
1201 std::string var_name = variable.
get_name();
1205 units = variable[
"units"],
1206 output_units = variable[
"output_units"];
1208 bool use_output_units = units != output_units;
1212 file.
write_attribute(var_name,
"units", use_output_units ? output_units : units);
1215 std::vector<double> bounds(2);
1220 bounds[0] = variable.
get_number(
"valid_min");
1223 bounds[1] = variable.
get_number(
"valid_max");
1227 double fill_value = 0.0;
1229 fill_value = variable.
get_number(
"_FillValue");
1234 if (use_output_units) {
1238 bounds[0] = c(bounds[0]);
1239 bounds[1] = c(bounds[1]);
1240 fill_value = c(fill_value);
1264 if (name ==
"units" or
1265 name ==
"output_units" or
1275 std::string name = d.first;
1276 std::vector<double> values = d.second;
1278 if (
member(name, {
"valid_min",
"valid_max",
"valid_range",
"_FillValue"}) or
1287 e.
add_context(
"writing attributes of variable '%s' to '%s'",
1288 var_name.c_str(), file.
filename().c_str());
1308 if (file_units.empty()) {
1317 if (bounds.size() == 2) {
1318 variable[
"valid_min"] = {c(bounds[0])};
1319 variable[
"valid_max"] = {c(bounds[1])};
1322 if (bounds.size() == 1) {
1323 variable[
"valid_min"] = {c(bounds[0])};
1327 if (bounds.size() == 1) {
1328 variable[
"valid_max"] = {c(bounds[0])};
1332 e.
add_context(
"reading valid range of variable '%s' from '%s'", name.c_str(),
1345 const std::string &variable_name) {
1349 for (
const auto &d : dims) {
1362 void move_if_exists(MPI_Comm com,
const std::string &file_to_move,
int rank_to_use) {
1363 int stat = 0, rank = 0;
1364 MPI_Comm_rank(com, &rank);
1365 std::string backup_filename = file_to_move +
"~";
1367 if (rank == rank_to_use) {
1368 bool exists =
false;
1371 if (FILE *f = fopen(file_to_move.c_str(),
"r")) {
1379 stat = rename(file_to_move.c_str(), backup_filename.c_str());
1383 int global_stat = 0;
1384 MPI_Allreduce(&stat, &global_stat, 1, MPI_INT, MPI_SUM, com);
1386 if (global_stat != 0) {
1388 "PISM ERROR: can't move '%s' to '%s'",
1389 file_to_move.c_str(), backup_filename.c_str());
1398 int stat = 0, rank = 0;
1399 MPI_Comm_rank(com, &rank);
1401 if (rank == rank_to_use) {
1402 bool exists =
false;
1405 if (FILE *f = fopen(file_to_remove.c_str(),
"r")) {
1413 stat = remove(file_to_remove.c_str());
1417 int global_stat = 0;
1418 MPI_Allreduce(&stat, &global_stat, 1, MPI_INT, MPI_SUM, com);
1420 if (global_stat != 0) {
1422 "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 find_dimension(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 read_variable_transposed(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const std::vector< unsigned int > &imap, 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.
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.
std::string filename() const
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 remove_attribute(const std::string &variable_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.
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.
const std::vector< double > & x() const
X-coordinates.
const std::vector< double > & y() const
Y-coordinates.
int ys() const
Global starting index of this processor's subset.
PointsWithGhosts points(unsigned int stencil_width=0) const
unsigned int My() const
Total grid size in the Y direction.
std::shared_ptr< const Context > ctx() const
Return execution context this grid corresponds to.
unsigned int Mx() const
Total grid size in the X direction.
const MappingInfo & get_mapping_info() const
int xs() const
Global starting index of this processor's subset.
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::array< int, 4 > start
std::shared_ptr< Interpolation > y
std::shared_ptr< Interpolation > z
std::shared_ptr< Interpolation > x
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
std::string format() const
System::Ptr system() const
#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 StartCountInfo compute_start_and_count(std::vector< AxisType > &dim_types, std::array< int, 4 > start_in, std::array< int, 4 > count_in)
void append_time(const File &file, const Config &config, double time_seconds)
Prepare a file for output.
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.
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.
static void define_dimensions(const SpatialVariableMetadata &var, const Grid &grid, const File &file)
Define dimensions a variable depends on.
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 define_dimension(const File &file, unsigned long int length, const VariableMetadata &metadata)
Define a dimension and the associated coordinate variable. Set attributes.
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)
static void read_distributed_array(const File &file, const Grid &grid, const std::string &var_name, unsigned int z_count, unsigned int t_start, double *output)
Read an array distributed according to the grid.
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_time_bounds(const File &file, const VariableMetadata &metadata, size_t t_start, const std::vector< double > &data)
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)
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.
void read_time_bounds(const File &file, const VariableMetadata &metadata, const Logger &log, std::vector< double > &data)
static void check_grid_overlap(const grid::InputGridInfo &input, const Grid &internal, const std::vector< double > &z_internal)
static std::vector< AxisType > dimension_types(const File &file, const std::string &var_name, std::shared_ptr< units::System > unit_system)
static std::vector< double > read_for_interpolation(const File &file, const std::string &variable_name, const Grid &internal_grid, const LocalInterpCtx &lic)
void write_dimensions(const SpatialVariableMetadata &var, const Grid &grid, const File &file)
static void regrid(const Grid &grid, const LocalInterpCtx &lic, double const *input_array, double *output_array)
Bi-(or tri-)linear interpolation.
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 read_attributes(const File &file, const std::string &variable_name, VariableMetadata &variable)
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)
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 read_valid_range(const File &file, const std::string &name, VariableMetadata &variable)
Read the valid range information from a file.
std::string time_dimension(units::System::Ptr unit_system, const File &file, const std::string &variable_name)
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.
static bool use_transposed_io(std::vector< AxisType > dimension_types)
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.
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 > imap
std::vector< unsigned int > count