|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 /* 00002 Copyright (C) 2008 Ed Bueler 00003 00004 This file is part of PISM. 00005 00006 PISM is free software; you can redistribute it and/or modify it under the 00007 terms of the GNU General Public License as published by the Free Software 00008 Foundation; either version 2 of the License, or (at your option) any later 00009 version. 00010 00011 PISM is distributed in the hope that it will be useful, but WITHOUT ANY 00012 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00013 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 00014 details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with PISM; if not, write to the Free Software 00018 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 00022 #include <stdio.h> 00023 #include <stdlib.h> 00024 #include <math.h> 00025 #include <gsl/gsl_errno.h> 00026 #include <gsl/gsl_matrix.h> 00027 #include <gsl/gsl_odeiv.h> 00028 #include "exactTestM.h" 00029 00030 #define MAX(a, b) (a > b ? a : b) 00031 #define MIN(a, b) (a > b ? b : a) 00032 00033 #define pi 3.1415926535897931 00034 #define SperA 31556926.0 /* seconds per year; 365.2422 days */ 00035 #define g 9.81 00036 #define rho 910.0 /* ice density; kg/m^3 */ 00037 #define rhow 1028.0 /* sea water density; kg/m^3 */ 00038 #define n 3.0 /* Glen power */ 00039 #define barB 3.7e8 /* strength of shelf; Pa s^(1/3); as in Schoof 2006; 00040 compare 1.9e8 from MacAyeal et al 1996 */ 00041 #define H0 500.0 /* m */ 00042 #define Rg 300.0e3 /* m; 300 km */ 00043 #define Rc 600.0e3 /* m; 600 km */ 00044 00045 00046 double F_M(double x, double alpha, double r, double Q) { 00047 const double 00048 aor = alpha / r, 00049 DD = x * x + x * aor + pow(aor, 2.0); 00050 return Q * pow(DD, 1./3.) - 2.0 * r * x - alpha; 00051 } 00052 00053 00054 double dF_M(double x, double alpha, double r, double Q) { 00055 const double 00056 aor = alpha / r, 00057 DD = x * x + x * aor + pow(aor, 2.0); 00058 return (1. / 3.) * Q * pow(DD, - 2./3.) * (2.0 * x + aor) - 2.0 * r; 00059 } 00060 00061 00062 int funcM_ode_G(double r, const double alpha[], double f[], void* params) { 00063 /* RHS G for differential equation: 00064 alpha' = G(alpha,r) 00065 but where we solve this equation to find alpha': 00066 F(alpha',alpha,r) = 0 00067 heuristic: guess is about 1/7 th of solution to a nearby problem; 00068 no range checking on r, so use away from zero */ 00069 00070 const double Q = (1.0 - rho / rhow) * rho * g * Rc * H0 / (2.0 * barB), 00071 guess = 0.15 * ( pow(Q/r,n) - alpha[0]/r ); 00072 /* in Python (exactM.py): f[0] = fsolve(F_M,guess,args=(alpha[0],r)); 00073 we could call GSL to find root, but hand-coding Newton's is easier */ 00074 double Old = guess, New; /* capitalized to avoid the C++ keyword name 00075 clash */ 00076 int i; 00077 for (i = 1; i < 100; i++) { 00078 New = Old - F_M(Old,alpha[0],r,Q) / dF_M(Old,alpha[0],r,Q); 00079 if (fabs((New-Old)/Old) < 1.0e-12) break; 00080 Old = New; 00081 } 00082 if (i >= 90) 00083 printf("exactTestM WARNING: Newton iteration not converged in funcM_ode_G!\n"); 00084 f[0] = New; 00085 return GSL_SUCCESS; 00086 } 00087 00088 00089 #define NOT_DONE 8966 00090 #define INVALID_METHOD 8968 00091 #define NEGATIVE_R 8969 00092 00093 /* combination EPS_ABS = 1e-12, EPS_REL=0.0, method = 1 = RK Cash-Karp 00094 is believed to be predictable and accurate; returns GSL_SUCCESS=0 if success */ 00095 int exactM(double r, 00096 double *alpha, double *Drr, 00097 const double EPS_ABS, const double EPS_REL, const int ode_method) { 00098 00099 double ug = 100.0 / SperA; /* velocity across grounding line is 100 m/a */ 00100 double DrrRg, xx, xA, nu, aa, rr, myalf, step; 00101 const gsl_odeiv_step_type* T; 00102 int status = NOT_DONE; 00103 gsl_odeiv_step* s; 00104 gsl_odeiv_control* c; 00105 gsl_odeiv_evolve* e; 00106 gsl_odeiv_system sys = {funcM_ode_G, NULL, 1, NULL}; /* Jac-free method and no params */ 00107 00108 if (r < 0) { 00109 return NEGATIVE_R; /* only nonnegative radial coord allowed */ 00110 } else if (r <= Rg/4.0) { 00111 *alpha = 0.0; /* zero velocity near center */ 00112 *Drr = 0.0; 00113 return GSL_SUCCESS; 00114 } else if (r <= Rg) { 00115 /* power law from alpha=0 to alpha=ug in Rg/4 < r <= Rg; 00116 f(r) w: f(Rg/4)=f'(Rg/4)=0 and f(Rg)=ug and f(Rg) = DrrRg */ 00117 funcM_ode_G(Rg, &ug, &DrrRg, NULL); /* first get Drr = alpha' at Rg where alpha=ug */ 00118 /* printf("DrrRg=%e (1/a)\n",DrrRg*SperA); */ 00119 xx = r - 0.25 * Rg; 00120 xA = 0.75 * Rg; 00121 nu = DrrRg * xA / ug; 00122 aa = ug / pow(xA, nu); 00123 /* printf("power nu=%e\n",nu); */ 00124 *alpha = aa * pow(xx, nu); 00125 *Drr = aa * nu * pow(xx, nu - 1); 00126 return GSL_SUCCESS; 00127 } else if (r >= Rc + 1.0) { 00128 *alpha = 0.0; /* zero velocity beyond calving front */ 00129 *Drr = 0.0; 00130 return GSL_SUCCESS; 00131 } 00132 00133 /* need to solve ODE to find alpha, so setup for GSL ODE solver */ 00134 switch (ode_method) { 00135 case 1: 00136 T = gsl_odeiv_step_rkck; /* RK Cash-Karp */ 00137 break; 00138 case 2: 00139 T = gsl_odeiv_step_rk2; 00140 break; 00141 case 3: 00142 T = gsl_odeiv_step_rk4; 00143 break; 00144 case 4: 00145 T = gsl_odeiv_step_rk8pd; 00146 break; 00147 default: 00148 printf("INVALID ode_method in exactM(): must be 1,2,3,4\n"); 00149 return INVALID_METHOD; 00150 } 00151 s = gsl_odeiv_step_alloc(T, (size_t)1); /* one scalar ode */ 00152 c = gsl_odeiv_control_y_new(EPS_ABS,EPS_REL); 00153 e = gsl_odeiv_evolve_alloc((size_t)1); /* one scalar ode */ 00154 00155 /* initial conditions: (r,alf) = (Rg,ug); r increases */ 00156 rr = Rg; 00157 myalf = ug; 00158 /* printf (" r (km) alpha (m/a)\n"); 00159 printf (" %11.5e %11.5e\n", rr/1000.0, myalf * SperA); */ 00160 while (rr < r) { 00161 /* step = r - rr; try to get to solution in one step; trust stepping algorithm */ 00162 step = MIN(r-rr,20.0e3); 00163 status = gsl_odeiv_evolve_apply(e, c, s, &sys, &rr, r, &step, &myalf); 00164 if (status != GSL_SUCCESS) break; 00165 /* printf (" %11.5e %11.5e\n", rr/1000.0, myalf * SperA); */ 00166 } 00167 00168 gsl_odeiv_evolve_free(e); 00169 gsl_odeiv_control_free(c); 00170 gsl_odeiv_step_free(s); 00171 00172 *alpha = myalf; 00173 funcM_ode_G(r, alpha, Drr, NULL); 00174 return status; 00175 } 00176
1.7.3