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
Element.cc
Go to the documentation of this file.
1/* Copyright (C) 2020, 2021, 2022, 2023, 2024 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#include <cassert> // assert
20#include <cmath> // std::sqrt()
21
22#include "pism/util/fem/Element.hh"
23#include "pism/util/fem/Quadrature.hh"
24#include "pism/util/Grid.hh"
25#include "pism/util/array/Scalar.hh"
26#include "pism/util/error_handling.hh"
27#include "pism/util/petscwrappers/DM.hh"
28
29namespace pism {
30namespace fem {
31
32//! Determinant of a 3x3 matrix
33static double det(const double a[3][3]) {
34 return (a[0][0] * (a[1][1] * a[2][2] - a[1][2] * a[2][1]) -
35 a[0][1] * (a[1][0] * a[2][2] - a[1][2] * a[2][0]) +
36 a[0][2] * (a[1][0] * a[2][1] - a[1][1] * a[2][0]));
37}
38
39//! Cross product of two 3D vectors
40static Vector3 cross(const Vector3 &a, const Vector3 &b) {
41 return {a.y * b.z - a.z * b.y,
42 a.z * b.x - a.x * b.z,
43 a.x * b.y - a.y * b.x};
44}
45
46// extract a row of a 3x3 matrix
47static Vector3 row(const double A[3][3], size_t k) {
48 return {A[k][0], A[k][1], A[k][2]};
49}
50
51// extract a column of a 3x3 matrix
52static Vector3 column(const double A[3][3], size_t k) {
53 return {A[0][k], A[1][k], A[2][k]};
54}
55
56// dot product of a vector and a [dx, dy, dz] vector in Germ
57static double dot(const Vector3 &v, const Germ &a) {
58 return a.dx * v.x + a.dy * v.y + a.dz + v.z;
59}
60
61//! Invert a 3x3 matrix
62static void invert(const double A[3][3], double result[3][3]) {
63 const double det_A = det(A);
64
65 assert(det_A != 0.0);
66
68 x0 = column(A, 0),
69 x1 = column(A, 1),
70 x2 = column(A, 2),
71 a = cross(x1, x2),
72 b = cross(x2, x0),
73 c = cross(x0, x1);
74
75 double A_cofactor[3][3] = {{a.x, a.y, a.z},
76 {b.x, b.y, b.z},
77 {c.x, c.y, c.z}};
78
79 // inverse(A) = 1/det(A) * transpose(A_cofactor)
80 for (int i = 0; i < 3; ++i) {
81 for (int j = 0; j < 3; ++j) {
82 // note the transpose on the RHS
83 result[i][j] = A_cofactor[j][i] / det_A;
84 }
85 }
86}
87
88//! Compute derivatives with respect to x,y using J^{-1} and derivatives with respect to xi, eta.
89static Germ multiply(const double A[3][3], const Germ &v) {
90 // FIXME: something is not right here
91 return {v.val,
92 dot(row(A, 0), v),
93 dot(row(A, 1), v),
94 dot(row(A, 2), v)};
95}
96
97static void set_to_identity(double A[3][3]) {
98 A[0][0] = 1.0;
99 A[0][1] = 0.0;
100 A[0][2] = 0.0;
101 A[1][0] = 0.0;
102 A[1][1] = 1.0;
103 A[1][2] = 0.0;
104 A[2][0] = 0.0;
105 A[2][1] = 0.0;
106 A[2][2] = 1.0;
107}
109Element::Element(const Grid &grid, int Nq, int n_chi, int block_size)
110 : m_n_chi(n_chi),
111 m_Nq(Nq),
112 m_block_size(block_size) {
113
114 assert(m_n_chi > 0);
115 assert(m_Nq >= 1);
116 assert(m_block_size >= 1);
117
118 // get sub-domain information from the grid:
119 auto da = grid.get_dm(1, 0); // dof = 1, stencil_width = 0
120 PetscErrorCode ierr = DMDAGetLocalInfo(*da, &m_grid);
121 if (ierr != 0) {
122 throw std::runtime_error("Failed to allocate an Element instance");
123 }
124 // reset da: we don't want to end up depending on it
125 m_grid.da = NULL;
126
127 m_germs.resize(Nq * n_chi);
128 m_row.resize(block_size);
129 m_col.resize(block_size);
130}
131
132Element::Element(const DMDALocalInfo &grid_info, int Nq, int n_chi, int block_size)
133 : m_n_chi(n_chi),
134 m_Nq(Nq),
135 m_block_size(block_size) {
136
137 assert(m_n_chi > 0);
138 assert(m_Nq >= 1);
139 assert(m_block_size >= 1);
140
141 m_grid = grid_info;
142 // reset da: we don't want to end up depending on it
143 m_grid.da = NULL;
144
145 m_germs.resize(Nq * n_chi);
146 m_row.resize(block_size);
147 m_col.resize(block_size);
148}
149
150//! Initialize shape function values and quadrature weights of a 2D physical element.
151/** Assumes that the Jacobian does not depend on coordinates of the current quadrature point.
152 */
153void Element::initialize(const double J[3][3],
154 ShapeFunction f,
155 unsigned int n_chi,
156 const std::vector<QuadPoint>& points,
157 const std::vector<double>& W) {
158
159 double J_inv[3][3];
160 invert(J, J_inv);
161
162 for (unsigned int q = 0; q < m_Nq; q++) {
163 for (unsigned int k = 0; k < n_chi; k++) {
164 m_germs[q * m_n_chi + k] = multiply(J_inv, f(k, points[q]));
165 }
166 }
167
168 m_weights.resize(m_Nq);
169 const double J_det = det(J);
170 for (unsigned int q = 0; q < m_Nq; q++) {
171 m_weights[q] = J_det * W[q];
172 }
173}
174
175Element2::Element2(const Grid &grid, int Nq, int n_chi, int block_size)
176 : Element(grid, Nq, n_chi, block_size) {
177 // empty
178}
179
180Element2::Element2(const DMDALocalInfo &grid_info, int Nq, int n_chi, int block_size)
181 : Element(grid_info, Nq, n_chi, block_size) {
182 // empty
183}
184
185void Element2::nodal_values(const array::Scalar &x_global, int *result) const {
186 for (unsigned int k = 0; k < m_n_chi; ++k) {
187 const int
188 ii = m_i + m_i_offset[k],
189 jj = m_j + m_j_offset[k];
190 result[k] = floor(x_global(ii, jj) + 0.5);
191 }
192}
193
194/*!@brief Initialize the Element to element (`i`, `j`) for the purposes of inserting into
195 global residual and Jacobian arrays. */
196void Element2::reset(int i, int j) {
197 m_i = i;
198 m_j = j;
199
200 for (unsigned int k = 0; k < m_n_chi; ++k) {
201 m_col[k].i = i + m_i_offset[k];
202 m_col[k].j = j + m_j_offset[k];
203 m_col[k].k = 0;
204 m_col[k].c = 0;
205 }
206 m_row = m_col;
207
208 // We never sum into rows that are not owned by the local rank.
209 for (unsigned int k = 0; k < m_n_chi; k++) {
210 int pism_i = 0, pism_j = 0;
211 local_to_global(k, pism_i, pism_j);
212 if (pism_i < m_grid.xs or m_grid.xs + m_grid.xm - 1 < pism_i or
213 pism_j < m_grid.ys or m_grid.ys + m_grid.ym - 1 < pism_j) {
215 }
216 }
217}
218
219/*!@brief Mark that the row corresponding to local degree of freedom `k` should not be updated
220 when inserting into the global residual or Jacobian arrays. */
221void Element::mark_row_invalid(unsigned int k) {
222 m_row[k].i = m_row[k].j = m_row[k].k = m_invalid_dof;
223}
224
225/*!@brief Mark that the column corresponding to local degree of freedom `k` should not be updated
226 when inserting into the global Jacobian arrays. */
227void Element::mark_col_invalid(unsigned int k) {
228 m_col[k].i = m_col[k].j = m_col[k].k = m_invalid_dof;
229}
230
231//! Add the contributions of an element-local Jacobian to the global Jacobian matrix.
232/*! The element-local Jacobian should be given as a row-major array of
233 * Nk*Nk values in the scalar case or (2Nk)*(2Nk) values in the
234 * vector valued case.
235 *
236 * Note that MatSetValuesBlockedStencil ignores negative indexes, so
237 * values in K corresponding to locations marked using
238 * mark_row_invalid() and mark_col_invalid() are ignored. (Just as they
239 * should be.)
240 */
241void Element::add_contribution(const double *K, Mat J) const {
242 PetscErrorCode ierr = MatSetValuesBlockedStencil(J,
243 m_block_size, m_row.data(),
244 m_block_size, m_col.data(),
245 K, ADD_VALUES);
246 PISM_CHK(ierr, "MatSetValuesBlockedStencil");
247}
248
249Q1Element2::Q1Element2(const Grid &grid, const Quadrature &quadrature)
250 : Element2(grid, quadrature.weights().size(), q1::n_chi, q1::n_chi) {
251
252 double dx = grid.dx();
253 double dy = grid.dy();
254
255 m_i_offset = {0, 1, 1, 0};
256 m_j_offset = {0, 0, 1, 1};
257
258 // south, east, north, west
259 m_normals = {{0.0, -1.0}, {1.0, 0.0}, {0.0, 1.0}, {-1.0, 0.0}};
260
261 m_side_lengths = {dx, dy, dx, dy};
262
263 // compute the Jacobian
264
265 double J[3][3];
267 J[0][0] = 0.5 * dx;
268 J[0][1] = 0.0;
269 J[1][0] = 0.0;
270 J[1][1] = 0.5 * dy;
271
272 // initialize germs and quadrature weights for the quadrature on this physical element
273 initialize(J, q1::chi, q1::n_chi, quadrature.points(), quadrature.weights());
274 reset(0, 0);
275}
276
277Q1Element2::Q1Element2(const DMDALocalInfo &grid_info,
278 double dx,
279 double dy,
280 const Quadrature &quadrature)
281 : Element2(grid_info, quadrature.weights().size(), q1::n_chi, q1::n_chi) {
282
283 m_i_offset = {0, 1, 1, 0};
284 m_j_offset = {0, 0, 1, 1};
285
286 // south, east, north, west
287 m_normals = {{0.0, -1.0}, {1.0, 0.0}, {0.0, 1.0}, {-1.0, 0.0}};
288
289 m_side_lengths = {dx, dy, dx, dy};
290
291 // compute the Jacobian
292
293 double J[3][3];
295 J[0][0] = 0.5 * dx;
296 J[0][1] = 0.0;
297 J[1][0] = 0.0;
298 J[1][1] = 0.5 * dy;
299
300 // initialize germs and quadrature weights for the quadrature on this physical element
301 initialize(J, q1::chi, q1::n_chi, quadrature.points(), quadrature.weights());
302 reset(0, 0);
303}
304
305P1Element2::P1Element2(const Grid &grid, const Quadrature &quadrature, int type)
306 : Element2(grid, quadrature.weights().size(), p1::n_chi, q1::n_chi) {
307
308 double dx = grid.dx();
309 double dy = grid.dy();
310
311 // outward pointing normals for all sides of a Q1 element with sides aligned with X and
312 // Y axes
313 const Vector2d
314 n01( 0.0, -1.0), // south
315 n12( 1.0, 0.0), // east
316 n23( 0.0, 1.0), // north
317 n30(-1.0, 0.0); // west
318
319 // "diagonal" sides
321 n13( 1.0, dx / dy), // 1-3 diagonal, outward for element 0
322 n20(-1.0, dx / dy); // 2-0 diagonal, outward for element 1
323
324 // normalize
325 n13 /= n13.magnitude();
326 n20 /= n20.magnitude();
327
328 // coordinates of nodes of a Q1 element this P1 element is embedded in (up to
329 // translation)
330 Vector2d p[] = {{0, 0}, {dx, 0}, {dx, dy}, {0, dy}};
331 std::vector<Vector2d> pts;
332
333 switch (type) {
334 case 0:
335 m_i_offset = {0, 1, 0};
336 m_j_offset = {0, 0, 1};
337 m_normals = {n01, n13, n30};
338 pts = {p[0], p[1], p[3]};
339 break;
340 case 1:
341 m_i_offset = {1, 1, 0};
342 m_j_offset = {0, 1, 0};
343 m_normals = {n12, n20, n01};
344 pts = {p[1], p[2], p[0]};
345 break;
346 case 2:
347 m_i_offset = {1, 0, 1};
348 m_j_offset = {1, 1, 0};
349 m_normals = {n23, -1.0 * n13, n12};
350 pts = {p[2], p[3], p[1]};
351 break;
352 case 3:
353 default:
354 m_i_offset = {0, 0, 1};
355 m_j_offset = {1, 0, 1};
356 m_normals = {n30, -1.0 * n20, n23};
357 pts = {p[3], p[0], p[2]};
358 break;
359 }
360
361 reset(0, 0);
362 // make sure add_contribution() ignores entries corresponding to the 4-th node
365
366 m_side_lengths.resize(n_sides());
367 // compute side lengths
368 for (unsigned int k = 0; k < n_sides(); ++k) {
369 m_side_lengths[k] = (pts[k] - pts[(k + 1) % 3]).magnitude();
370 }
371
372 // compute the Jacobian
373 double J[3][3];
375 J[0][0] = pts[1].u - pts[0].u;
376 J[0][1] = pts[1].v - pts[0].v;
377 J[1][0] = pts[2].u - pts[0].u;
378 J[1][1] = pts[2].v - pts[0].v;
379
380 // initialize germs and quadrature weights for the quadrature on this physical element
381 initialize(J, p1::chi, p1::n_chi, quadrature.points(), quadrature.weights());
382 reset(0, 0);
383}
384
385Element3::Element3(const DMDALocalInfo &grid_info, int Nq, int n_chi, int block_size)
386 : Element(grid_info, Nq, n_chi, block_size) {
387 m_i = 0;
388 m_j = 0;
389 m_k = 0;
390}
391
392Element3::Element3(const Grid &grid, int Nq, int n_chi, int block_size)
393 : Element(grid, Nq, n_chi, block_size) {
394 m_i = 0;
395 m_j = 0;
396 m_k = 0;
397}
398
399Q1Element3::Q1Element3(const DMDALocalInfo &grid_info,
400 const Quadrature &quadrature,
401 double dx,
402 double dy,
403 double x_min,
404 double y_min)
405 : Element3(grid_info, quadrature.weights().size(), q13d::n_chi, q13d::n_chi),
406 m_dx(dx),
407 m_dy(dy),
408 m_x_min(x_min),
409 m_y_min(y_min),
410 m_points(quadrature.points()),
411 m_w(quadrature.weights()) {
412
413 m_weights.resize(m_Nq);
414
415 m_i_offset = {0, 1, 1, 0, 0, 1, 1, 0};
416 m_j_offset = {0, 0, 1, 1, 0, 0, 1, 1};
417 m_k_offset = {0, 0, 0, 0, 1, 1, 1, 1};
418
419 // store values of shape functions on the reference element
420 m_chi.resize(m_Nq * m_n_chi);
421 for (unsigned int q = 0; q < m_Nq; q++) {
422 for (unsigned int n = 0; n < m_n_chi; n++) {
423 m_chi[q * m_n_chi + n] = q13d::chi(n, m_points[q]);
424 }
425 }
426 m_germs = m_chi;
427}
428
429Q1Element3::Q1Element3(const Grid &grid, const Quadrature &quadrature)
430 : Element3(grid, quadrature.weights().size(), q13d::n_chi, q13d::n_chi),
431 m_dx(grid.dx()),
432 m_dy(grid.dy()),
433 m_points(quadrature.points()),
434 m_w(quadrature.weights()) {
435
436 m_weights.resize(m_Nq);
437
438 m_i_offset = {0, 1, 1, 0, 0, 1, 1, 0};
439 m_j_offset = {0, 0, 1, 1, 0, 0, 1, 1};
440 m_k_offset = {0, 0, 0, 0, 1, 1, 1, 1};
441
442 // store values of shape functions on the reference element
443 m_chi.resize(m_Nq * m_n_chi);
444 for (unsigned int q = 0; q < m_Nq; q++) {
445 for (unsigned int n = 0; n < m_n_chi; n++) {
446 m_chi[q * m_n_chi + n] = q13d::chi(n, m_points[q]);
447 }
448 }
449}
450
451
452/*! Initialize the element `i,j,k`.
453 *
454 *
455 * @param[in] i i-index of the lower left node
456 * @param[in] j j-index of the lower left node
457 * @param[in] k k-index of the lower left node
458 * @param[in] z z-coordinates of the nodes of this element
459 */
460void Q1Element3::reset(int i, int j, int k, const double *z) {
461 // Record i,j,k corresponding to the current element:
462 m_i = i;
463 m_j = j;
464 m_k = k;
465
466 // store z coordinates
467 for (unsigned int n = 0; n < m_n_chi; ++n) {
468 m_z_nodal[n] = z[n];
469 }
470
471 // Set row and column info used to add contributions:
472 for (unsigned int n = 0; n < m_n_chi; ++n) {
473 m_col[n].i = k + m_k_offset[n]; // x -- z (STORAGE_ORDER)
474 m_col[n].j = i + m_i_offset[n]; // y -- x (STORAGE_ORDER)
475 m_col[n].k = j + m_j_offset[n]; // z -- y (STORAGE_ORDER)
476 m_col[n].c = 0;
477 }
478 m_row = m_col;
479
480 // Mark rows that we don't own as invalid:
481 for (unsigned int n = 0; n < m_n_chi; n++) {
482 auto I = local_to_global(n);
483 if (I.i < m_grid.xs or m_grid.xs + m_grid.xm - 1 < I.i or
484 I.j < m_grid.ys or m_grid.ys + m_grid.ym - 1 < I.j) {
486 }
487 }
488
489 // Compute J^{-1} and use it to compute m_germs and m_weights:
490 for (unsigned int q = 0; q < m_Nq; q++) {
491
492 Vector3 dz{0.0, 0.0, 0.0};
493 for (unsigned int n = 0; n < m_n_chi; ++n) {
494 auto &chi = m_chi[q * m_n_chi + n];
495 dz.x += chi.dx * z[n];
496 dz.y += chi.dy * z[n];
497 dz.z += chi.dz * z[n];
498 }
499
500 double J[3][3] = {{m_dx / 2.0, 0.0, dz.x},
501 { 0.0, m_dy / 2.0, dz.y},
502 { 0.0, 0.0, dz.z}};
503
504 double J_det = J[0][0] * J[1][1] * J[2][2];
505
506 assert(J_det != 0.0);
507
508 double J_inv[3][3] = {{1.0 / J[0][0], 0.0, -J[0][2] / (J[0][0] * J[2][2])},
509 {0.0, 1.0 / J[1][1], -J[1][2] / (J[1][1] * J[2][2])},
510 {0.0, 0.0, 1.0 / J[2][2]}};
511
512 m_weights[q] = J_det * m_w[q];
513
514 for (unsigned int n = 0; n < m_n_chi; n++) {
515 auto &chi = m_chi[q * m_n_chi + n];
516 // FIXME: I should be able to use multiply() defined above, but there must be a bug
517 // there...
518 m_germs[q * m_n_chi + n] = {chi.val,
519 J_inv[0][0] * chi.dx + J_inv[0][1] * chi.dy + J_inv[0][2] * chi.dz,
520 J_inv[1][0] * chi.dx + J_inv[1][1] * chi.dy + J_inv[1][2] * chi.dz,
521 J_inv[2][0] * chi.dx + J_inv[2][1] * chi.dy + J_inv[2][2] * chi.dz};
522 }
523 }
524}
525
526Q1Element3Face::Q1Element3Face(double dx, double dy, const Quadrature &quadrature)
527 : m_dx(dx),
528 m_dy(dy),
529 m_points(quadrature.points()),
530 m_w(quadrature.weights()),
531 m_n_chi(q13d::n_chi),
532 m_Nq(m_w.size()) {
533
534 // Note: here I set m_n_chi to q13d::n_chi (8) while each face has only four basis
535 // functions that are not zero on it. One could make evaluate() cheaper by omitting
536 // these zeros. (This would make the code somewhat more complex.)
537
538 m_chi.resize(m_Nq * m_n_chi);
539 m_weights.resize(m_Nq);
540 m_normals.resize(m_Nq);
541}
542
543void Q1Element3Face::reset(int face, const double *z) {
544
545 // Turn coordinates of a 2D quadrature point on [-1,1]*[-1,1] into coordinates on a face
546 // of the cube [-1,1]*[-1,1]*[-1,1].
547 for (unsigned int q = 0; q < m_Nq; q++) {
548 auto pt = m_points[q];
549 QuadPoint P;
550
551 // This expresses parameterizations of faces of the reference element: for example,
552 // face 0 is parameterized by (s, t) -> [-1, s, t].
553 switch (face) {
555 P = {-1.0, pt.xi, pt.eta};
556 break;
558 P = { 1.0, pt.xi, pt.eta};
559 break;
561 P = {pt.xi, -1.0, pt.eta};
562 break;
564 P = {pt.xi, 1.0, pt.eta};
565 break;
567 P = {pt.xi, pt.eta, -1.0};
568 break;
570 P = {pt.xi, pt.eta, 1.0};
571 break;
572 }
573
574 // Compute dz/dxi, dz/deta and dz/dzeta.
575 Vector3 dz{0.0, 0.0, 0.0};
576 for (unsigned int n = 0; n < m_n_chi; ++n) {
577 // Note: chi(n, point) for a particular face does not depend on the element geometry
578 // and could be computed in advance (in the constructor). On the other hand, I
579 // expect that the number of faces in a Neumann boundary is relatively small and
580 // this optimization is not likely to pay off.
581 auto chi = q13d::chi(n, P);
582
583 m_chi[q * m_n_chi + n] = chi.val;
584
585 dz.x += chi.dx * z[n];
586 dz.y += chi.dy * z[n];
587 dz.z += chi.dz * z[n];
588 }
589
590 // Use the magnitude of the normal to a face to turn quadrature weights on
591 // [-1,1]*[-1,1] into quadrature weights on a face of this physical element.
592
593 m_weights[q] = m_w[q];
594
595 // Sign (-1 or +1) used to set normal orientation This relies of the order of faces in
596 // fem::q13d::incident_nodes and above (see the code setting QuadPoint P).
597 double sign = 2 * (face % 2) - 1;
598
599 switch (face) {
602 m_weights[q] *= 0.5 * m_dy * dz.z;
603 m_normals[q] = {sign, 0.0, 0.0};
604 break;
607 m_weights[q] *= 0.5 * m_dx * dz.z;
608 m_normals[q] = {0.0, sign, 0.0};
609 break;
612 {
613 double
614 a = 0.5 * m_dy * dz.x,
615 b = 0.5 * m_dx * dz.y,
616 c = 0.25 * m_dx * m_dy,
617 M = std::sqrt(a * a + b * b + c * c);
618 m_weights[q] *= M;
619
620 M *= sign;
621 m_normals[q] = {a / M, b / M, c / M};
622 }
623 break;
624 }
625 } // end of the loop over quadrature points
626}
627
628
629} // end of namespace fem
630} // end of namespace pism
Describes the PISM grid and the distribution of data across processors.
Definition Grid.hh:290
double magnitude() const
Magnitude.
Definition Vector2d.hh:40
This class represents a 2D vector field (such as ice velocity) at a certain grid point.
Definition Vector2d.hh:29
Element2(const Grid &grid, int Nq, int n_chi, int block_size)
Definition Element.cc:175
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 reset(int i, int j)
Initialize the Element to element (i, j) for the purposes of inserting into global residual and Jacob...
Definition Element.cc:196
std::vector< double > m_side_lengths
Definition Element.hh:260
std::vector< Vector2d > m_normals
Definition Element.hh:258
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
unsigned int n_sides() const
Definition Element.hh:181
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
Element3(const DMDALocalInfo &grid_info, int Nq, int n_chi, int block_size)
Definition Element.cc:385
std::vector< int > m_k_offset
Definition Element.hh:349
GlobalIndex local_to_global(int i, int j, int k, unsigned int n) const
Definition Element.hh:305
int n_chi() const
Definition Element.hh:65
std::vector< int > m_i_offset
Definition Element.hh:126
void initialize(const double J[3][3], ShapeFunction f, unsigned int n_chi, const std::vector< QuadPoint > &points, const std::vector< double > &W)
Initialize shape function values and quadrature weights of a 2D physical element.
Definition Element.cc:153
std::vector< double > m_weights
Quadrature weights for a particular physical element.
Definition Element.hh:155
std::vector< MatStencil > m_col
Definition Element.hh:144
const Germ & chi(unsigned int q, unsigned int k) const
Definition Element.hh:73
const unsigned int m_n_chi
Definition Element.hh:131
void add_contribution(const double *K, Mat J) const
Add Jacobian contributions.
Definition Element.cc:241
const int m_block_size
Definition Element.hh:139
std::vector< Germ > m_germs
Definition Element.hh:141
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
const unsigned int m_Nq
Number of quadrature points.
Definition Element.hh:137
static const int m_invalid_dof
Definition Element.hh:152
DMDALocalInfo m_grid
Definition Element.hh:113
std::vector< MatStencil > m_row
Stencils for updating entries of the Jacobian matrix.
Definition Element.hh:144
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
std::vector< int > m_j_offset
Definition Element.hh:127
int m_i
Indices of the current element.
Definition Element.hh:134
The mapping from global to local degrees of freedom.
Definition Element.hh:61
P1Element2(const Grid &grid, const Quadrature &quadrature, int type)
Definition Element.cc:305
Q1Element2(const Grid &grid, const Quadrature &quadrature)
Definition Element.cc:249
const unsigned int m_Nq
Definition Element.hh:464
Q1Element3Face(double dx, double dy, const Quadrature &quadrature)
Definition Element.cc:526
std::vector< Vector3 > m_normals
Definition Element.hh:454
const double & chi(unsigned int q, unsigned int k) const
Definition Element.hh:419
std::vector< double > m_w
Definition Element.hh:457
std::vector< double > m_chi
Definition Element.hh:449
std::vector< QuadPoint > m_points
Definition Element.hh:452
std::vector< double > m_weights
Definition Element.hh:460
const unsigned int m_n_chi
Definition Element.hh:463
void reset(int face, const double *z)
Definition Element.cc:543
void reset(int i, int j, int k, const double *z)
Definition Element.cc:460
std::vector< QuadPoint > m_points
Definition Element.hh:399
Q1Element3(const DMDALocalInfo &grid, const Quadrature &quadrature, double dx, double dy, double x_min, double y_min)
Definition Element.cc:399
double m_z_nodal[q13d::n_chi]
Definition Element.hh:392
std::vector< double > m_w
Definition Element.hh:402
double z(int n) const
Definition Element.hh:381
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
std::vector< Germ > m_chi
Definition Element.hh:396
const std::vector< double > & weights() const
Definition Quadrature.cc:30
const std::vector< QuadPoint > & points() const
Definition Quadrature.cc:26
Numerical integration of finite element functions.
Definition Quadrature.hh:63
#define PISM_CHK(errcode, name)
#define n
Definition exactTestM.c:37
const int n_chi
Definition FEM.hh:199
Germ chi(unsigned int k, const QuadPoint &pt)
P1 basis functions on the reference element with nodes (0,0), (1,0), (0,1).
Definition FEM.cc:90
Germ chi(unsigned int k, const QuadPoint &p)
Evaluate a Q1 shape function and its derivatives with respect to xi and eta.
Definition FEM.cc:140
const int n_chi
Definition FEM.hh:191
Germ chi(unsigned int k, const QuadPoint &pt)
Q1 basis functions on the reference element with nodes (-1,-1), (1,-1), (1,1), (-1,...
Definition FEM.cc:72
static double det(const double a[3][3])
Determinant of a 3x3 matrix.
Definition Element.cc:33
static double dot(const Vector3 &v, const Germ &a)
Definition Element.cc:57
static void invert(const double A[3][3], double result[3][3])
Invert a 3x3 matrix.
Definition Element.cc:62
static Vector3 row(const double A[3][3], size_t k)
Definition Element.cc:47
static void set_to_identity(double A[3][3])
Definition Element.cc:97
static Germ multiply(const double A[3][3], const Germ &v)
Compute derivatives with respect to x,y using J^{-1} and derivatives with respect to xi,...
Definition Element.cc:89
static Vector3 column(const double A[3][3], size_t k)
Definition Element.cc:52
static Vector3 cross(const Vector3 &a, const Vector3 &b)
Cross product of two 3D vectors.
Definition Element.cc:40
static const double k
Definition exactTestP.cc:42
double dy
Function derivative with respect to y.
Definition FEM.hh:157
double val
Function value.
Definition FEM.hh:153
double dz
Function derivative with respect to z.
Definition FEM.hh:159
double dx
Function deriviative with respect to x.
Definition FEM.hh:155
Struct for gathering the value and derivative of a function at a point.
Definition FEM.hh:151