PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
DirichletData.cc
Go to the documentation of this file.
1 /* Copyright (C) 2020, 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/util/fem/DirichletData.hh"
21 
22 #include "pism/util/array/Scalar.hh"
23 #include "pism/util/array/Vector.hh"
24 #include "pism/util/Context.hh"
25 #include "pism/util/error_handling.hh"
26 #include "pism/util/Context.hh"
27 
28 namespace pism {
29 namespace fem {
30 
32  : m_indices(NULL), m_weight(1.0) {
33  for (unsigned int k = 0; k < q1::n_chi; ++k) {
34  m_indices_e[k] = 0;
35  }
36 }
37 
39  finish(NULL);
40 }
41 
42 void DirichletData::init(const array::Scalar *indices,
43  const array::Array *values,
44  double weight) {
45  m_weight = weight;
46 
47  if (indices != NULL) {
48  indices->begin_access();
49  m_indices = indices;
50  }
51 
52  if (values != NULL) {
53  values->begin_access();
54  }
55 }
56 
57 void DirichletData::finish(const array::Array *values) {
58  if (m_indices != NULL) {
59  MPI_Comm com = m_indices->grid()->ctx()->com();
60  try {
62  m_indices = NULL;
63  } catch (...) {
65  }
66  }
67 
68  if (values != NULL) {
69  MPI_Comm com = values->grid()->ctx()->com();
70  try {
71  values->end_access();
72  } catch (...) {
74  }
75  }
76 }
77 
78 //! @brief Constrain `element`, i.e. ensure that quadratures do not contribute to Dirichlet nodes by marking corresponding rows and columns as "invalid".
81  auto n_chi = element.n_chi();
82  for (int k = 0; k < n_chi; k++) {
83  if (m_indices_e[k] > 0.5) { // Dirichlet node
84  // Mark any kind of Dirichlet node as not to be touched
85  element.mark_row_invalid(k);
86  element.mark_col_invalid(k);
87  }
88  }
89 }
90 
91 // Scalar version
92 
94  const array::Scalar *values,
95  double weight)
96  : m_values(values) {
97  init(indices, m_values, weight);
98 }
99 
100 void DirichletData_Scalar::enforce(const Element2 &element, double* x_nodal) {
101  assert(m_values != NULL);
102 
104  for (int k = 0; k < element.n_chi(); k++) {
105  if (m_indices_e[k] > 0.5) { // Dirichlet node
106  int i = 0, j = 0;
107  element.local_to_global(k, i, j);
108  x_nodal[k] = (*m_values)(i, j);
109  }
110  }
111 }
112 
113 void DirichletData_Scalar::enforce_homogeneous(const Element2 &element, double* x_nodal) {
115  for (int k = 0; k < element.n_chi(); k++) {
116  if (m_indices_e[k] > 0.5) { // Dirichlet node
117  x_nodal[k] = 0.0;
118  }
119  }
120 }
121 
122 void DirichletData_Scalar::fix_residual(double const *const *const x_global, double **r_global) {
123  assert(m_values != NULL);
124 
125  const Grid &grid = *m_indices->grid();
126 
127  // For each node that we own:
128  for (auto p = grid.points(); p; p.next()) {
129  const int i = p.i(), j = p.j();
130 
131  if ((*m_indices)(i, j) > 0.5) {
132  // Enforce explicit dirichlet data.
133  r_global[j][i] = m_weight * (x_global[j][i] - (*m_values)(i,j));
134  }
135  }
136 }
137 
139  const Grid &grid = *m_indices->grid();
140 
141  // For each node that we own:
142  for (auto p = grid.points(); p; p.next()) {
143  const int i = p.i(), j = p.j();
144 
145  if ((*m_indices)(i, j) > 0.5) {
146  // Enforce explicit dirichlet data.
147  r_global[j][i] = 0.0;
148  }
149  }
150 }
151 
153  const Grid &grid = *m_indices->grid();
154 
155  // Until now, the rows and columns correspoinding to Dirichlet data
156  // have not been set. We now put an identity block in for these
157  // unknowns. Note that because we have takes steps to not touching
158  // these columns previously, the symmetry of the Jacobian matrix is
159  // preserved.
160 
161  const double identity = m_weight;
162  ParallelSection loop(grid.com);
163  try {
164  for (auto p = grid.points(); p; p.next()) {
165  const int i = p.i(), j = p.j();
166 
167  if ((*m_indices)(i, j) > 0.5) {
168  MatStencil row;
169  row.j = j;
170  row.i = i;
171  PetscErrorCode ierr = MatSetValuesBlockedStencil(J, 1, &row, 1, &row, &identity,
172  ADD_VALUES);
173  PISM_CHK(ierr, "MatSetValuesBlockedStencil"); // this may throw
174  }
175  }
176  } catch (...) {
177  loop.failed();
178  }
179  loop.check();
180 }
181 
183  finish(m_values);
184  m_values = NULL;
185 }
186 
187 // Vector version
188 
190  const array::Vector *values,
191  double weight)
192  : m_values(values) {
193  init(indices, m_values, weight);
194 }
195 
196 void DirichletData_Vector::enforce(const Element2 &element, Vector2d* x_nodal) {
197  assert(m_values != NULL);
198 
200  for (int k = 0; k < element.n_chi(); k++) {
201  if (m_indices_e[k] > 0.5) { // Dirichlet node
202  int i = 0, j = 0;
203  element.local_to_global(k, i, j);
204  x_nodal[k] = (*m_values)(i, j);
205  }
206  }
207 }
208 
211  for (int k = 0; k < element.n_chi(); k++) {
212  if (m_indices_e[k] > 0.5) { // Dirichlet node
213  x_nodal[k] = 0.0;
214  }
215  }
216 }
217 
218 void DirichletData_Vector::fix_residual(Vector2d const *const *const x_global, Vector2d **r_global) {
219  assert(m_values != NULL);
220 
221  const Grid &grid = *m_indices->grid();
222 
223  // For each node that we own:
224  for (auto p = grid.points(); p; p.next()) {
225  const int i = p.i(), j = p.j();
226 
227  if ((*m_indices)(i, j) > 0.5) {
228  // Enforce explicit dirichlet data.
229  r_global[j][i] = m_weight * (x_global[j][i] - (*m_values)(i, j));
230  }
231  }
232 }
233 
235  const Grid &grid = *m_indices->grid();
236 
237  // For each node that we own:
238  for (auto p = grid.points(); p; p.next()) {
239  const int i = p.i(), j = p.j();
240 
241  if ((*m_indices)(i, j) > 0.5) {
242  // Enforce explicit dirichlet data.
243  r_global[j][i].u = 0.0;
244  r_global[j][i].v = 0.0;
245  }
246  }
247 }
248 
250  const Grid &grid = *m_indices->grid();
251 
252  // Until now, the rows and columns correspoinding to Dirichlet data
253  // have not been set. We now put an identity block in for these
254  // unknowns. Note that because we have taken steps to avoid touching
255  // these columns previously, the symmetry of the Jacobian matrix is
256  // preserved.
257 
258  const double identity[4] = {m_weight, 0,
259  0, m_weight};
260  ParallelSection loop(grid.com);
261  try {
262  for (auto p = grid.points(); p; p.next()) {
263  const int i = p.i(), j = p.j();
264 
265  if ((*m_indices)(i, j) > 0.5) {
266  MatStencil row;
267  row.j = j;
268  row.i = i;
269  PetscErrorCode ierr = MatSetValuesBlockedStencil(J, 1, &row, 1, &row, identity,
270  ADD_VALUES);
271  PISM_CHK(ierr, "MatSetValuesBlockedStencil"); // this may throw
272  }
273  }
274  } catch (...) {
275  loop.failed();
276  }
277  loop.check();
278 }
279 
281  finish(m_values);
282  m_values = NULL;
283 }
284 
285 } // end of namespace fem
286 } // end of namespace pism
PointsWithGhosts points(unsigned int stencil_width=0) const
Definition: Grid.hh:362
const MPI_Comm com
Definition: Grid.hh:355
Describes the PISM grid and the distribution of data across processors.
Definition: Grid.hh:282
void failed()
Indicates a failure of a parallel section.
This class represents a 2D vector field (such as ice velocity) at a certain grid point.
Definition: Vector2d.hh:29
virtual void end_access() const
Checks if an Array is allocated and calls DAVecRestoreArray.
Definition: Array.cc:667
virtual void begin_access() const
Checks if an Array is allocated and calls DAVecGetArray.
Definition: Array.cc:646
std::shared_ptr< const Grid > grid() const
Definition: Array.cc:132
Abstract class for reading, writing, allocating, and accessing a DA-based PETSc Vec (2D and 3D fields...
Definition: Array.hh:208
void enforce_homogeneous(const Element2 &element, double *x_e)
void fix_residual(double const *const *const x_global, double **r_global)
void fix_residual_homogeneous(double **r_global)
const array::Scalar * m_values
DirichletData_Scalar(const array::Scalar *indices, const array::Scalar *values, double weight=1.0)
void enforce(const Element2 &element, double *x_e)
void fix_residual(Vector2d const *const *const x_global, Vector2d **r_global)
DirichletData_Vector(const array::Scalar *indices, const array::Vector *values, double weight)
void enforce(const Element2 &element, Vector2d *x_e)
void fix_residual_homogeneous(Vector2d **r)
void enforce_homogeneous(const Element2 &element, Vector2d *x_e)
const array::Vector * m_values
double m_indices_e[q1::n_chi]
void finish(const array::Array *values)
void init(const array::Scalar *indices, const array::Array *values, double weight=1.0)
const array::Scalar * m_indices
void constrain(Element2 &element)
Constrain element, i.e. ensure that quadratures do not contribute to Dirichlet nodes by marking corre...
void local_to_global(unsigned int k, int &i, int &j) const
Convert a local degree of freedom index k to a global degree of freedom index (i,j).
Definition: Element.hh:171
void mark_row_invalid(unsigned int k)
Mark that the row corresponding to local degree of freedom k should not be updated when inserting int...
Definition: Element.cc:212
void nodal_values(const array::Scalar &x_global, int *result) const
Get nodal values of an integer mask.
Definition: Element.cc:176
void mark_col_invalid(unsigned int k)
Mark that the column corresponding to local degree of freedom k should not be updated when inserting ...
Definition: Element.cc:218
int n_chi() const
Definition: Element.hh:65
#define PISM_CHK(errcode, name)
const int n_chi
Definition: FEM.hh:177
const int n_chi
Definition: FEM.hh:191
static Vector3 row(const double A[3][3], size_t k)
Definition: Element.cc:46
static int weight(int M_ij, int M_n, double h_ij, double h_n)
static const double k
Definition: exactTestP.cc:42
void handle_fatal_errors(MPI_Comm com)
const int J[]
Definition: ssafd_code.cc:34