24 #include <gsl/gsl_interp.h>
32 #include "pism/util/io/File.hh"
33 #include "pism/util/Vars.hh"
34 #include "pism/util/Logger.hh"
35 #include "pism/util/projection.hh"
36 #include "pism/pism_config.hh"
37 #include "pism/util/Context.hh"
38 #include "pism/util/petscwrappers/DM.hh"
50 Impl(std::shared_ptr<const Context> context);
52 std::shared_ptr<petsc::DM>
create_dm(
int da_dof,
int stencil_width)
const;
54 const std::vector<unsigned int> &
procs_y);
58 std::shared_ptr<const Context>
ctx;
76 std::vector<double>
x;
78 std::vector<double>
y;
80 std::vector<double>
z;
104 std::map<int,std::weak_ptr<petsc::DM> >
dms;
124 : ctx(context), mapping_info(
"mapping", ctx->unit_system()) {
130 if (keyword ==
"none") {
134 if (keyword ==
"x") {
138 if (keyword ==
"y") {
142 if (keyword ==
"xy") {
147 "grid periodicity type '%s' is invalid.",
168 if (keyword ==
"quadratic") {
170 }
else if (keyword ==
"equal") {
190 if (keyword ==
"center") {
192 }
else if (keyword ==
"corner") {
214 double Lx,
double Ly,
215 double x0,
double y0,
216 unsigned int Mx,
unsigned int My,
230 double Lz =
ctx->config()->get_number(
"grid.Lz");
274 int stencil_width = (int)context->config()->get_number(
"grid.max_stencil_width");
277 std::shared_ptr<petsc::DM> tmp = this->
get_dm(1, stencil_width);
279 e.
add_context(
"distributing a %d x %d grid across %d processors.",
306 const std::string &filename,
307 const std::vector<std::string> &var_names,
312 for (
const auto &name : var_names) {
319 " Cannot initialize the grid.",
321 join(var_names,
",").c_str());
327 const std::string &var_name,
337 if (p.
z.size() < 2) {
338 double Lz =
ctx->config()->get_number(
"grid.Lz");
340 "WARNING: Can't determine vertical grid information using '%s' in %s'\n"
341 " Using 2 levels and Lz of %3.3fm\n",
342 var_name.c_str(), file.
filename().c_str(),
Lz);
352 e.
add_context(
"initializing computational grid from variable \"%s\" in \"%s\"",
353 var_name.c_str(), file.
filename().c_str());
361 #if (Pism_USE_PIO==1)
363 int ierr = PIOc_freedecomp(
m_impl->
ctx->pio_iosys_id(), p.second);
364 if (ierr != PIO_NOERR) {
365 m_impl->
ctx->log()->message(1,
"Failed to de-allocate a ParallelIO decomposition");
400 if (spacing ==
QUADRATIC and lambda <= 0) {
404 std::vector<double> result(new_Mz);
409 double dz = new_Lz / ((double) new_Mz - 1);
412 for (
unsigned int k=0;
k < new_Mz - 1;
k++) {
413 result[
k] = dz * ((double)
k);
415 result[new_Mz - 1] = new_Lz;
420 for (
unsigned int k=0;
k < new_Mz - 1;
k++) {
421 const double zeta = ((double)
k) / ((double) new_Mz - 1);
422 result[
k] = new_Lz * ((zeta / lambda) * (1.0 + (lambda - 1.0) * zeta));
424 result[new_Mz - 1] = new_Lz;
437 const double eps = 1.0e-6;
438 if (height < 0.0 - eps) {
440 " (height must be non-negative)\n", height);
443 if (height >
Lz() + eps) {
445 " grid Lz = %5.4f\n", height,
Lz());
453 unsigned int &Nx,
unsigned int &Ny) {
459 Nx = (
unsigned int)(0.5 + sqrt(((
double)Mx)*((
double)size)/((
double)My)));
468 if (Nx*Ny == (
unsigned int)size) {
474 if (Mx > My and Nx < Ny) {
498 std::vector<unsigned int> result(Nx);
500 for (
unsigned int i=0; i < Nx; i++) {
501 result[i] = Mx / Nx + ((Mx % Nx) > i);
508 const std::vector<unsigned int> &input_procs_y) {
509 if (input_procs_x.size() * input_procs_y.size() != (
size_t)
size) {
513 procs_x.resize(input_procs_x.size());
514 for (
unsigned int k = 0;
k < input_procs_x.size(); ++
k) {
518 procs_y.resize(input_procs_y.size());
519 for (
unsigned int k = 0;
k < input_procs_y.size(); ++
k) {
525 std::vector<unsigned int>
x,
y;
535 unsigned int Nx_default, Ny_default;
539 options::Integer Nx(
"-Nx",
"Number of processors in the x direction", Nx_default);
540 options::Integer Ny(
"-Ny",
"Number of processors in the y direction", Ny_default);
554 if (Nx * Ny != (
int)
size) {
562 if (procs_x.is_set()) {
563 if (procs_x->size() != (
unsigned int)Nx) {
567 result.
x.resize(procs_x->size());
568 for (
unsigned int k = 0;
k < procs_x->size(); ++
k) {
569 result.
x[
k] = procs_x[
k];
576 if (procs_y.is_set()) {
577 if (procs_y->size() != (
unsigned int)Ny) {
581 result.
y.resize(procs_y->size());
582 for (
unsigned int k = 0;
k < procs_y->size(); ++
k) {
583 result.
y[
k] = procs_y[
k];
589 if (result.
x.size() * result.
y.size() !=
size) {
599 return 2.0 * half_width / M;
601 return 2.0 * half_width / (M - 1);
607 double v_min,
double v_max,
608 bool cell_centered) {
609 std::vector<double> result(M);
615 for (
unsigned int i = 0; i < M; ++i) {
616 result[i] = v_min + (i + 0.5) * delta;
618 result[M - 1] = v_max - 0.5*delta;
620 for (
unsigned int i = 0; i < M; ++i) {
621 result[i] = v_min + i * delta;
623 result[M - 1] = v_max;
676 log.
message(2,
"computational domain and grid:\n");
682 " grid size %d x %d x %d\n",
687 " spatial domain %.2f km x %.2f km x %.2f m\n",
688 km(2*
Lx()), km(2*
Ly()),
Lz());
691 if ((
dx() &&
dy()) > 1000.) {
693 " horizontal grid cell %.2f km x %.2f km\n",
697 " horizontal grid cell %.0f m x %.0f m\n",
702 " vertical spacing in ice dz = %.3f m (equal spacing)\n",
706 " vertical spacing in ice uneven, %d levels, %.3f m < dz < %.3f m\n",
713 " IceGrid parameters:\n");
715 " Lx = %6.2f km, Ly = %6.2f km, Lz = %6.2f m, \n",
716 km(
Lx()), km(
Ly()),
Lz());
718 " x0 = %6.2f km, y0 = %6.2f km, (coordinates of center)\n",
721 " Mx = %d, My = %d, Mz = %d, \n",
724 " dx = %6.3f km, dy = %6.3f km, \n",
727 " Nx = %d, Ny = %d\n",
731 " Registration: %s\n",
734 " Periodicity: %s\n",
740 " REALLY verbose output on IceGrid:\n");
742 " vertical levels in ice (Mz=%d, Lz=%5.4f): ",
Mz(),
Lz());
743 for (
unsigned int k=0;
k <
Mz();
k++) {
771 int &i_left,
int &i_right,
772 int &j_bottom,
int &j_top)
const {
776 i_right = i_left + 1;
777 j_top = j_bottom + 1;
793 int i_left, i_right, j_bottom, j_top;
795 return {i_left, i_right, j_bottom, j_top};
802 int i_left = 0, i_right = 0, j_bottom = 0, j_top = 0;
804 double alpha = 0.0, beta = 0.0;
808 if (i_left != i_right) {
813 if (j_bottom != j_top) {
818 return {(1.0 - alpha) * (1.0 - beta),
819 alpha * (1.0 - beta),
821 (1.0 - alpha) * beta};
825 static int dm_hash(
int dm_dof,
int stencil_width) {
828 "Invalid dm_dof argument: %d", dm_dof);
833 "Invalid stencil_width argument: %d", stencil_width);
842 std::shared_ptr<petsc::DM> result;
844 int j =
dm_hash(da_dof, stencil_width);
874 ctx->log()->message(3,
875 "* Creating a DM with dof=%d and stencil_width=%d...\n",
876 da_dof, stencil_width);
879 PetscErrorCode ierr = DMDACreate2d(
ctx->com(),
880 DM_BOUNDARY_PERIODIC, DM_BOUNDARY_PERIODIC,
883 (PetscInt)procs_x.size(),
884 (PetscInt)procs_y.size(),
885 da_dof, stencil_width,
886 &procs_x[0], &procs_y[0],
890 #if PETSC_VERSION_GE(3,8,0)
891 ierr = DMSetUp(result);
PISM_CHK(ierr,
"DMSetUp");
894 return std::shared_ptr<petsc::DM>(
new petsc::DM(result));
998 double result =
m_impl->
z.back();
999 for (
unsigned int k = 0;
k <
m_impl->
z.size() - 1; ++
k) {
1008 double result = 0.0;
1009 for (
unsigned int k = 0;
k <
m_impl->
z.size() - 1; ++
k) {
1043 return sqrt(grid.
x(i) * grid.
x(i) + grid.
y(j) * grid.
y(j));
1076 " x: %5d points, [%10.3f, %10.3f] km, x0 = %10.3f km, Lx = %10.3f km\n",
1078 km(this->
x0 - this->
Lx),
1079 km(this->
x0 + this->
Lx),
1084 " y: %5d points, [%10.3f, %10.3f] km, y0 = %10.3f km, Ly = %10.3f km\n",
1086 km(this->
y0 - this->
Ly),
1087 km(this->
y0 + this->
Ly),
1092 " z: %5d points, [%10.3f, %10.3f] m\n",
1093 this->z_len, this->z_min, this->z_max);
1096 " t: %5d points, last time = %.3f years\n\n",
1111 if (not var.exists) {
1117 for (
auto dimension_name : dimensions) {
1125 this->x_len = this->
x.size();
1129 this->
x0 = 0.5 * (x_min + x_max);
1130 this->
Lx = 0.5 * (x_max - x_min);
1132 const double dx = this->
x[1] - this->
x[0];
1133 this->
Lx += 0.5 *
dx;
1140 this->y_len = this->
y.size();
1144 this->
y0 = 0.5 * (y_min + y_max);
1145 this->
Ly = 0.5 * (y_max - y_min);
1147 const double dy = this->
y[1] - this->
y[0];
1148 this->
Ly += 0.5 *
dy;
1155 this->z_len = this->
z.size();
1169 "can't figure out which direction dimension '%s' corresponds to.",
1170 dimension_name.c_str());
1174 }
catch (RuntimeError &e) {
1175 e.add_context(
"getting grid information using variable '%s' in '%s'", variable.c_str(),
1198 init_from_config(config);
1209 Lx = config->get_number(
"grid.Lx");
1210 Ly = config->get_number(
"grid.Ly");
1215 Mx = config->get_number(
"grid.Mx");
1216 My = config->get_number(
"grid.My");
1221 double Lz = config->get_number(
"grid.Lz");
1222 unsigned int Mz = config->get_number(
"grid.Mz");
1223 double lambda = config->get_number(
"grid.lambda");
1231 const std::string &variable_name,
1234 MPI_Comm_size(
ctx->com(), &
size);
1237 init_from_config(
ctx->config());
1239 grid_info input_grid(file, variable_name,
ctx->unit_system(), r);
1253 const std::string &variable_name,
1255 init_from_file(
ctx, file, variable_name, r);
1259 const std::string &filename,
1260 const std::string &variable_name,
1263 init_from_file(
ctx, file, variable_name, r);
1276 "-Lx",
"Half of the grid extent in the Y direction, in km",
1278 Ly = 1000.0 *
options::Real(unit_system,
"-Ly",
"Half of the grid extent in the X direction, in km",
1287 if (x_range.is_set() and y_range.is_set()) {
1288 if (x_range->size() != 2 or y_range->size() != 2) {
1291 x0 = (x_range[0] + x_range[1]) / 2.0;
1292 y0 = (y_range[0] + y_range[1]) / 2.0;
1293 Lx = (x_range[1] - x_range[0]) / 2.0;
1294 Ly = (y_range[1] - y_range[0]) / 2.0;
1300 double Lz =
z.size() > 0 ?
z.back() : config->get_number(
"grid.Lz");
1301 int Mz =
z.size() > 0 ?
z.size() : config->get_number(
"grid.Mz");
1302 double lambda = config->get_number(
"grid.lambda");
1333 if (
z.back() < 0.0) {
1337 if (std::accumulate(procs_x.begin(), procs_x.end(), 0.0) !=
Mx) {
1341 if (std::accumulate(procs_y.begin(), procs_y.end(), 0.0) !=
My) {
1350 auto config =
ctx->config();
1352 auto input_file = config->get_string(
"input.file");
1353 bool bootstrap = config->get_flag(
"input.bootstrap");
1359 if (not input_file.empty() and (not bootstrap)) {
1362 }
else if (not input_file.empty() and bootstrap) {
1368 bool grid_info_found =
false;
1372 for (
auto name : {
"land_ice_thickness",
"bedrock_altitude",
"thk",
"topg"}) {
1375 if (not grid_info_found) {
1381 if (grid_info_found) {
1387 if (not grid_info_found) {
1389 input_file.c_str());
1406 " setting computational box for ice from '%s' and\n"
1407 " user options: [%6.2f km, %6.2f km] x [%6.2f km, %6.2f km] x [0 m, %6.2f m]\n",
1409 km(result->x0() - result->Lx()),
1410 km(result->x0() + result->Lx()),
1411 km(result->y0() - result->Ly()),
1412 km(result->y0() + result->Ly()),
1440 #if (Pism_USE_PIO==1)
1441 static int pio_decomp_hash(
int dof,
int output_datatype) {
1444 "Invalid dof argument: %d", dof);
1449 return NC_FIRSTUSERTYPEID * dof + output_datatype;
1461 #if (Pism_USE_PIO==1)
1463 int hash = pio_decomp_hash(dof, output_datatype);
1468 int ndims = dof < 2 ? 2 : 3;
1471 std::vector<int> gdimlen{(int)
My(), (int)
Mx(), dof};
1472 std::vector<long int> start{
ys(),
xs(), 0},
count{
ym(),
xm(), dof};
1474 int stat = PIOc_InitDecomp_bc(
m_impl->
ctx->pio_iosys_id(),
1475 output_datatype, ndims, gdimlen.data(),
1476 start.data(),
count.data(), &result);
1478 if (stat != PIO_NOERR) {
1480 "Failed to create a ParallelIO I/O decomposition");
1486 (void) output_datatype;
std::shared_ptr< const Config > ConstPtr
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
unsigned int dimension_length(const std::string &name) const
Get the length of a dimension.
std::vector< double > read_dimension(const std::string &name) const
Get dimension data (a coordinate variable).
std::vector< std::string > dimensions(const std::string &variable_name) const
High-level PISM I/O class.
void init_from_file(std::shared_ptr< const Context > ctx, const File &file, const std::string &variable_name, GridRegistration r)
double x0
Domain center in the X direction.
void ownership_ranges_from_options(unsigned int size)
Re-compute ownership ranges. Uses current values of Mx and My.
std::vector< unsigned int > procs_y
Processor ownership ranges in the Y direction.
void horizontal_extent_from_options(std::shared_ptr< units::System > unit_system)
Process -Lx, -Ly, -x0, -y0, -x_range, -y_range; set Lx, Ly, x0, y0.
double Ly
Domain half-width in the Y direction.
Periodicity periodicity
Grid periodicity.
std::vector< double > z
Vertical levels.
GridRegistration registration
Grid registration.
double Lx
Domain half-width in the X direction.
void init_from_config(std::shared_ptr< const Config > config)
Initialize from a configuration database. Does not try to compute ownership ranges.
GridParameters()
Create an uninitialized GridParameters instance.
double y0
Domain center in the Y direction.
void vertical_grid_from_options(std::shared_ptr< const Config > config)
Process -Mz and -Lz; set z;.
unsigned int Mx
Number of grid points in the X direction.
void validate() const
Validate data members.
std::vector< unsigned int > procs_x
Processor ownership ranges in the X direction.
void horizontal_size_from_options()
Process -Mx and -My; set Mx and My.
unsigned int My
Number of grid points in the Y direction.
Grid parameters; used to collect defaults before an IceGrid is allocated.
const std::vector< double > & y() const
Y-coordinates.
IceGrid(std::shared_ptr< const Context > ctx, const GridParameters &p)
Create a PISM distributed computational grid.
double y0() const
Y-coordinate of the center of the domain.
GridRegistration registration() const
Vars & variables()
Dictionary of variables (2D and 3D fields) associated with this grid.
int rank() const
MPI rank.
Periodicity periodicity() const
Return grid periodicity.
double Lx() const
Half-width of the computational domain.
static const int max_dm_dof
Maximum number of degrees of freedom supported by PISM.
const std::vector< double > & x() const
X-coordinates.
int ys() const
Global starting index of this processor's subset.
std::shared_ptr< IceGrid > Ptr
unsigned int Mx() const
Total grid size in the X direction.
static Ptr FromOptions(std::shared_ptr< const Context > ctx)
Create a grid using command-line options and (possibly) an input file.
std::vector< double > compute_interp_weights(double x, double y) const
Compute 4 interpolation weights necessary for linear interpolation from the current grid....
double x0() const
X-coordinate of the center of the domain.
unsigned int Mz() const
Number of vertical levels.
static Ptr Shallow(std::shared_ptr< const Context > ctx, double Lx, double Ly, double x0, double y0, unsigned int Mx, unsigned int My, GridRegistration r, Periodicity p)
Initialize a uniform, shallow (3 z-levels) grid with half-widths (Lx,Ly) and Mx by My nodes.
int xm() const
Width of this processor's sub-domain.
void set_mapping_info(const MappingInfo &info)
static const int max_stencil_width
Maximum stencil width supported by PISM.
std::shared_ptr< const Context > ctx() const
Return execution context this grid corresponds to.
double dz_max() const
Maximum vertical spacing.
int pio_io_decomposition(int dof, int output_datatype) const
int xs() const
Global starting index of this processor's subset.
unsigned int kBelowHeight(double height) const
Return the index k into zlevels[] so that zlevels[k] <= height < zlevels[k+1] and k < Mz.
double dx() const
Horizontal grid spacing.
double dy() const
Horizontal grid spacing.
const std::vector< double > & z() const
Z-coordinates within the ice.
void compute_point_neighbors(double X, double Y, int &i_left, int &i_right, int &j_bottom, int &j_top) const
Computes indices of grid points to the lower left and upper right from (X,Y).
const MappingInfo & get_mapping_info() const
static Ptr FromFile(std::shared_ptr< const Context > ctx, const File &file, const std::string &var_name, GridRegistration r)
Create a grid from a file, get information from variable var_name.
static std::vector< double > compute_vertical_levels(double new_Lz, unsigned int new_Mz, SpacingType spacing, double Lambda=0.0)
Set the vertical levels in the ice according to values in Mz (number of levels), Lz (domain height),...
std::shared_ptr< petsc::DM > get_dm(int dm_dof, int stencil_width) const
Get a PETSc DM ("distributed array manager") object for given dof (number of degrees of freedom per g...
void report_parameters() const
Report grid parameters.
double Lz() const
Height of the computational domain.
double dz_min() const
Minimum vertical spacing.
int ym() const
Width of this processor's sub-domain.
unsigned int size() const
MPI communicator size.
unsigned int My() const
Total grid size in the Y direction.
double Ly() const
Half-width of the computational domain.
Describes the PISM grid and the distribution of data across processors.
std::shared_ptr< const Logger > ConstPtr
void message(int threshold, const char format[],...) const __attribute__((format(printf
Print a message to the log.
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
A class for passing PISM variables from the core to other parts of the code (such as climate couplers...
double Ly
domain half-height
double Lx
domain half-width
std::vector< double > z
z coordinates
void report(const Logger &log, int threshold, std::shared_ptr< units::System > s) const
double x0
x-coordinate of the domain center
double y0
y-coordinate of the domain center
Contains parameters of an input file grid.
std::shared_ptr< System > Ptr
#define PISM_CHK(errcode, name)
#define PISM_ERROR_LOCATION
double convert(System::Ptr system, double input, const std::string &spec1, const std::string &spec2)
Convert a quantity from unit1 to unit2.
bool is_increasing(const std::vector< double > &a)
Checks if a vector of doubles is strictly increasing.
std::string periodicity_to_string(Periodicity p)
Convert Periodicity to a STL string.
double max(const IceModelVec2S &input)
Finds maximum over all the values in an IceModelVec2S object. Ignores ghosts.
double radius(const IceGrid &grid, int i, int j)
Returns the distance from the point (i,j) to the origin.
static OwnershipRanges compute_ownership_ranges(unsigned int Mx, unsigned int My, unsigned int size)
static void compute_nprocs(unsigned int Mx, unsigned int My, unsigned int size, unsigned int &Nx, unsigned int &Ny)
Computes the number of processors in the X- and Y-directions.
static std::vector< double > compute_coordinates(unsigned int M, double delta, double v_min, double v_max, bool cell_centered)
Compute grid coordinates for one direction (X or Y).
static double compute_horizontal_spacing(double half_width, unsigned int M, bool cell_centered)
Compute horizontal grid spacing. See compute_horizontal_coordinates() for more.
std::string spacing_to_string(SpacingType s)
Convert SpacingType to an STL string.
Periodicity string_to_periodicity(const std::string &keyword)
Convert a string to Periodicity.
double vector_min(const std::vector< double > &input)
std::string registration_to_string(GridRegistration registration)
SpacingType string_to_spacing(const std::string &keyword)
Convert an STL string to SpacingType.
double min(const IceModelVec2S &input)
Finds minimum over all the values in an IceModelVec2S object. Ignores ghosts.
@ PISM_READONLY
open an existing file for reading only
static std::vector< unsigned int > ownership_ranges(unsigned int Mx, unsigned int Nx)
Computes processor ownership ranges corresponding to equal area distribution among processors.
std::string join(const std::vector< std::string > &strings, const std::string &separator)
Concatenate strings, inserting separator between elements.
static int dm_hash(int dm_dof, int stencil_width)
GridRegistration string_to_registration(const std::string &keyword)
double vector_max(const std::vector< double > &input)
unsigned int Mx
number of grid points in the x-direction
unsigned int My
number of grid points in the y-direction
std::shared_ptr< const Context > ctx
double Ly
half width of the ice model grid in y-direction (m)
double Lx
half width of the ice model grid in x-direction (m)
double cell_area
cell area (meters^2)
std::shared_ptr< petsc::DM > dm_scalar_global
std::vector< PetscInt > procs_x
array containing lenghts (in the x-direction) of processor sub-domains
std::vector< double > x
x-coordinates of grid points
gsl_interp_accel * bsearch_accel
GSL binary search accelerator used to speed up kBelowHeight().
void set_ownership_ranges(const std::vector< unsigned int > &procs_x, const std::vector< unsigned int > &procs_y)
Set processor ownership ranges. Takes care of type conversion (unsigned int -> PetscInt).
double dx
horizontal grid spacing
std::map< int, int > io_decompositions
ParallelIO I/O decompositions.
std::shared_ptr< petsc::DM > create_dm(int da_dof, int stencil_width) const
Create a DM with the given number of dof (degrees of freedom per grid point) and stencil width.
double x0
x-coordinate of the grid center
GridRegistration registration
std::vector< PetscInt > procs_y
array containing lenghts (in the y-direction) of processor sub-domains
std::map< int, std::weak_ptr< petsc::DM > > dms
std::vector< double > y
y-coordinates of grid points
std::vector< double > z
vertical grid levels in the ice; correspond to the storage grid
Impl(std::shared_ptr< const Context > context)
double y0
y-coordinate of the grid center
double dy
horizontal grid spacing
void compute_horizontal_coordinates()
Compute horizontal spacing parameters dx and dy and grid coordinates using Mx, My,...
Vars variables
A dictionary with pointers to IceModelVecs, for passing them from the one component to another (e....
Internal structures of IceGrid.
std::vector< unsigned int > y
std::vector< unsigned int > x