28#include "pism/util/array/Array.hh"
29#include "pism/util/array/Array_impl.hh"
31#include "pism/util/Config.hh"
32#include "pism/util/Grid.hh"
33#include "pism/util/Time.hh"
35#include "pism/util/Context.hh"
36#include "pism/util/Logger.hh"
37#include "pism/util/Profiling.hh"
38#include "pism/util/VariableMetadata.hh"
39#include "pism/util/error_handling.hh"
40#include "pism/util/io/File.hh"
41#include "pism/util/io/IO_Flags.hh"
42#include "pism/util/io/io_helpers.hh"
43#include "pism/util/petscwrappers/VecScatter.hh"
44#include "pism/util/petscwrappers/DM.hh"
45#include "pism/util/petscwrappers/Viewer.hh"
46#include "pism/util/pism_utilities.hh"
48#include "pism/util/InputInterpolation.hh"
49#include "pism/util/io/OutputWriter.hh"
50#include "pism/util/io/SynchronousOutputWriter.hh"
59 ierr = DMGlobalToLocalBegin(dm, source, INSERT_VALUES, destination);
60 PISM_CHK(ierr,
"DMGlobalToLocalBegin");
62 ierr = DMGlobalToLocalEnd(dm, source, INSERT_VALUES, destination);
63 PISM_CHK(ierr,
"DMGlobalToLocalEnd");
66Array::Array(std::shared_ptr<const Grid> grid,
const std::string &name,
Kind ghostedp,
size_t dof,
67 size_t stencil_width,
const std::vector<double> &zlevels) {
77 const auto &config =
grid->ctx()->config();
79 auto max_stencil_width =
static_cast<size_t>(config->get_number(
"grid.max_stencil_width"));
88 auto system =
m_impl->
grid->ctx()->unit_system();
91 for (
unsigned int j = 0; j <
m_impl->
dof; ++j) {
99 if (zlevels.size() > 1) {
159 return levels().empty() ? 2 : 3;
202 return NORM_INFINITY;
212 PetscErrorCode ierr = VecAXPY(
vec(), alpha, x.
vec());
220 PetscErrorCode ierr = VecShift(
vec(), alpha);
228 PetscErrorCode ierr = VecScale(
vec(), alpha);
248 this->
get_dof(destination_da, destination, 0, N);
252 unsigned int count)
const {
259 double ***result_a =
static_cast<double ***
>(tmp_res.get()),
260 ***source_a =
static_cast<double ***
>(tmp_v.
get());
265 const int i = p.i(), j = p.j();
266 PetscErrorCode ierr =
267 PetscMemcpy(result_a[j][i], &source_a[j][i][start],
count *
sizeof(PetscScalar));
277 unsigned int count) {
284 double ***source_a =
static_cast<double ***
>(tmp_src.get()),
285 ***result_a =
static_cast<double ***
>(tmp_v.
get());
290 const int i = p.i(), j = p.j();
291 PetscErrorCode ierr =
292 PetscMemcpy(&result_a[j][i][start], source_a[j][i],
count *
sizeof(PetscScalar));
315 PetscErrorCode ierr = 0;
318 PISM_CHK(ierr,
"DMCreateLocalVector");
321 PISM_CHK(ierr,
"DMCreateGlobalVector");
362 const Logger &log, Vec output) {
364 if (default_value.
exists()) {
366 log.
message(2,
" variable %s (%s) is not found: using the default constant\n",
369 PetscErrorCode ierr = VecSet(output, default_value);
383 assert(
ndims() == 2);
385 auto log =
grid()->ctx()->log();
389 auto dm_for_io =
ndof() == 1 ?
dm() :
grid()->get_dm(1, 0);
394 for (
unsigned int j = 0; j <
ndof(); ++j) {
397 auto V = file.
find_variable(variable.get_name(), variable[
"standard_name"]);
402 int last_record = -1;
403 interp->regrid(variable, file, last_record, *
grid(), tmp);
421 auto log =
grid()->ctx()->log();
422 log->message(4,
" Reading %s...\n",
m_impl->
name.c_str());
442 auto da2 =
grid()->get_dm(1, 0);
448 for (
unsigned int j = 0; j <
ndof(); ++j) {
468 assert(N < m_impl->dof);
473 assert(N < m_impl->dof);
483 auto log =
grid()->ctx()->log();
487 auto unit_converter = [
this](
unsigned int j) {
488 auto ctx =
grid()->ctx();
489 if (ctx->config()->get_flag(
"output.use_MKS")) {
491 return std::make_shared<units::Converter>();
494 std::string units =
metadata(j)[
"units"];
495 std::string output_units =
metadata(j)[
"output_units"];
497 bool use_output_units =
498 (not units.empty() and not output_units.empty() and units != output_units);
500 if (use_output_units) {
501 return std::make_shared<units::Converter>(ctx->unit_system(), units, output_units);
504 return std::make_shared<units::Converter>();
508 size_t n_levels =
levels().empty() ? 1 :
levels().size();
509 size_t local_array_size =
grid()->xm() *
grid()->ym() * n_levels;
513 log->message(3,
"[%s] Writing %s...\n", time.c_str(),
metadata(0).
get_name().c_str());
521 unit_converter(0)->convert_doubles(tmp_array.
get(), local_array_size);
533 auto da2 =
grid()->get_dm(1, 0);
539 for (
unsigned int j = 0; j <
ndof(); ++j) {
544 log->message(3,
"[%s] Writing %s...\n", time.c_str(),
metadata(j).
get_name().c_str());
546 unit_converter(j)->convert_doubles(tmp_array.
get(), local_array_size);
555 auto ctx =
grid()->ctx();
556 auto writer = std::make_shared<SynchronousOutputWriter>(ctx->com(), *ctx->config());
557 writer->initialize({},
true);
561 if (
metadata(0).get_time_dependent()) {
562 auto time = ctx->time();
567 for (
unsigned int k = 0;
k <
ndof(); ++
k) {
578 PetscInt X_size, Y_size;
585 ierr = VecGetSize(
vec(), &X_size);
588 ierr = VecGetSize(other.
vec(), &Y_size);
591 if (X_size != Y_size) {
608 PISM_CHK(ierr,
"DMDAVecGetArrayDOF");
624 "Array::end_access(): a == NULL (looks like begin_access() was not called)");
635 PISM_CHK(ierr,
"DMDAVecRestoreArrayDOF");
638 PISM_CHK(ierr,
"DMDAVecRestoreArray");
651 ierr = DMLocalToLocalBegin(*
dm(),
vec(), INSERT_VALUES,
vec());
652 PISM_CHK(ierr,
"DMLocalToLocalBegin");
654 ierr = DMLocalToLocalEnd(*
dm(),
vec(), INSERT_VALUES,
vec());
655 PISM_CHK(ierr,
"DMLocalToLocalEnd");
660 PetscErrorCode ierr = VecSet(
vec(),c);
667 double ghost_width = 0;
677 bool out_of_range = (i <
m_impl->
grid->xs() - ghost_width) ||
679 (j < m_impl->
grid->ys() - ghost_width) ||
705 PetscErrorCode ierr = VecStrideNormAll(
vec(), type, result.data());
708 PetscErrorCode ierr = VecNorm(
vec(), type, result.data());
718 "Array::norm_all(...): NORM_1_AND_2"
719 " not implemented (called as %s.norm_all(...))",
735 case NORM_INFINITY: {
743 "Array::norm_all(...): unknown norm type"
744 " (called as %s.norm_all(...))",
755 this->
read(file, time);
760 this->
regrid(file, default_value);
765 const std::string &filename,
768 PetscErrorCode ierr = 0;
773 ierr = VecMin(v, NULL, &
min);
775 ierr = VecMax(v, NULL, &
max);
817 m_impl->
grid->ctx()->profiling().begin(
"io.regridding");
823 for (
unsigned k = 0;
k <
ndof(); ++
k) {
824 auto dm =
grid()->get_dm(1, 0);
842 m_impl->
grid->ctx()->profiling().end(
"io.regridding");
847 if (time_spent > 1.0) {
848 log->message(3,
" done in %f seconds.\n", time_spent);
850 log->message(3,
" done.\n");
869 megabyte = pow(2, 20),
870 N =
static_cast<double>(
size()),
871 mb_double =
static_cast<double>(
sizeof(
double)) * N / megabyte,
872 mb_float =
static_cast<double>(
sizeof(
float)) * N / megabyte;
875 std::string spacer(
timestamp.size(),
' ');
876 if (time_spent > 1) {
879 " [%s] Done writing %s (%f Mb double, %f Mb float)\n"
880 " %s in %f seconds (%f minutes).\n"
881 " %s Effective throughput: double: %f Mb/s, float: %f Mb/s.\n",
883 spacer.c_str(), time_spent, time_spent / minute,
885 mb_double / time_spent, mb_float / time_spent);
887 m_impl->
grid->ctx()->log()->message(3,
" done.\n");
896 while (not
m_vecs.empty()) {
898 m_vecs.back()->end_access();
907 for (
const auto *j : vecs) {
908 assert(j !=
nullptr);
923 for (
const auto *v : vecs) {
924 assert(v !=
nullptr);
942 return Mx * My * Mz * dof;
952 ierr = PetscObjectQuery((PetscObject)
dm()->get(),
"v_proc0", (PetscObject*)&v_proc0);
955 if (v_proc0 == NULL) {
962 ierr = DMDACreateNaturalVector(*
dm(), natural_work.
rawptr());
963 PISM_CHK(ierr,
"DMDACreateNaturalVector");
966 ierr = PetscObjectCompose((PetscObject)
dm()->get(),
"natural_work",
967 (PetscObject)((::Vec)natural_work));
968 PISM_CHK(ierr,
"PetscObjectCompose");
976 ierr = VecScatterCreateToZero(natural_work, scatter_to_zero.
rawptr(),
978 PISM_CHK(ierr,
"VecScatterCreateToZero");
981 ierr = PetscObjectCompose((PetscObject)
dm()->get(),
"scatter_to_zero",
982 (PetscObject)((::VecScatter)scatter_to_zero));
983 PISM_CHK(ierr,
"PetscObjectCompose");
986 ierr = PetscObjectCompose((PetscObject)
dm()->get(),
"v_proc0",
987 (PetscObject)v_proc0);
988 PISM_CHK(ierr,
"PetscObjectCompose");
996 ierr = VecDuplicate(v_proc0, &result);
999 return std::shared_ptr<petsc::Vec>(
new petsc::Vec(result));
1003 PetscErrorCode ierr = 0;
1004 VecScatter scatter_to_zero = NULL;
1005 Vec natural_work = NULL;
1007 ierr = PetscObjectQuery((PetscObject)
dm()->get(),
"scatter_to_zero",
1008 (PetscObject*)&scatter_to_zero);
1009 PISM_CHK(ierr,
"PetscObjectQuery");
1011 ierr = PetscObjectQuery((PetscObject)
dm()->get(),
"natural_work",
1012 (PetscObject*)&natural_work);
1013 PISM_CHK(ierr,
"PetscObjectQuery");
1015 if (natural_work == NULL || scatter_to_zero == NULL) {
1019 ierr = DMDAGlobalToNaturalBegin(*
dm(), parallel, INSERT_VALUES, natural_work);
1020 PISM_CHK(ierr,
"DMDAGlobalToNaturalBegin");
1022 ierr = DMDAGlobalToNaturalEnd(*
dm(), parallel, INSERT_VALUES, natural_work);
1023 PISM_CHK(ierr,
"DMDAGlobalToNaturalEnd");
1025 ierr = VecScatterBegin(scatter_to_zero, natural_work, onp0,
1026 INSERT_VALUES, SCATTER_FORWARD);
1029 ierr = VecScatterEnd(scatter_to_zero, natural_work, onp0,
1030 INSERT_VALUES, SCATTER_FORWARD);
1047 PetscErrorCode ierr;
1049 VecScatter scatter_to_zero = NULL;
1050 Vec natural_work = NULL;
1051 ierr = PetscObjectQuery((PetscObject)
dm()->get(),
"scatter_to_zero",
1052 (PetscObject*)&scatter_to_zero);
1053 PISM_CHK(ierr,
"PetscObjectQuery");
1055 ierr = PetscObjectQuery((PetscObject)
dm()->get(),
"natural_work",
1056 (PetscObject*)&natural_work);
1057 PISM_CHK(ierr,
"PetscObjectQuery");
1059 if (natural_work == NULL || scatter_to_zero == NULL) {
1063 ierr = VecScatterBegin(scatter_to_zero, onp0, natural_work,
1064 INSERT_VALUES, SCATTER_REVERSE);
1067 ierr = VecScatterEnd(scatter_to_zero, onp0, natural_work,
1068 INSERT_VALUES, SCATTER_REVERSE);
1071 ierr = DMDANaturalToGlobalBegin(*
dm(), natural_work, INSERT_VALUES, parallel);
1072 PISM_CHK(ierr,
"DMDANaturalToGlobalBegin");
1074 ierr = DMDANaturalToGlobalEnd(*
dm(), natural_work, INSERT_VALUES, parallel);
1075 PISM_CHK(ierr,
"DMDANaturalToGlobalEnd");
1104 MPI_Comm_rank(com, &rank);
1106 uint64_t result = 0;
1111 PetscErrorCode ierr = VecGetLocalSize(*v, &
size);
1116 MPI_Bcast(&result, 1, MPI_UINT64_T, 0, com);
1129 static_assert(
sizeof(
double) == 2 *
sizeof(uint32_t),
1130 "Cannot compile Array::fletcher64() (sizeof(double) != 2 * sizeof(uint32_t))");
1132 MPI_Status mpi_stat;
1133 const int checksum_tag = 42;
1138 MPI_Comm_rank(com, &rank);
1141 MPI_Comm_size(com, &comm_size);
1143 PetscInt local_size = 0;
1144 PetscErrorCode ierr = VecGetLocalSize(
vec(), &local_size);
PISM_CHK(ierr,
"VecGetLocalSize");
1153 std::vector<uint64_t> sums(comm_size);
1157 for (
int r = 1; r < comm_size; ++r) {
1158 MPI_Recv(&sums[r], 1, MPI_UINT64_T, r, checksum_tag, com, &mpi_stat);
1164 MPI_Send(&
sum, 1, MPI_UINT64_T, 0, checksum_tag, com);
1168 MPI_Bcast(&
sum, 1, MPI_UINT64_T, 0, com);
1185 log->message(1,
"%s%s: %s\n", prefix,
m_impl->
name.c_str(),
checksum(serial).c_str());
1189void Array::view(std::vector<std::shared_ptr<petsc::Viewer> > viewers)
const {
1190 PetscErrorCode ierr;
1194 "cannot 'view' a 3D field '%s'",
1204 for (
unsigned int i = 0; i <
ndof(); ++i) {
1211 output_units.c_str());
1215 PetscDraw draw = NULL;
1216 ierr = PetscViewerDrawGetDraw(v, 0, &draw);
1217 PISM_CHK(ierr,
"PetscViewerDrawGetDraw");
1219 ierr = PetscDrawSetTitle(draw, title.c_str());
1220 PISM_CHK(ierr,
"PetscDrawSetTitle");
1225 units, output_units);
1227 double bounds[2] = {0.0, 0.0};
1228 ierr = VecMin(tmp, NULL, &bounds[0]);
PISM_CHK(ierr,
"VecMin");
1229 ierr = VecMax(tmp, NULL, &bounds[1]);
PISM_CHK(ierr,
"VecMax");
1231 if (bounds[0] == bounds[1]) {
1236 ierr = PetscViewerDrawSetBounds(v, 1, bounds);
1237 PISM_CHK(ierr,
"PetscViewerDrawSetBounds");
1239 ierr = VecView(tmp, v);
1244std::set<VariableMetadata>
metadata(std::initializer_list<const Array *> vecs) {
1245 std::set<VariableMetadata> result;
1246 for (
const auto *vec : vecs) {
1247 for (
const auto &var : vec->all_metadata()) {
1257 const std::string &spec1,
const std::string &spec2) {
1261 PetscInt data_size = 0;
1262 PetscErrorCode ierr = VecGetLocalSize(v, &data_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.
High-level PISM I/O class.
void message(int threshold, const char format[],...) const __attribute__((format(printf
Print a message to the log.
void write_distributed_array(const std::string &variable_name, const double *input) const
void append_time(double time_seconds) const
void define_variable(const VariableMetadata &variable) const
void failed()
Indicates a failure of a parallel section.
virtual void begin_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
void add(const PetscAccessible &v)
std::vector< const PetscAccessible * > m_vecs
void read(const std::string &filename, unsigned int time)
virtual void end_access() const
Checks if an Array is allocated and calls DAVecRestoreArray.
virtual void regrid_impl(const File &file, io::Default default_value)
Gets an Array from a file file, interpolating onto the current grid.
void write_impl(const OutputFile &file) const
Writes an Array to a NetCDF file.
Array(std::shared_ptr< const Grid > grid, const std::string &name, Kind ghostedp, size_t dof, size_t stencil_width, const std::vector< double > &zlevels)
unsigned int ndof() const
Returns the number of degrees of freedom per grid point.
void set_interpolation_type(InterpolationType type)
void set_name(const std::string &name)
Sets the variable name to name.
void dump(const char filename[]) const
Dumps a variable to a file, overwriting this file's contents (for debugging).
void write(const OutputFile &file) const
virtual void begin_access() const
Checks if an Array is allocated and calls DAVecGetArray.
void shift(double alpha)
Result: v[j] <- v[j] + alpha for all j. Calls VecShift.
const std::vector< double > & levels() const
size_t size() const
Return the total number of elements in the owned part of an array.
void get_from_proc0(petsc::Vec &onp0)
Gets a local Array2 from processor 0.
void copy_to_vec(std::shared_ptr< petsc::DM > destination_da, petsc::Vec &destination) const
Copies v to a global vector 'destination'. Ghost points are discarded.
const std::string & get_name() const
Get the name of an Array object.
uint64_t fletcher64_serial() const
void get_dof(std::shared_ptr< petsc::DM > da_result, petsc::Vec &result, unsigned int start, unsigned int count=1) const
void scale(double alpha)
Result: v <- v * alpha. Calls VecScale.
void print_checksum(const char *prefix="", bool serial=false) const
int state_counter() const
Get the object state counter.
std::vector< int > shape() const
std::string checksum(bool serial) const
void view(std::vector< std::shared_ptr< petsc::Viewer > > viewers) const
View a 2D vector field using existing PETSc viewers.
std::shared_ptr< const Grid > grid() const
void set(double c)
Result: v[j] <- c for all j.
void set_dof(std::shared_ptr< petsc::DM > da_source, petsc::Vec &source, unsigned int start, unsigned int count=1)
void inc_state_counter()
Increment the object state counter.
std::shared_ptr< petsc::DM > dm() const
unsigned int ndims() const
Returns the number of spatial dimensions.
void regrid(const std::string &filename, io::Default default_value)
std::vector< VariableMetadata > all_metadata() const
std::shared_ptr< petsc::Vec > allocate_proc0_copy() const
uint64_t fletcher64() const
void put_on_proc0(petsc::Vec &onp0) const
Puts a local array::Scalar on processor 0.
void set_begin_access_use_dof(bool flag)
void add(double alpha, const Array &x)
Result: v <- v + alpha * x. Calls VecAXPY.
std::vector< double > norm(int n) const
Computes the norm of all the components of an Array.
void update_ghosts()
Updates ghost points.
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
unsigned int stencil_width() const
Get the stencil width of the current Array. Returns 0 if ghosts are not available.
void checkCompatibility(const char *function, const Array &other) const
Checks if two Arrays have compatible sizes, dimensions and numbers of degrees of freedom.
void read_impl(const File &file, unsigned int time)
Reads appropriate NetCDF variable(s) into an Array.
void check_array_indices(int i, int j, unsigned int k) const
Check array indices and warn if they are out of range.
Abstract class for reading, writing, allocating, and accessing a DA-based PETSc Vec (2D and 3D fields...
Wrapper around VecGetArray and VecRestoreArray.
void convert_doubles(double *data, size_t length) const
std::shared_ptr< System > Ptr
#define PISM_CHK(errcode, name)
#define PISM_ERROR_LOCATION
std::set< VariableMetadata > metadata(std::initializer_list< const Array * > vecs)
void global_to_local(petsc::DM &dm, Vec source, Vec destination)
double max(const array::Scalar &input)
Finds maximum over all the values in an array::Scalar object. Ignores ghosts.
void set_default_value_or_stop(const VariableMetadata &variable, io::Default default_value, const Logger &log, Vec output)
double sum(const array::Scalar &input)
Sums up all the values in an array::Scalar object. Ignores ghosts.
Kind
What "kind" of a vector to create: with or without ghosts.
static NormType int_to_normtype(int input)
double min(const array::Scalar &input)
Finds minimum over all the values in an array::Scalar object. Ignores ghosts.
static void check_range(petsc::Vec &v, const VariableMetadata &metadata, const std::string &filename, const Logger &log, bool report_range)
void read_spatial_variable(const VariableMetadata &variable, const Grid &grid, const File &file, unsigned int time, double *output)
Read a variable from a file into an array output.
@ PISM_READONLY
open an existing file for reading only
double get_time(MPI_Comm comm)
void GlobalMax(MPI_Comm comm, double *local, double *result, int count)
std::string printf(const char *format,...)
uint64_t fletcher64(const uint32_t *data, size_t length)
static double end_time(const Config &config, double time_start, const std::string &calendar, const units::Unit &time_units)
static void report_range(const std::vector< double > &data, const VariableMetadata &metadata, const Logger &log)
Report the range of a time-series stored in data.
std::string timestamp(MPI_Comm com)
Creates a time-stamp used for the history NetCDF attribute.
void handle_fatal_errors(MPI_Comm com)
static double start_time(const Config &config, const File *file, const std::string &reference_date, const std::string &calendar, const units::Unit &time_units)
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)
void convert_vec(petsc::Vec &v, units::System::Ptr system, const std::string &spec1, const std::string &spec2)
bool begin_access_use_dof
If true, use DMDAVecGetArrayDOF() in begin_access()
int state_counter
Internal array::Array "revision number".
bool ghosted
true if this Array is ghosted
std::vector< VariableMetadata > metadata
Metadata (NetCDF variable attributes)
std::shared_ptr< const Grid > grid
The computational grid.
InterpolationType interpolation_type
bool report_range
If true, report range when regridding.
gsl_interp_accel * bsearch_accel
unsigned int da_stencil_width
stencil width supported by the DA
std::vector< double > zlevels
Vertical levels (for 3D fields)
std::shared_ptr< petsc::DM > da
unsigned int dof
number of "degrees of freedom" per grid point