PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
Array.hh
Go to the documentation of this file.
1 // Copyright (C) 2008--2023 Ed Bueler, Constantine Khroulev, and David Maxwell
2 //
3 // This file is part of PISM.
4 //
5 // PISM is free software; you can redistribute it and/or modify it under the
6 // terms of the GNU General Public License as published by the Free Software
7 // Foundation; either version 3 of the License, or (at your option) any later
8 // version.
9 //
10 // PISM is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with PISM; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 
19 #ifndef PISM_ARRAY_H
20 #define PISM_ARRAY_H
21 
22 #include <initializer_list>
23 #include <memory> // shared_ptr, dynamic_pointer_cast
24 #include <cstdint> // uint64_t
25 #include <array>
26 
27 #include "pism/util/error_handling.hh" // RuntimeError
28 
29 namespace pism {
30 
31 enum InterpolationType : int;
32 
33 namespace io {
34 enum Type : int;
35 class Default;
36 }
37 
38 class Grid;
39 class File;
41 
42 namespace petsc {
43 class DM;
44 class Vec;
45 class Viewer;
46 } // end of namespace petsc
47 
48 namespace units {
49 class System;
50 }
51 
53 public:
54  virtual ~PetscAccessible() = default;
55  virtual void begin_access() const = 0;
56  virtual void end_access() const = 0;
57 };
58 
59 namespace array {
60 
61 //! What "kind" of a vector to create: with or without ghosts.
63 
64 //! Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
65 class AccessScope {
66 public:
67  AccessScope();
68  AccessScope(std::initializer_list<const PetscAccessible *> vecs);
69  AccessScope(const PetscAccessible &v);
70  ~AccessScope();
71  void add(const PetscAccessible &v);
72  void add(const std::vector<const PetscAccessible*> &vecs);
73 private:
74  std::vector<const PetscAccessible*> m_vecs;
75 };
76 
77 /*!
78  * Interpolation helper. Does not check if points needed for interpolation are within the current
79  * processor's sub-domain.
80  */
81 template<class F, typename T>
82 T interpolate(const F &field, double x, double y) {
83  auto grid = field.grid();
84 
85  int i_left = 0, i_right = 0, j_bottom = 0, j_top = 0;
86  grid->compute_point_neighbors(x, y, i_left, i_right, j_bottom, j_top);
87 
88  auto w = grid->compute_interp_weights(x, y);
89 
90  return (w[0] * field(i_left, j_bottom) +
91  w[1] * field(i_right, j_bottom) +
92  w[2] * field(i_right, j_top) +
93  w[3] * field(i_left, j_top));
94 }
95 
96 //! \brief Abstract class for reading, writing, allocating, and accessing a
97 //! DA-based PETSc Vec (2D and 3D fields) from within IceModel.
98 /*!
99  @anchor icemodelvec_use
100 
101  This class represents 2D and 3D fields in PISM. Its methods common to all
102  the derived classes can be split (roughly) into six kinds:
103 
104  - memory allocation (create)
105  - point-wise access (begin_access(), end_access())
106  - arithmetic (range(), norm(), add(), shift(), scale(), set(), ...)
107  - setting or reading metadata (set_attrs(), metadata())
108  - file input/output (read, write, regrid)
109  - tracking whether a field was updated (get_state_counter(), inc_state_counter())
110 
111  ## Memory allocation
112 
113  \code
114  array::Scalar var(grid, "var_name", WITH_GHOSTS);
115  // var is ready to use
116  \endcode
117 
118  ("WITH_GHOSTS" means "can be used in computations using map-plane neighbors
119  of grid points.)
120 
121  It is usually a good idea to set variable metadata right after creating it.
122  The method set_attrs() is used throughout PISM to set commonly used
123  attributes.
124 
125  ## Point-wise access
126 
127  PETSc performs some pointer arithmetic magic to allow convenient indexing of
128  grid point values. Because of this one needs to surround the code using row,
129  column or level indexes with begin_access() and end_access() calls:
130 
131  \code
132  double foo;
133  int i = 0, j = 0;
134  array::Scalar var;
135  // assume that var was allocated
136  ierr = var.begin_access(); CHKERRQ(ierr);
137  foo = var(i,j) * 2;
138  ierr = var.end_access(); CHKERRQ(ierr);
139  \endcode
140 
141  Please see [this page](@ref computational_grid) for a discussion of the
142  organization of PISM's computational grid and examples of for-loops you will
143  probably put between begin_access() and end_access().
144 
145  To ensure that ghost values are up to date add the following call
146  before the code using ghosts:
147 
148  \code
149  ierr = var.update_ghosts(); CHKERRQ(ierr);
150  \endcode
151 
152  ## Reading and writing variables
153 
154  PISM can read variables either from files with data on a grid matching the
155  current grid (read()) or, using bilinear interpolation, from files
156  containing data on a different (but compatible) grid (regrid()).
157 
158  To write a field to a "prepared" NetCDF file, use write(). (A file is prepared
159  if it contains all the necessary dimensions, coordinate variables and global
160  metadata.)
161 
162  If you need to "prepare" a file, do:
163  \code
164  File file(grid.com, PISM_NETCDF3);
165  io::prepare_for_output(file, *grid.ctx());
166  \endcode
167 
168  A note about NetCDF write performance: due to limitations of the NetCDF
169  (classic, version 3) format, it is significantly faster to
170  \code
171  for (all variables)
172  var.define(...);
173 
174  for (all variables)
175  var.write(...);
176  \endcode
177 
178  as opposed to
179 
180  \code
181  for (all variables) {
182  var.define(...);
183  var.write(...);
184  }
185  \endcode
186 
187  array::Array::define() is here so that we can use the first approach.
188 
189  ## Tracking if a field changed
190 
191  It is possible to track if a certain field changed with the help of
192  get_state_counter() and inc_state_counter() methods.
193 
194  For example, PISM's SIA code re-computes the smoothed bed only if the bed
195  deformation code updated it:
196 
197  \code
198  if (bed->get_state_counter() > bed_state_counter) {
199  ierr = bed_smoother->preprocess_bed(...); CHKERRQ(ierr);
200  bed_state_counter = bed->get_state_counter();
201  }
202  \endcode
203 
204  The state counter is **not** updated automatically. For the code snippet above
205  to work, a bed deformation model has to call inc_state_counter() after an
206  update.
207 */
208 class Array : public PetscAccessible {
209 public:
210  virtual ~Array();
211 
212  std::shared_ptr<const Grid> grid() const;
213  unsigned int ndims() const;
214  std::vector<int> shape() const;
215  //! @brief Returns the number of degrees of freedom per grid point.
216  unsigned int ndof() const;
217  unsigned int stencil_width() const;
218 
219  const std::vector<double>& levels() const;
220 
221  std::array<double,2> range() const;
222  std::vector<double> norm(int n) const;
223 
224  void add(double alpha, const Array &x);
225  void shift(double alpha);
226  void scale(double alpha);
227 
228  petsc::Vec& vec() const;
229  std::shared_ptr<petsc::DM> dm() const;
230 
231  void set_name(const std::string &name);
232  const std::string& get_name() const;
233 
234  void define(const File &file, io::Type default_type) const;
235 
236  void read(const std::string &filename, unsigned int time);
237  void read(const File &file, unsigned int time);
238 
239  void write(const std::string &filename) const;
240  void write(const File &file) const;
241 
242  void regrid(const std::string &filename, io::Default default_value);
243  void regrid(const File &file, io::Default default_value);
244 
245  virtual void begin_access() const;
246  virtual void end_access() const;
247  void update_ghosts();
248 
249  std::shared_ptr<petsc::Vec> allocate_proc0_copy() const;
250  void put_on_proc0(petsc::Vec &onp0) const;
251  void get_from_proc0(petsc::Vec &onp0);
252 
253  void set(double c);
254 
255  SpatialVariableMetadata& metadata(unsigned int N = 0);
256 
257  const SpatialVariableMetadata& metadata(unsigned int N = 0) const;
258 
259  int state_counter() const;
260  void inc_state_counter();
261 
263 
264  void view(std::vector<std::shared_ptr<petsc::Viewer> > viewers) const;
265 
266 protected:
267  Array(std::shared_ptr<const Grid> grid,
268  const std::string &name,
269  Kind ghostedp,
270  size_t dof,
271  size_t stencil_width,
272  const std::vector<double> &zlevels);
273  struct Impl;
275 
276  // will be cast to double**, double***, or Vector2** in derived classes
277  // This is not hidden in m_impl to make it possible to inline operator()
278  mutable void *m_array;
279 
280  void set_begin_access_use_dof(bool flag);
281 
282  void read_impl(const File &file, unsigned int time);
283  virtual void regrid_impl(const File &file, io::Default default_value);
284  void write_impl(const File &file) const;
285 
286  void checkCompatibility(const char *function, const Array &other) const;
287 
288  //! @brief Check array indices and warn if they are out of range.
289  void check_array_indices(int i, int j, unsigned int k) const;
290 
291  void copy_to_vec(std::shared_ptr<petsc::DM> destination_da, petsc::Vec &destination) const;
292  void get_dof(std::shared_ptr<petsc::DM> da_result, petsc::Vec &result, unsigned int start,
293  unsigned int count=1) const;
294  void set_dof(std::shared_ptr<petsc::DM> da_source, petsc::Vec &source, unsigned int start,
295  unsigned int count=1);
296 private:
297  size_t size() const;
298  // disable copy constructor and the assignment operator:
299  Array(const Array &other);
301 public:
302  //! Dump an Array to a file. *This is for debugging only.*
303  //! Uses const char[] to make it easier to call it from gdb.
304  void dump(const char filename[]) const;
305 
306  uint64_t fletcher64_serial() const;
307  uint64_t fletcher64() const;
308  std::string checksum(bool serial) const;
309  void print_checksum(const char *prefix = "", bool serial=false) const;
310 
311 protected:
312  void put_on_proc0(petsc::Vec &parallel, petsc::Vec &onp0) const;
313  void get_from_proc0(petsc::Vec &onp0, petsc::Vec &parallel) const;
314 };
315 
316 //! `std::dynamic_pointer_cast` wrapper that checks if the cast succeeded.
317 template <class T>
318 static typename std::shared_ptr<T> cast(std::shared_ptr<Array> input) {
319  auto result = std::dynamic_pointer_cast<T, Array>(input);
320 
321  if (not result) {
322  throw RuntimeError(PISM_ERROR_LOCATION, "dynamic cast failure");
323  }
324 
325  return result;
326 }
327 
328 } // end of namespace array
329 
330 /**
331  * Convert a PETSc Vec from the units in `from` into units in `to` (in place).
332  *
333  * @param v data to convert
334  * @param system unit system
335  * @param spec1 source unit specification string
336  * @param spec2 destination unit specification string
337  */
338 void convert_vec(petsc::Vec &v, std::shared_ptr<units::System> system,
339  const std::string &spec1, const std::string &spec2);
340 
341 } // end of namespace pism
342 
343 #endif /* PISM_ARRAY_H */
High-level PISM I/O class.
Definition: File.hh:56
Describes the PISM grid and the distribution of data across processors.
Definition: Grid.hh:282
virtual ~PetscAccessible()=default
virtual void begin_access() const =0
virtual void end_access() const =0
Spatial NetCDF variable (corresponding to a 2D or 3D scalar field).
void add(const PetscAccessible &v)
Definition: Array.cc:933
std::vector< const PetscAccessible * > m_vecs
Definition: Array.hh:74
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition: Array.hh:65
void read(const std::string &filename, unsigned int time)
Definition: Array.cc:809
void write_impl(const File &file) const
Writes an Array to a NetCDF file.
Definition: Array.cc:564
virtual void end_access() const
Checks if an Array is allocated and calls DAVecRestoreArray.
Definition: Array.cc:667
virtual void regrid_impl(const File &file, io::Default default_value)
Gets an Array from a file file, interpolating onto the current grid.
Definition: Array.cc:426
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)
Definition: Array.cc:59
unsigned int ndof() const
Returns the number of degrees of freedom per grid point.
Definition: Array.cc:136
void set_interpolation_type(InterpolationType type)
Definition: Array.cc:179
void set_name(const std::string &name)
Sets the variable name to name.
Definition: Array.cc:371
void dump(const char filename[]) const
Dumps a variable to a file, overwriting this file's contents (for debugging).
Definition: Array.cc:607
std::array< double, 2 > range() const
Result: min <- min(v[j]), max <- max(v[j]).
Definition: Array.cc:194
Array(const Array &other)
void define(const File &file, io::Type default_type) const
Define variables corresponding to an Array in a file opened using file.
Definition: Array.cc:540
virtual void begin_access() const
Checks if an Array is allocated and calls DAVecGetArray.
Definition: Array.cc:646
void shift(double alpha)
Result: v[j] <- v[j] + alpha for all j. Calls VecShift.
Definition: Array.cc:245
const std::vector< double > & levels() const
Definition: Array.cc:140
size_t size() const
Return the total number of elements in the owned part of an array.
Definition: Array.cc:946
void get_from_proc0(petsc::Vec &onp0)
Gets a local Array2 from processor 0.
Definition: Array.cc:1095
void * m_array
Definition: Array.hh:278
void write(const std::string &filename) const
Definition: Array.cc:800
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.
Definition: Array.cc:267
const std::string & get_name() const
Get the name of an Array object.
Definition: Array.cc:383
virtual ~Array()
Definition: Array.cc:105
petsc::Vec & vec() const
Definition: Array.cc:339
uint64_t fletcher64_serial() const
Definition: Array.cc:1112
void get_dof(std::shared_ptr< petsc::DM > da_result, petsc::Vec &result, unsigned int start, unsigned int count=1) const
Definition: Array.cc:277
void scale(double alpha)
Result: v <- v * alpha. Calls VecScale.
Definition: Array.cc:253
void print_checksum(const char *prefix="", bool serial=false) const
Definition: Array.cc:1198
int state_counter() const
Get the object state counter.
Definition: Array.cc:128
std::vector< int > shape() const
Definition: Array.cc:160
std::string checksum(bool serial) const
Definition: Array.cc:1189
void view(std::vector< std::shared_ptr< petsc::Viewer > > viewers) const
View a 2D vector field using existing PETSc viewers.
Definition: Array.cc:1205
std::shared_ptr< const Grid > grid() const
Definition: Array.cc:132
void set(double c)
Result: v[j] <- c for all j.
Definition: Array.cc:707
void set_dof(std::shared_ptr< petsc::DM > da_source, petsc::Vec &source, unsigned int start, unsigned int count=1)
Definition: Array.cc:302
Array & operator=(const Array &)
void inc_state_counter()
Increment the object state counter.
Definition: Array.cc:151
std::shared_ptr< petsc::DM > dm() const
Definition: Array.cc:353
unsigned int ndims() const
Returns the number of spatial dimensions.
Definition: Array.cc:156
void regrid(const std::string &filename, io::Default default_value)
Definition: Array.cc:814
std::shared_ptr< petsc::Vec > allocate_proc0_copy() const
Definition: Array.cc:963
uint64_t fletcher64() const
Definition: Array.cc:1144
void put_on_proc0(petsc::Vec &onp0) const
Puts a local array::Scalar on processor 0.
Definition: Array.cc:1052
void set_begin_access_use_dof(bool flag)
Definition: Array.cc:175
void add(double alpha, const Array &x)
Result: v <- v + alpha * x. Calls VecAXPY.
Definition: Array.cc:235
std::vector< double > norm(int n) const
Computes the norm of all the components of an Array.
Definition: Array.cc:746
void update_ghosts()
Updates ghost points.
Definition: Array.cc:693
unsigned int stencil_width() const
Get the stencil width of the current Array. Returns 0 if ghosts are not available.
Definition: Array.cc:331
void checkCompatibility(const char *function, const Array &other) const
Checks if two Arrays have compatible sizes, dimensions and numbers of degrees of freedom.
Definition: Array.cc:623
void read_impl(const File &file, unsigned int time)
Reads appropriate NetCDF variable(s) into an Array.
Definition: Array.cc:493
void check_array_indices(int i, int j, unsigned int k) const
Check array indices and warn if they are out of range.
Definition: Array.cc:714
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
Definition: Array.cc:553
Abstract class for reading, writing, allocating, and accessing a DA-based PETSc Vec (2D and 3D fields...
Definition: Array.hh:208
#define PISM_ERROR_LOCATION
#define n
Definition: exactTestM.c:37
Kind
What "kind" of a vector to create: with or without ghosts.
Definition: Array.hh:62
@ WITH_GHOSTS
Definition: Array.hh:62
@ WITHOUT_GHOSTS
Definition: Array.hh:62
T interpolate(const F &field, double x, double y)
Definition: Array.hh:82
static std::shared_ptr< T > cast(std::shared_ptr< Array > input)
std::dynamic_pointer_cast wrapper that checks if the cast succeeded.
Definition: Array.hh:318
static double F(double SL, double B, double H, double alpha)
InterpolationType
static const double k
Definition: exactTestP.cc:42
void convert_vec(petsc::Vec &v, units::System::Ptr system, const std::string &spec1, const std::string &spec2)
Definition: Array.cc:1262
int count
Definition: test_cube.c:16