PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
LocalInterpCtx.cc
Go to the documentation of this file.
1 // Copyright (C) 2007-2020, 2023 Jed Brown, Ed Bueler and Constantine Khroulev
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 #include <cstddef> // size_t
20 #include <cstring>
21 #include <cstdlib>
22 #include <algorithm> // std::min
23 #include <gsl/gsl_interp.h>
24 #include <memory>
25 #include <vector>
26 
27 #include "IO_Flags.hh"
28 #include "pism/util/io/LocalInterpCtx.hh"
29 #include "pism/util/Grid.hh"
30 
31 #include "pism/util/Context.hh"
32 #include "pism/util/Logger.hh"
33 #include "pism/util/error_handling.hh"
34 #include "pism/util/interpolation.hh"
35 
36 namespace pism {
37 
38 //! Compute start and count for getting a subset of x.
39 /*! Given a grid `x` we find `x_start` and `x_count` so that `[subset_x_min, subset_x_max]` is in
40  * `[x[x_start], x[x_start + x_count]]`.
41  *
42  * `x_start` and `x_count` define the smallest subset of `x` with this property.
43  *
44  * Note that `x_start + x_count <= x.size()` as long as `x` is strictly increasing.
45  *
46  * @param[in] x input grid (defined interpolation domain)
47  * @param[in] subset_x_min minimum `x` of a subset (interpolation range)
48  * @param[in] subset_x_max maxumum `x` of a subset (interpolation range)
49  * @param[out] x_start starting index
50  * @param[out] x_count number of elements required
51  */
52 static void subset_start_and_count(const std::vector<double> &x, double subset_x_min,
53  double subset_x_max, int &x_start, int &x_count) {
54  auto x_size = (int)x.size();
55 
56  x_start = (int)gsl_interp_bsearch(x.data(), subset_x_min, 0, x_size - 1);
57 
58  auto x_end = (int)gsl_interp_bsearch(x.data(), subset_x_max, 0, x_size - 1) + 1;
59 
60  x_end = std::min(x_size - 1, x_end);
61 
62  x_count = x_end - x_start + 1;
63 }
64 
65 //! Construct a local interpolation context.
66 /*!
67  The essential quantities to compute are where each processor should start within the NetCDF file grid
68  (`start[]`) and how many grid points, from the starting place, the processor has. The resulting
69  portion of the grid is stored in array `a` (a field of the `LocalInterpCtx`).
70 
71  We make conservative choices about `start[]` and `count[]`. In particular, the portions owned by
72  processors \e must overlap at one point in the NetCDF file grid, but they \e may overlap more than that
73  (as computed here).
74 
75  Note this constructor doesn't extract new information from the NetCDF file or
76  do communication. The information from the NetCDF file must already be
77  extracted, validly stored in a grid_info structure `input`.
78 
79  The `Grid` is used to determine what ranges of the target arrays (i.e. \c
80  Vecs into which NetCDF information will be interpolated) are owned by each
81  processor.
82 */
83 LocalInterpCtx::LocalInterpCtx(const grid::InputGridInfo &input_grid, const Grid &internal_grid,
84  const std::vector<double> &z_internal, InterpolationType type)
85  : LocalInterpCtx(input_grid, internal_grid, type) {
86 
87  // Z
88  start[Z_AXIS] = 0; // always start at the base
89  count[Z_AXIS] = std::max((int)input_grid.z.size(), 1); // read at least one level
90 
91  if (type == LINEAR or type == NEAREST) {
92  z.reset(new Interpolation(type, input_grid.z, z_internal));
93  } else {
94  throw RuntimeError(PISM_ERROR_LOCATION, "invalid interpolation type in LocalInterpCtx");
95  }
96 }
97 
98 /*!
99  * The two-dimensional version of the interpolation context.
100  */
101 LocalInterpCtx::LocalInterpCtx(const grid::InputGridInfo &input_grid, const Grid &internal_grid,
102  InterpolationType type) {
103 
104  // limits of the processor's part of the target computational domain
105  const double x_min_proc = internal_grid.x(internal_grid.xs()),
106  x_max_proc = internal_grid.x(internal_grid.xs() + internal_grid.xm() - 1),
107  y_min_proc = internal_grid.y(internal_grid.ys()),
108  y_max_proc = internal_grid.y(internal_grid.ys() + internal_grid.ym() - 1);
109 
110  // T
111  start[T_AXIS] = (int)input_grid.t_len - 1; // use the latest time.
112  count[T_AXIS] = 1; // read only one record
113 
114  // X
115  subset_start_and_count(input_grid.x, x_min_proc, x_max_proc, start[X_AXIS], count[X_AXIS]);
116 
117  // Y
118  subset_start_and_count(input_grid.y, y_min_proc, y_max_proc, start[Y_AXIS], count[Y_AXIS]);
119 
120  // Z
121  start[Z_AXIS] = 0;
122  count[Z_AXIS] = 1;
123 
124  if (type == LINEAR or type == NEAREST) {
125  x = std::make_shared<Interpolation>(type, &input_grid.x[start[X_AXIS]], count[X_AXIS],
126  &internal_grid.x()[internal_grid.xs()], internal_grid.xm());
127 
128  y = std::make_shared<Interpolation>(type, &input_grid.y[start[Y_AXIS]], count[Y_AXIS],
129  &internal_grid.y()[internal_grid.ys()], internal_grid.ym());
130 
131  std::vector<double> zz = {0.0};
132  z = std::make_shared<Interpolation>(type, zz, zz);
133  } else {
134  throw RuntimeError(PISM_ERROR_LOCATION, "invalid interpolation type in LocalInterpCtx");
135  }
136 }
137 
138 
140  return count[X_AXIS] * count[Y_AXIS] * std::max(count[Z_AXIS], 1);
141 }
142 
143 
144 } // end of namespace pism
const std::vector< double > & x() const
X-coordinates.
Definition: Grid.cc:766
const std::vector< double > & y() const
Y-coordinates.
Definition: Grid.cc:776
int ys() const
Global starting index of this processor's subset.
Definition: Grid.cc:736
int xs() const
Global starting index of this processor's subset.
Definition: Grid.cc:731
int xm() const
Width of this processor's sub-domain.
Definition: Grid.cc:741
int ym() const
Width of this processor's sub-domain.
Definition: Grid.cc:746
Describes the PISM grid and the distribution of data across processors.
Definition: Grid.hh:282
std::array< int, 4 > count
std::array< int, 4 > start
LocalInterpCtx(const grid::InputGridInfo &input_grid, const Grid &internal_grid, InterpolationType type)
std::shared_ptr< Interpolation > y
std::shared_ptr< Interpolation > z
std::shared_ptr< Interpolation > x
std::vector< double > y
y coordinates
Definition: Grid.hh:88
unsigned int t_len
Definition: Grid.hh:71
std::vector< double > z
z coordinates
Definition: Grid.hh:90
std::vector< double > x
x coordinates
Definition: Grid.hh:86
Contains parameters of an input file grid.
Definition: Grid.hh:65
#define PISM_ERROR_LOCATION
double max(const array::Scalar &input)
Finds maximum over all the values in an array::Scalar object. Ignores ghosts.
Definition: Scalar.cc:165
double min(const array::Scalar &input)
Finds minimum over all the values in an array::Scalar object. Ignores ghosts.
Definition: Scalar.cc:193
@ T_AXIS
Definition: IO_Flags.hh:33
@ X_AXIS
Definition: IO_Flags.hh:33
@ Z_AXIS
Definition: IO_Flags.hh:33
@ Y_AXIS
Definition: IO_Flags.hh:33
InterpolationType
static void subset_start_and_count(const std::vector< double > &x, double subset_x_min, double subset_x_max, int &x_start, int &x_count)
Compute start and count for getting a subset of x.