PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
BlatterTestvanderVeen.cc
Go to the documentation of this file.
1/* Copyright (C) 2020, 2021, 2022, 2023, 2025 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/verification/BlatterTestvanderVeen.hh"
21#include "pism/util/node_types.hh"
22
23#include "pism/rheology/IsothermalGlen.hh"
24
25#include "pism/stressbalance/blatter/verification/manufactured_solutions.hh"
26
27namespace pism {
28namespace stressbalance {
29
30BlatterTestvanderVeen::BlatterTestvanderVeen(std::shared_ptr<const Grid> grid,
31 int Mz, int coarsening_factor)
32 : Blatter(grid, Mz, coarsening_factor) {
33
34 // use the isothermal Glen flow law
35 double n = m_config->get_number("stress_balance.blatter.Glen_exponent");
37
38 // make sure we use the same Glen exponent
39 assert(m_flow_law->exponent() == 3.0);
40
41 // make sure the grid is periodic in the Y direction
42 assert(m_grid->periodicity() == grid::Y_PERIODIC);
43
44 // store constant ice hardness (enthalpy and pressure values are irrelevant)
45 m_B = m_flow_law->hardness(1e5, 0);
46
47 // ice thickness (m)
48 m_H0 = 600.0;
49
50 // ice velocity (m / s)
51 m_V0 = convert(m_sys, 300.0, "m / year", "m / s");
52
53 m_rho_ice = m_config->get_number("constants.ice.density");
54
55 // s = alpha * H, where s is surface elevation and H ice thickness
56 double rho_w = m_config->get_number("constants.sea_water.density");
57 m_alpha = 1.0 - m_rho_ice / rho_w;
58
59 m_g = m_config->get_number("constants.standard_gravity");
60}
61
62bool BlatterTestvanderVeen::dirichlet_node(const DMDALocalInfo &info,
64 (void) info;
65 // use Dirichlet BC at x == 0
66 return I.i == 0;
67}
68
70 const int *node_type,
71 const double *ice_bottom,
72 const double *sea_level) {
73 // Ignore sea level and ice bottom elevation:
74 (void) ice_bottom;
75 (void) sea_level;
76
77 const auto *nodes = fem::q13d::incident_nodes[face];
78
79 // number of nodes per face
80 int N = 4;
81
82 // exclude faces that contain at least one node that is not a part of the boundary
83 for (int n = 0; n < N; ++n) {
84 if (not (node_type[nodes[n]] == NODE_BOUNDARY)) {
85 return false;
86 }
87 }
88
89 return true;
90}
91
92Vector2d BlatterTestvanderVeen::u_bc(double x, double y, double z) const {
93 (void) y;
94 (void) z;
95
96 return u_exact(x);
97}
98
100 double Q0 = m_H0 * m_V0;
102}
103
104double BlatterTestvanderVeen::H_exact(double x) const {
105 double Q0 = m_H0 * m_V0;
107}
108
109double BlatterTestvanderVeen::b_exact(double x) const {
110 return (m_alpha - 1.0) * H_exact(x);
111}
112
113double BlatterTestvanderVeen::beta_exact(double x) const {
114 double Q0 = m_H0 * m_V0;
116}
117
119 const fem::Q1Element3Face &face,
120 const double *surface_nodal,
121 const double *z_nodal,
122 const double *sl_nodal,
123 Vector2d *residual) {
124 (void) surface_nodal;
125 (void) sl_nodal;
126 (void) z_nodal;
127
128 double Q0 = m_H0 * m_V0;
129
130 // compute x coordinates of quadrature points
131 double *x = m_work[0];
132 {
133 double *x_nodal = m_work[1];
134
135 for (int n = 0; n < element.n_chi(); ++n) {
136 x_nodal[n] = element.x(n);
137 }
138
139 face.evaluate(x_nodal, x);
140 }
141
142 // loop over all quadrature points
143 for (unsigned int q = 0; q < face.n_pts(); ++q) {
144 auto W = face.weight(q) / m_scaling;
145
146 // the normal direction (1, 0, 0) is hard-wired here
148 m_rho_ice, m_g, m_B);
149
150 // loop over all test functions
151 for (int t = 0; t < element.n_chi(); ++t) {
152 auto psi = face.chi(q, t);
153
154 residual[t] += - W * psi * F;
155 }
156 }
157}
158
159/*!
160 * Top surface contribution to the residual.
161 */
163 const fem::Q1Element3Face &face,
164 Vector2d *residual) {
165 double Q0 = m_H0 * m_V0;
166
167 // compute x coordinates of quadrature points
168 double
169 *x = m_work[0];
170 {
171 double *x_nodal = m_work[1];
172
173 for (int n = 0; n < fem::q13d::n_chi; ++n) {
174 x_nodal[n] = element.x(n);
175 }
176
177 face.evaluate(x_nodal, x);
178 }
179
180 for (unsigned int q = 0; q < face.n_pts(); ++q) {
181 auto W = face.weight(q) / m_scaling;
182
184 m_rho_ice, m_g, m_B);
185
186 // loop over all test functions
187 for (int t = 0; t < element.n_chi(); ++t) {
188 auto psi = face.chi(q, t);
189
190 residual[t] += - W * psi * F;
191 }
192 }
193}
194
195} // end of namespace stressbalance
196} // end of namespace pism
const units::System::Ptr m_sys
unit system used by this component
Definition Component.hh:162
std::shared_ptr< const Config > m_config
configuration database used by this component
Definition Component.hh:160
const std::shared_ptr< const Grid > m_grid
grid used by this component
Definition Component.hh:158
This class represents a 2D vector field (such as ice velocity) at a certain grid point.
Definition Vector2d.hh:29
int n_chi() const
Definition Element.hh:65
double weight(unsigned int q) const
Definition Element.hh:414
unsigned int n_pts() const
Number of quadrature points.
Definition Element.hh:411
const double & chi(unsigned int q, unsigned int k) const
Definition Element.hh:419
void evaluate(const T *x, T *result) const
Definition Element.hh:434
double x(int n) const
Definition Element.hh:371
3D Q1 element
Definition Element.hh:358
Isothermal Glen ice allowing extra customization.
Vector2d u_bc(double x, double y, double z) const
bool dirichlet_node(const DMDALocalInfo &info, const fem::Element3::GlobalIndex &I)
bool marine_boundary(int face, const int *node_type, const double *ice_bottom, const double *sea_level)
BlatterTestvanderVeen(std::shared_ptr< const Grid > grid, int Mz, int coarsening_factor)
void residual_surface(const fem::Q1Element3 &element, const fem::Q1Element3Face &face, Vector2d *residual)
void residual_lateral(const fem::Q1Element3 &element, const fem::Q1Element3Face &face, const double *surface_nodal, const double *z_nodal, const double *sl_nodal, Vector2d *residual)
double m_work[m_n_work][m_Nq]
Definition Blatter.hh:109
std::shared_ptr< rheology::FlowLaw > m_flow_law
std::shared_ptr< EnthalpyConverter > m_EC
#define n
Definition exactTestM.c:37
const int n_chi
Number of shape functions on a Q1 element.
Definition FEM.hh:213
const unsigned int incident_nodes[n_faces][4]
Definition FEM.hh:223
double blatter_xz_vanderveen_beta(double x, double alpha, double H_0, double Q_0, double rho_i, double g, double B)
double blatter_xz_vanderveen_thickness(double x, double alpha, double H_0, double Q_0, double rho_i, double g, double B)
static double F(double SL, double B, double H, double alpha)
Vector2d blatter_xz_vanderveen_source_lateral(double x, double alpha, double H_0, double Q_0, double rho_i, double g, double B)
@ NODE_BOUNDARY
Definition node_types.hh:35
Vector2d blatter_xz_vanderveen_source_surface(double x, double alpha, double H_0, double Q_0, double rho_i, double g, double B)
Vector2d blatter_xz_vanderveen_exact(double x, double alpha, double H_0, double Q_0, double rho_i, double g, double B)