PISM, A Parallel Ice Sheet Model  stable v2.1.1 committed by Constantine Khrulev on 2024-12-04 13:36:58 -0900
grid_hierarchy.cc
Go to the documentation of this file.
1 /* Copyright (C) 2020, 2021, 2022, 2023 PISM Authors
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 
20 #include "pism/stressbalance/blatter/util/grid_hierarchy.hh"
21 
22 namespace pism {
23 
24 /*!
25  * z coordinates of the nodes
26  *
27  * @param[in] b surface elevation of the bottom of the domain
28  * @param[in] H domain thickness
29  * @param[in] Mz number of grid points in each vertical column
30  * @param[in] k node index in the z direction
31  */
32 double grid_z(double b, double H, int Mz, int k) {
33  return b + H * k / (Mz - 1.0);
34 }
35 
36 /* Transpose a DMDALocalInfo structure to map from PETSc's ordering to PISM's order needed
37  to ensure that vertical columns are stored contiguously in RAM.
38 
39  (What a pain.)
40 
41  Map from PETSc to PISM order:
42 
43  | PETSc | PISM |
44  |-------+------|
45  | x | z |
46  | y | x |
47  | z | y |
48 
49  Assuming that i, j, k indexes correspond to x, y, and z PETSc's indexing order is
50  [k][j][i]. After this transpose we have to use [j][i][k].
51 
52  Note that this indexing order is compatible with the PETSc-standard indexing for 2D
53  Vecs: [j][i].
54 
55  All the lines changed to implement this transpose are marked with STORAGE_ORDER: that
56  way you can use grep to find them.
57  */
58 DMDALocalInfo grid_transpose(const DMDALocalInfo &input) {
59  DMDALocalInfo result = input;
60 
61  result.mx = input.my;
62  result.my = input.mz;
63  result.mz = input.mx;
64 
65  result.xs = input.ys;
66  result.ys = input.zs;
67  result.zs = input.xs;
68 
69  result.xm = input.ym;
70  result.ym = input.zm;
71  result.zm = input.xm;
72 
73  result.gxs = input.gys;
74  result.gys = input.gzs;
75  result.gzs = input.gxs;
76 
77  result.gxm = input.gym;
78  result.gym = input.gzm;
79  result.gzm = input.gxm;
80 
81  result.bx = input.by;
82  result.by = input.bz;
83  result.bz = input.bx;
84 
85  return result;
86 }
87 
88 
89 /*!
90  * Set up storage for 3D data inputs (DMDAs and Vecs)
91  */
92 PetscErrorCode setup_level(DM dm, int mg_levels) {
93  PetscErrorCode ierr;
94 
95  // Create a 3D DMDA and a global Vec, then stash them in dm.
96  {
97  DM da;
98  Vec parameters;
99  int dof = 1;
100 #if PETSC_VERSION_LT(3,10,0)
101  ierr = DMDAGetReducedDMDA(dm, dof, &da); CHKERRQ(ierr);
102 #else
103  ierr = DMDACreateCompatibleDMDA(dm, dof, &da); CHKERRQ(ierr);
104 #endif
105 
106  ierr = DMSetUp(da); CHKERRQ(ierr);
107 
108  ierr = DMCreateGlobalVector(da, &parameters); CHKERRQ(ierr);
109 
110  ierr = PetscObjectCompose((PetscObject)dm, "3D_DM", (PetscObject)da); CHKERRQ(ierr);
111  ierr = PetscObjectCompose((PetscObject)dm, "3D_DM_data", (PetscObject)parameters); CHKERRQ(ierr);
112 
113  ierr = DMDestroy(&da); CHKERRQ(ierr);
114 
115  ierr = VecDestroy(&parameters); CHKERRQ(ierr);
116  }
117 
118  // get coarsening level
119  PetscInt level = 0;
120  ierr = DMGetCoarsenLevel(dm, &level); CHKERRQ(ierr);
121 
122  // report
123  {
124  MPI_Comm comm;
125  ierr = PetscObjectGetComm((PetscObject)dm, &comm); CHKERRQ(ierr);
126 
127  DMDALocalInfo info;
128  ierr = DMDAGetLocalInfo(dm, &info); CHKERRQ(ierr);
129  info = grid_transpose(info);
130 
131  int
132  Mx = info.mx,
133  My = info.my,
134  Mz = info.mz;
135  ierr = PetscPrintf(comm,
136  "Blatter grid level %d: %3d x %3d x %3d (%8d) nodes\n",
137  (mg_levels - 1) - static_cast<int>(level),
138  Mx, My, Mz, Mx * My * Mz); CHKERRQ(ierr);
139  }
140  return 0;
141 }
142 
143 /*! @brief Create the restriction matrix.
144  *
145  * The result of this call is attached to `dm_fine` under `mat_name`.
146  *
147  * @param[in] fine DM corresponding to the fine grid
148  * @param[in] coarse DM corresponding to the coarse grid
149  * @param[in] dm_name name of the DM for 2D or 3D parameters
150  * @param[in] mat_name name to use when attaching the restriction matrix to `fine`
151  */
152 PetscErrorCode create_restriction(DM fine, DM coarse, const char *dm_name) {
153  PetscErrorCode ierr;
154  DM da_fine, da_coarse;
155  Mat mat;
156  Vec scale;
157 
158  std::string
159  prefix = dm_name,
160  mat_name = prefix + "_restriction",
161  vec_name = prefix + "_scaling";
162 
163  /* Get the DM for parameters from the fine grid DM */
164  ierr = PetscObjectQuery((PetscObject)fine, dm_name, (PetscObject *)&da_fine); CHKERRQ(ierr);
165  if (!da_fine) {
166 #if PETSC_VERSION_LT(3,17,0)
167  SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No %s composed with given DMDA", dm_name); // LCOV_EXCL_LINE
168 #else
169  SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No %s composed with given DMDA", dm_name); // LCOV_EXCL_LINE
170 #endif
171  }
172 
173  /* Get the DM for parameters from the coarse grid DM */
174  ierr = PetscObjectQuery((PetscObject)coarse, dm_name, (PetscObject *)&da_coarse); CHKERRQ(ierr);
175  if (!da_coarse) {
176 #if PETSC_VERSION_LT(3,17,0)
177  SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No %s composed with given DMDA", dm_name); // LCOV_EXCL_LINE
178 #else
179  SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No %s composed with given DMDA", dm_name); // LCOV_EXCL_LINE
180 #endif
181  }
182 
183  /* call DMCreateInterpolation */
184  ierr = DMCreateInterpolation(da_coarse, da_fine, &mat, &scale); CHKERRQ(ierr);
185 
186  /* attach to the fine grid DM */
187  ierr = PetscObjectCompose((PetscObject)fine, vec_name.c_str(), (PetscObject)scale); CHKERRQ(ierr);
188  ierr = VecDestroy(&scale); CHKERRQ(ierr);
189 
190  ierr = PetscObjectCompose((PetscObject)fine, mat_name.c_str(), (PetscObject)mat); CHKERRQ(ierr);
191  ierr = MatDestroy(&mat); CHKERRQ(ierr);
192 
193  return 0;
194 }
195 
196 
197 /*! @brief Restrict model parameters from the `fine` grid onto the `coarse` grid.
198  *
199  * This function uses the restriction matrix created by coarsening_hook().
200  */
201 PetscErrorCode restrict_data(DM fine, DM coarse, const char *dm_name) {
202  PetscErrorCode ierr;
203  Vec X_fine, X_coarse, scaling;
204  DM da_fine, da_coarse;
205  Mat mat;
206 
207  std::string
208  prefix = dm_name,
209  mat_name = prefix + "_restriction",
210  scaling_name = prefix + "_scaling",
211  vec_name = prefix + "_data";
212 
213  /* get the restriction matrix from the fine grid DM */
214  ierr = PetscObjectQuery((PetscObject)fine, mat_name.c_str(), (PetscObject *)&mat); CHKERRQ(ierr);
215  if (!mat) {
216  SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Failed to get the restriction matrix"); // LCOV_EXCL_LINE
217  }
218 
219  /* get the scaling vector from the fine grid DM */
220  ierr = PetscObjectQuery((PetscObject)fine, scaling_name.c_str(), (PetscObject *)&scaling); CHKERRQ(ierr);
221  if (!scaling) {
222  SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Failed to get the scaling vector"); // LCOV_EXCL_LINE
223  }
224 
225  /* get the DMDA from the fine grid DM */
226  ierr = PetscObjectQuery((PetscObject)fine, dm_name, (PetscObject *)&da_fine); CHKERRQ(ierr);
227  if (!da_fine) {
228  SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Failed to get the fine grid DM"); // LCOV_EXCL_LINE
229  }
230 
231  /* get the storage vector from the fine grid DM */
232  ierr = PetscObjectQuery((PetscObject)fine, vec_name.c_str(), (PetscObject *)&X_fine); CHKERRQ(ierr);
233  if (!X_fine) {
234  SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Failed to get the fine grid Vec"); // LCOV_EXCL_LINE
235  }
236 
237  /* get the DMDA from the coarse grid DM */
238  ierr = PetscObjectQuery((PetscObject)coarse, dm_name, (PetscObject *)&da_coarse); CHKERRQ(ierr);
239  if (!da_coarse) {
240  SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Failed to get the coarse grid DM"); // LCOV_EXCL_LINE
241  }
242 
243  /* get the storage vector from the coarse grid DM */
244  ierr = PetscObjectQuery((PetscObject)coarse, vec_name.c_str(), (PetscObject *)&X_coarse); CHKERRQ(ierr);
245  if (!X_coarse) {
246  SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Failed to get the coarse grid Vec"); // LCOV_EXCL_LINE
247  }
248 
249  ierr = MatRestrict(mat, X_fine, X_coarse); CHKERRQ(ierr);
250 
251  ierr = VecPointwiseMult(X_coarse, X_coarse, scaling); CHKERRQ(ierr);
252 
253  return 0;
254 }
255 
256 } // end of namespace pism
double grid_z(double b, double H, int Mz, int k)
PetscErrorCode setup_level(DM dm, int mg_levels)
DMDALocalInfo grid_transpose(const DMDALocalInfo &input)
static const double k
Definition: exactTestP.cc:42
PetscErrorCode restrict_data(DM fine, DM coarse, const char *dm_name)
Restrict model parameters from the fine grid onto the coarse grid.
PetscErrorCode create_restriction(DM fine, DM coarse, const char *dm_name)
Create the restriction matrix.