4 friction_coefficients =
r"""
5 const double Zeta = 35.0 * tarch::la::PI / 180.0; // Conversion of degrees to radians
6 const double Zeta1 = 28.95 * tarch::la::PI / 180.0;
7 const double Zeta2 = 44.09 * tarch::la::PI / 180.0;
8 const double Zeta3 = 31.81 * tarch::la::PI / 180.0;
10 const double Mu1 = std::tan(Zeta1);
11 const double Mu2 = std::tan(Zeta2);
12 const double Mu3 = std::tan(Zeta3);
14 constexpr double Beta = 1.07;
15 constexpr double Gamma = 2.01;
16 constexpr double BetaStar = 0.06;
17 // Kappa in the friction law is assumed to be 1 and is just initialised as a
18 // const double here using Kappa. The user can apply std::pow((Fr/BetaStar),
19 // Kappa) for evaluating T here in case the value of Kappa is different
22 constexpr double Kappa = 1.0;
23 constexpr double FrictionLengthScale = 0.00035;
25 const double Nu = (2.0 / 9.0) * (FrictionLengthScale / Beta) * (GRAV * std::sin(Zeta) / std::sqrt(GRAV * std::cos(Zeta))) * (((Mu2 - Mu1) / (std::tan(Zeta) - Mu1)) - 1.0);
26 const double Hstart = FrictionLengthScale * (((Mu2 - Mu1) / (std::tan(Zeta) - Mu3)) - 1.0);
27 const double Hstop = FrictionLengthScale * (((Mu2 - Mu1) / (std::tan(Zeta) - Mu1)) - 1.0);
30 max_eigenvalue = friction_coefficients +
r"""
33 if (tarch::la::greater(Q[Shortcuts::h], 0.0)) {
34 const double u = Q[Shortcuts::hu + normal] / Q[Shortcuts::h];
35 const double c = std::sqrt(GRAV * std::cos(Zeta) * Q[Shortcuts::h]);
36 result = std::fmax(std::fabs(u - c), std::fabs(u + c));
42 flux = friction_coefficients +
r"""
43 if (tarch::la::greater(Q[Shortcuts::h], 0.0)) {
44 const double ih = 1.0 / Q[Shortcuts::h];
45 F[Shortcuts::h] = Q[Shortcuts::hu + normal];
48 F[Shortcuts::hu] = ih * Q[Shortcuts::hu] * Q[Shortcuts::hu] + 0.5 * GRAV * std::cos(Zeta) * Q[Shortcuts::h] * Q[Shortcuts::h];
49 F[Shortcuts::hv] = ih * Q[Shortcuts::hu] * Q[Shortcuts::hv];
52 F[Shortcuts::hu] = ih * Q[Shortcuts::hv] * Q[Shortcuts::hu];
53 F[Shortcuts::hv] = ih * Q[Shortcuts::hv] * Q[Shortcuts::hv] + 0.5 * GRAV * std::cos(Zeta) * Q[Shortcuts::h] * Q[Shortcuts::h];
57 F[Shortcuts::h] = 0.0;
58 F[Shortcuts::hu] = 0.0;
59 F[Shortcuts::hv] = 0.0;
63 nonconservative_product = friction_coefficients +
r"""
64 BTimesDeltaQ[Shortcuts::h] = 0.0;
65 BTimesDeltaQ[Shortcuts::hu] = 0.0;
66 BTimesDeltaQ[Shortcuts::hv] = 0.0;
67 BTimesDeltaQ[Shortcuts::b] = 0.0;
69 const double hx = (Q[Shortcuts::hx] - 0.5 * deltaQ[Shortcuts::hx]) / (1.0 * h(0));
70 const double hy = (Q[Shortcuts::hy] - 0.5 * deltaQ[Shortcuts::hy]) / (1.0 * h(1));
73 const double ux = (Q[Shortcuts::ux] - 0.5 * deltaQ[Shortcuts::ux]) / (1.0 * h(0));
74 const double uy = (Q[Shortcuts::uy] - 0.5 * deltaQ[Shortcuts::uy]) / (1.0 * h(1));
75 const double uxx = (Q[Shortcuts::uxx] - 0.5 * deltaQ[Shortcuts::uxx]) / (h(0) * h(0));
76 const double uyy = (Q[Shortcuts::uyy] - 0.5 * deltaQ[Shortcuts::uyy]) / (h(1) * h(1));
77 const double uxy = (Q[Shortcuts::uxy] - 0.5 * deltaQ[Shortcuts::uxy]) / (4.0 * h(0) * h(1));
80 const double vx = (Q[Shortcuts::vx] - 0.5 * deltaQ[Shortcuts::vx]) / (1.0 * h(0));
81 const double vy = (Q[Shortcuts::vy] - 0.5 * deltaQ[Shortcuts::vy]) / (1.0 * h(1));
82 const double vxx = (Q[Shortcuts::vxx] - 0.5 * deltaQ[Shortcuts::vxx]) / (h(0) * h(0));
83 const double vyy = (Q[Shortcuts::vyy] - 0.5 * deltaQ[Shortcuts::vyy]) / (h(1) * h(1));
84 const double vxy = (Q[Shortcuts::vxy] - 0.5 * deltaQ[Shortcuts::vxy]) / (4.0 * h(0) * h(1));
88 BTimesDeltaQ[Shortcuts::hu] = -(h(0) * Nu * std::sqrt(Q[Shortcuts::h]) * (1.5 * hx * ux + Q[Shortcuts::h] * uxx));
89 BTimesDeltaQ[Shortcuts::hv] = -(h(0) * 0.5 * Nu * std::sqrt(Q[Shortcuts::h]) * (1.5 * hx * (uy + vx) + Q[Shortcuts::h] * (uxy + vxx)));
92 BTimesDeltaQ[Shortcuts::hu] = -(h(1) * 0.5 * Nu * std::sqrt(Q[Shortcuts::h]) * (1.5 * hy * (uy + vx) + Q[Shortcuts::h] * (uyy + vxy)));
93 BTimesDeltaQ[Shortcuts::hv] = -(h(1) * Nu * std::sqrt(Q[Shortcuts::h]) * (1.5 * hy * vy + Q[Shortcuts::h] * vyy));
98 coulomb_friction = friction_coefficients +
r"""
99 S[Shortcuts::h] = 0.0;
100 S[Shortcuts::hu] = 0.0;
101 S[Shortcuts::hv] = 0.0;
103 if (tarch::la::greater(Q[Shortcuts::h], 0.0)) {
104 const double u{Q[Shortcuts::hu + 0] / Q[Shortcuts::h]};
105 const double v{Q[Shortcuts::hu + 1] / Q[Shortcuts::h]};
106 const double velMagnitudeSqr{u * u + v * v};
107 if (tarch::la::greater(velMagnitudeSqr, 0.0)) {
108 const double zx{Q[Shortcuts::bx] / h(0)};
109 const double zy{Q[Shortcuts::by] / h(1)};
110 const double c{1.0 / std::sqrt(1.0 + zx * zx + zy * zy)};
111 const double friction{-GRAV * (Mu1 * Q[Shortcuts::h] * c)};
112 const double velMagnitude{std::sqrt(velMagnitudeSqr)};
113 S[Shortcuts::hu] += u / velMagnitude * friction;
114 S[Shortcuts::hv] += v / velMagnitude * friction;
119 material_dependent_basal_friction = friction_coefficients +
r"""
120 if (tarch::la::greater(Q[Shortcuts::h], 0.0)) {
121 const double ih = 1.0 / Q[Shortcuts::h];
122 const double u = ih * Q[Shortcuts::hu];
123 const double v = ih * Q[Shortcuts::hv];
124 const double ubar = std::sqrt(Q[Shortcuts::hu] * Q[Shortcuts::hu] + Q[Shortcuts::hv] * Q[Shortcuts::hv]) * ih;
125 const double Fr = ubar / std::sqrt(GRAV * Q[Shortcuts::h] * std::cos(Zeta));
126 const double Hstar = (BetaStar + Gamma) * Hstop / Beta;
130 const double vstop = (Q[Shortcuts::h] * Beta) / (Fr + Gamma);
131 const double Mustop = Mu1 + (Mu1 - Mu2) / (1.0 + vstop / FrictionLengthScale);
133 } else if (Fr > 0.0 && Fr <= BetaStar) {
134 const double vstart = Q[Shortcuts::h];
135 const double vstop = Q[Shortcuts::h] * Beta / (BetaStar + Gamma);
136 const double Mustart = Mu3 + (Mu1 - Mu2) / (1.0 + vstart / FrictionLengthScale);
137 const double Mustop = Mu1 + (Mu1 - Mu2) / (1.0 + vstop / FrictionLengthScale);
138 const double T = Mustart + (Mustop - Mustart) * std::pow((Fr / BetaStar), Kappa);
140 } else if (tarch::la::equals(Fr, 0.0)) {
141 const double vstart = Q[Shortcuts::h];
142 const double Mustart = Mu3 + (Mu1 - Mu2) / (1.0 + vstart / FrictionLengthScale);
146 if (tarch::la::equals(ubar, 0.0)) {
147 const double hx = Q[Shortcuts::hx] / h(0);
148 const double hy = Q[Shortcuts::hy] / h(1);
149 const tarch::la::Vector<DIMENSIONS, double> frictionVector = {std::tan(Zeta) - hx, -hy};
150 const double frictionVectorMagnitude = tarch::la::norm2(frictionVector);
151 if (tarch::la::greater(Mu, frictionVectorMagnitude)) {
152 Mu = frictionVectorMagnitude;
155 if (tarch::la::equals(Mu, 0.0)) {
156 S[Shortcuts::h] = 0.0;
157 S[Shortcuts::hu] = Q[Shortcuts::h] * GRAV * std::sin(Zeta);
158 S[Shortcuts::hv] = 0.0;
160 S[Shortcuts::h] = 0.0;
161 S[Shortcuts::hu] = Q[Shortcuts::h] * GRAV * std::sin(Zeta) - Mu * (frictionVector(0) / frictionVectorMagnitude) * Q[Shortcuts::h] * GRAV * std::cos(Zeta);
162 S[Shortcuts::hv] = -Mu * (frictionVector(1) / frictionVectorMagnitude) * Q[Shortcuts::h] * GRAV * std::cos(Zeta);
164 } else if (tarch::la::greater(ubar, 0.0)) {
165 S[Shortcuts::h] = 0.0;
166 S[Shortcuts::hu] = Q[Shortcuts::h] * GRAV * std::sin(Zeta) - Mu * (u / ubar) * Q[Shortcuts::h] * GRAV * std::cos(Zeta);
167 S[Shortcuts::hv] = -Mu * (v / ubar) * Q[Shortcuts::h] * GRAV * std::cos(Zeta);
170 S[Shortcuts::h] = 0.0;
171 S[Shortcuts::hu] = 0.0;
172 S[Shortcuts::hv] = 0.0;