Loading [MathJax]/extensions/tex2jax.js
PISM, A Parallel Ice Sheet Model 2.2.2-d6b3a29ca committed by Constantine Khrulev on 2025-03-28
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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/fem/Element.hh"
27
28namespace pism {
29namespace 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
41
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
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
100void 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
113void 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
122void 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
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
196void 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
218void 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
284
285} // end of namespace fem
286} // end of namespace pism
Describes the PISM grid and the distribution of data across processors.
Definition Grid.hh:290
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:589
virtual void begin_access() const
Checks if an Array is allocated and calls DAVecGetArray.
Definition Array.cc:568
std::shared_ptr< const Grid > grid() const
Definition Array.cc:131
Abstract class for reading, writing, allocating, and accessing a DA-based PETSc Vec (2D and 3D fields...
Definition Array.hh:207
void enforce_homogeneous(const Element2 &element, double *x_e)
void fix_residual_homogeneous(double **r_global)
const array::Scalar * m_values
void fix_residual(double const *const *x_global, double **r_global)
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 *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:221
void nodal_values(const array::Scalar &x_global, int *result) const
Get nodal values of an integer mask.
Definition Element.cc:185
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:227
int n_chi() const
Definition Element.hh:65
#define PISM_CHK(errcode, name)
const int n_chi
Definition FEM.hh:191
static Vector3 row(const double A[3][3], size_t k)
Definition Element.cc:47
static const double k
Definition exactTestP.cc:42
void handle_fatal_errors(MPI_Comm com)