PISM, A Parallel Ice Sheet Model  stable v2.1.1 committed by Constantine Khrulev on 2024-12-04 13:36:58 -0900
exactTestL.cc
Go to the documentation of this file.
1 /* Copyright (C) 2016, 2017, 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/verification/tests/exactTestL.hh"
21 
22 #include <cstdlib>
23 #include <cmath>
24 #include <gsl/gsl_errno.h>
25 #include <gsl/gsl_matrix.h>
26 #include <gsl/gsl_math.h> /* M_PI */
27 
28 #include <gsl/gsl_version.h>
29 #if (defined GSL_MAJOR_VERSION) && (defined GSL_MINOR_VERSION) && \
30  ((GSL_MAJOR_VERSION >= 1 && GSL_MINOR_VERSION >= 15) || (GSL_MAJOR_VERSION >= 2))
31 #define PISM_USE_ODEIV2 1
32 #include <gsl/gsl_odeiv2.h>
33 #endif
34 
35 #include "pism/util/error_handling.hh"
36 using pism::RuntimeError;
37 
38 static const double SperA = 31556926.0; /* seconds per year; 365.2422 days */
39 
40 static const double L = 750.0e3; /* m; i.e. 750 km */
41 static const double b0 = 500.0; /* m */
42 static const double z0 = 1.2;
43 static const double g = 9.81;
44 static const double rho = 910.0;
45 static const double n = 3.0; /* Glen power */
46 
47 int funcL(double r, const double u[], double f[], void *params) {
48  /*
49  RHS for differential equation:
50  du 5/8 / a_0 r (L^2 - r^2) \ 1/3
51  -- = - (8/3) b'(r) u - |---------------------|
52  dr \ 2 L^2 \tilde\Gamma /
53  */
54 
55  const double Lsqr = L * L;
56  const double a0 = 0.3 / SperA; /* m/s; i.e. 0.3 m/a */
57  const double A = 1.0e-16 / SperA; /* = 3.17e-24 1/(Pa^3 s); EISMINT I flow law */
58  const double Gamma = 2 * pow(rho * g,n) * A / (n+2);
59  const double tilGamma = Gamma * pow(n,n) / (pow(2.0 * n + 2.0, n));
60  const double C = a0 / (2.0 * Lsqr * tilGamma);
61 
62  if (params == NULL) {} /* quash warning "unused parameters" */
63 
64  if ((r >= 0.0) && (r <= L)) {
65  const double freq = z0 * M_PI / L;
66  const double bprime = b0 * freq * sin(freq * r);
67  f[0] = - (8.0/3.0) * bprime * pow(u[0], 5.0/8.0)
68  - pow(C * r * (Lsqr - r * r), 1.0/3.0);
69  } else {
70  f[0] = 0.0; /* no changes outside of defined interval */
71  }
72  return GSL_SUCCESS;
73 }
74 
75 /* exit status could be one of these; returned zero indicates success */
76 #define TESTL_NOT_DONE 8966
77 #define TESTL_NOT_DECREASING 8967
78 #define TESTL_INVALID_METHOD 8968
79 #define TESTL_NO_LIST 8969
80 
81 #ifdef PISM_USE_ODEIV2
82 
83 /* combination EPS_ABS = 1e-12, EPS_REL=0.0, method = 1 = RK Cash-Karp
84  is believed to be predictable and accurate */
85 int getU(const double *r, int N, double *u,
86  const double EPS_ABS, const double EPS_REL, const int ode_method) {
87  /* solves ODE for u(r)=H(r)^{8/3}, 0 <= r <= L, for test L
88  r and u must be allocated vectors of length N; r[] must be decreasing */
89  int k, count;
90  int status = TESTL_NOT_DONE;
91  double rr, hstart;
92  const gsl_odeiv2_step_type* Tpossible[4];
93  const gsl_odeiv2_step_type *T;
94  gsl_odeiv2_system sys = {funcL, NULL, 1, NULL}; /* Jac-free method and no params */
95  gsl_odeiv2_driver *d;
96 
97  /* setup for GSL ODE solver; these choices don't need Jacobian */
98  Tpossible[0] = gsl_odeiv2_step_rk8pd;
99  Tpossible[1] = gsl_odeiv2_step_rk2;
100  Tpossible[2] = gsl_odeiv2_step_rkf45;
101  Tpossible[3] = gsl_odeiv2_step_rkck;
102  if ((ode_method > 0) && (ode_method < 5))
103  T = Tpossible[ode_method-1];
104  else {
105  return TESTL_INVALID_METHOD;
106  }
107 
108  /* check first: we have a list, and r is decreasing */
109  if (N < 1) return TESTL_NO_LIST;
110  for (k = 1; k<N; k++) { if (r[k] > r[k-1]) return TESTL_NOT_DECREASING; }
111 
112  /* outside of ice cap, u = 0 */
113  k = 0;
114  while (r[k] >= L) {
115  u[k] = 0.0;
116  k++;
117  if (k == N) return GSL_SUCCESS;
118  }
119 
120  /* initialize GSL ODE solver */
121  hstart = -10000.0;
122  d = gsl_odeiv2_driver_alloc_y_new(&sys, T, hstart, EPS_ABS, EPS_REL);
123 
124  /* initial conditions: (r,u) = (L,0); r decreases from L */
125  rr = L;
126  for (count = k; count < N; count++) {
127  /* except at start, use value at end of last interval as initial guess */
128  u[count] = (count == 0) ? 0.0 : u[count-1];
129  while (rr > r[count]) {
130  status = gsl_odeiv2_driver_apply(d, &rr, r[count], &(u[count]));
131  if (status != GSL_SUCCESS){
132  break;
133  }
134  }
135  }
136 
137  gsl_odeiv2_driver_free(d);
138  return status;
139 }
140 
141 #else /* old GSL (< 1.15) */
142 int getU(const double *r, int N, double *u,
143  const double EPS_ABS, const double EPS_REL, const int ode_method) {
144  (void) r;
145  (void) N;
146  (void) u;
147  (void) EPS_ABS;
148  (void) EPS_REL;
149  (void) ode_method;
150  throw RuntimeError(PISM_ERROR_LOCATION, "Test L requires GSL version 1.15 or later.");
151  return 0;
152 }
153 #endif
154 
155 int exactL_list(const double *r, int N, double *H, double *b, double *a) {
156  /* N values r[0] > r[1] > ... > r[N-1] (decreasing)
157  assumes r, H, b, a are allocated length N arrays */
158 
159  const double Lsqr = L * L;
160  const double a0 = 0.3 / SperA; /* m/s; i.e. 0.3 m/a */
161  int stat, i;
162 
163  std::vector<double> u(N);
164 
165  /* combination EPS_ABS = 1e-12, EPS_REL=0.0, method = 1 = RK Cash-Karp
166  believed to be predictable and accurate */
167  stat = getU(r,N,u.data(),1.0e-12,0.0,1);
168  if (stat != GSL_SUCCESS) {
169  return stat;
170  }
171 
172  for (i = 0; i < N; i++) {
173  H[i] = pow(u[i],3.0/8.0);
174  b[i] = - b0 * cos(z0 * M_PI * r[i] / L);
175  a[i] = a0 * (1.0 - (2.0 * r[i] * r[i] / Lsqr));
176  }
177 
178  return 0;
179 }
180 
182  : H(size), a(size), b(size) {
183 }
184 
185 ExactLParameters exactL(const std::vector<double> &r) {
186  ExactLParameters result(r.size());
187 
188  int error_code = exactL_list(&r[0], r.size(), &result.H[0], &result.b[0], &result.a[0]);
189 
190  switch (error_code) {
191  case TESTL_NOT_DONE:
192  throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Test L ERROR: exactL_list() returns 'NOT_DONE' (%d) ...",
193  error_code);
194  break;
196  throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Test L ERROR: exactL_list() returns 'NOT_DECREASING' (%d) ...",
197  error_code);
198  break;
200  throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Test L ERROR: exactL_list() returns 'INVALID_METHOD' (%d) ...",
201  error_code);
202  break;
203  case TESTL_NO_LIST:
204  throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Test L ERROR: exactL_list() returns 'NO_LIST' (%d) ...",
205  error_code);
206  break;
207  default:
208  break;
209  }
210 
211  return result;
212 }
#define PISM_ERROR_LOCATION
static const double L
Definition: exactTestL.cc:40
#define TESTL_NOT_DECREASING
Definition: exactTestL.cc:77
int funcL(double r, const double u[], double f[], void *params)
Definition: exactTestL.cc:47
#define TESTL_NO_LIST
Definition: exactTestL.cc:79
#define TESTL_NOT_DONE
Definition: exactTestL.cc:76
int exactL_list(const double *r, int N, double *H, double *b, double *a)
Definition: exactTestL.cc:155
static const double g
Definition: exactTestL.cc:43
static const double SperA
Definition: exactTestL.cc:38
static const double b0
Definition: exactTestL.cc:41
int getU(const double *r, int N, double *u, const double EPS_ABS, const double EPS_REL, const int ode_method)
Definition: exactTestL.cc:142
static const double z0
Definition: exactTestL.cc:42
ExactLParameters exactL(const std::vector< double > &r)
Definition: exactTestL.cc:185
static const double rho
Definition: exactTestL.cc:44
#define TESTL_INVALID_METHOD
Definition: exactTestL.cc:78
static const double n
Definition: exactTestL.cc:45
static const double k
Definition: exactTestP.cc:42
const int C[]
Definition: ssafd_code.cc:44
std::vector< double > b
Definition: exactTestL.hh:39
std::vector< double > H
Definition: exactTestL.hh:39
std::vector< double > a
Definition: exactTestL.hh:39
ExactLParameters(size_t n)
Definition: exactTestL.cc:181
int count
Definition: test_cube.c:16