PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/verif/tests/exactTestM.c

Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines