|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 /* 00002 Copyright (C) 2004-2008 Ed Bueler and Jed Brown 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 #include <stdio.h> 00022 #include <stdlib.h> 00023 #include <math.h> 00024 #include "exactTestsFG.h" 00025 00026 static double p3(double x) { 00027 /* p_3=x^3-3*x^2+6*x-6, using Horner's */ 00028 return -6.0 + x*(6.0 + x*(-3.0 + x)); 00029 } 00030 00031 static double p4(double x) { 00032 /* p_4=x^4-4*x^3+12*x^2-24*x+24, using Horner's */ 00033 return 24.0 + x*(-24.0 + x*(12.0 + x*(-4.0 + x))); 00034 } 00035 00036 int bothexact(double t, double r, double *z, int Mz, double Cp, 00037 double *Hreturn, double *M, double *TT, 00038 double *Ureturn, double *wreturn, 00039 double *Sigreturn, double *Sigc) { 00040 00041 const double pi = 3.14159265358979; 00042 const double SperA = 31556926.0; /* seconds per year; 365.2422 days */ 00043 00044 /* parameters describing extent of sheet: */ 00045 const double H0=3000.0; /* m */ 00046 const double L=750000.0; /* m */ 00047 /* period of perturbation; inactive in Test F: */ 00048 const double Tp=2000.0*SperA; /* s */ 00049 00050 /* fundamental physical constants */ 00051 const double g=9.81; /* m/s^2; accel of gravity */ 00052 const double Rgas=8.314; /* J/(mol K) */ 00053 /* ice properties; parameters which appear in constitutive relation: */ 00054 const double rho=910.0; /* kg/m^3; density */ 00055 const double k=2.1; /* J/m K s; thermal conductivity */ 00056 const double cpheat=2009.0;/* J/kg K; specific heat capacity */ 00057 const double n=3.0; /* Glen exponent */ 00058 /* next two are EISMINT II values; Paterson-Budd for T<263 */ 00059 const double A=3.615E-13; /* Pa^-3 s^-1 */ 00060 const double Q=6.0E4; /* J/mol */ 00061 /* EISMINT II temperature boundary condition (Experiment F): */ 00062 const double Ggeo=0.042; /* J/m^2 s; geo. heat flux */ 00063 const double ST=1.67E-5; /* K m^-1 */ 00064 const double Tmin=223.15; /* K */ 00065 const double Kcond=k/(rho*cpheat); /* constant in temp eqn */ 00066 00067 /* declare all temporary quantities; computed in blocks below */ 00068 double power, Hconst, s, lamhat, f, goft, Ts, nusqrt, nu; 00069 double lamhatr, fr, Hr, mu, surfArr, Uconst, omega; 00070 double Sigmu, lamhatrr, frr, Hrr, Tsr, nur, mur, phi, gam; 00071 double I4H, divQ, Ht, nut; 00072 double I4,dTt,Tr,Tz,Tzz; 00073 double H, *U, *w, *Sig; /* compute with these; return copies */ 00074 int i; 00075 double *I3; 00076 00077 I3 = (double *) malloc((size_t)Mz * sizeof(double)); /* need temporary arrays */ 00078 U = (double *) malloc((size_t)Mz * sizeof(double)); 00079 w = (double *) malloc((size_t)Mz * sizeof(double)); 00080 Sig = (double *) malloc((size_t)Mz * sizeof(double)); 00081 if ((I3 == NULL) || (U == NULL) || (w == NULL) || (Sig == NULL)) { 00082 fprintf(stderr, "\nERROR bothexact(): couldn't allocate memory!\n\n"); 00083 return -9999; 00084 } 00085 00086 if ( (r<=0) || (r>=L) ) { 00087 fprintf(stderr, "\nERROR bothexact(): code and derivation assume 0<r<L !\n\n"); 00088 return 1; 00089 } 00090 00091 /* compute H from analytical steady state Hs (Test D) plus perturbation */ 00092 power = n/(2*n+2); 00093 Hconst = H0/pow(1-1/n,power); 00094 s = r/L; 00095 lamhat = (1+1/n)*s - (1/n) + pow(1-s,1+1/n) - pow(s,1+1/n); 00096 if ((r>0.3*L) && (r<0.9*L)) 00097 f = pow( cos(pi*(r-0.6*L)/(0.6*L)) ,2.0); 00098 else 00099 f = 0.0; 00100 goft = Cp*sin(2.0*pi*t/Tp); 00101 H = Hconst*pow(lamhat,power) + goft*f; 00102 00103 /* compute TT = temperature */ 00104 Ts = Tmin+ST*r; 00105 nusqrt = sqrt( 1 + (4.0*H*Ggeo)/(k*Ts) ); 00106 nu = ( k*Ts/(2.0*Ggeo) )*( 1 + nusqrt ); 00107 for (i=0; i<Mz; i++) { 00108 if (z[i] < H) { 00109 TT[i] = Ts * (nu+H) / (nu+z[i]); 00110 } else { /* surface value above ice surface; matches numerical way */ 00111 TT[i] = Ts; 00112 } 00113 /* old way: extend formula above surface: TT[i] = Ts * (nu+H) / (nu+z[i]); */ 00114 } 00115 00116 /* compute surface slope and horizontal velocity */ 00117 lamhatr = ((1+1/n)/L)*( 1 - pow(1-s,1/n) - pow(s,1/n) ); 00118 if ( (r>0.3*L) && (r<0.9*L) ) 00119 fr = -(pi/(0.6*L)) * sin(2.0*pi*(r-0.6*L)/(0.6*L)); 00120 else 00121 fr = 0.0; 00122 Hr = Hconst * power * pow(lamhat,power-1) * lamhatr + goft*fr; /* chain rule */ 00123 if ( Hr>0 ) { 00124 fprintf(stderr, "\nERROR bothexact(): assumes H_r negative for all 0<r<L !\n\n"); 00125 return 2; 00126 } 00127 mu = Q/(Rgas*Ts*(nu+H)); 00128 surfArr = exp(-Q/(Rgas*Ts)); 00129 Uconst = 2.0 * pow(rho*g,n) * A; 00130 omega = Uconst * pow(-Hr,n) * surfArr * pow(mu,-n-1); 00131 for (i=0; i<Mz; i++) { 00132 if (z[i] < H) { 00133 I3[i] = p3(mu*H) * exp(mu*H) - p3(mu*(H-z[i])) * exp(mu*(H-z[i])); 00134 U[i] = omega * I3[i]; 00135 } else { /* surface value above ice surface; matches numerical way */ 00136 I3[i] = p3(mu*H) * exp(mu*H) - p3(0.0); /* z[i] = H case in above */ 00137 U[i] = omega * I3[i]; 00138 } 00139 } 00140 00141 /* compute strain heating */ 00142 for (i=0; i<Mz; i++) { 00143 if (z[i] < H) { 00144 Sigmu = -(Q*(nu+z[i])) / (Rgas*Ts*(nu+H)); 00145 Sig[i] = (Uconst*g/cpheat) * exp(Sigmu) * pow( fabs(Hr)*( H -z[i]) ,n+1); 00146 } else { 00147 Sig[i] = 0.0; 00148 } 00149 } 00150 00151 /* compute vertical velocity */ 00152 lamhatrr = ((1+1/n) / (n*L*L)) * ( pow(1-s,(1/n)-1) - pow(s,(1/n)-1) ); 00153 if ( (r>0.3*L) && (r<0.9*L) ) 00154 frr = -(2.0*pi*pi/(0.36*L*L)) * cos(2.0*pi*(r-0.6*L)/(0.6*L)); 00155 else 00156 frr = 0.0; 00157 Hrr = Hconst*power*(power-1)*pow(lamhat,power-2.0) * pow(lamhatr,2.0) + 00158 Hconst*power*pow(lamhat,power-1)*lamhatrr + goft*frr; 00159 Tsr = ST; 00160 nur = (k*Tsr/(2.0*Ggeo)) * (1 + nusqrt) + 00161 (1/Ts) * (Hr*Ts-H*Tsr) / nusqrt; 00162 mur = ( -Q/(Rgas*Ts*Ts*pow(nu+H,2.0)) ) * ( Tsr*(nu+H)+Ts*(nur+Hr) ); 00163 phi = 1/r + n*Hrr/Hr + Q*Tsr/(Rgas*Ts*Ts) - (n+1)*mur/mu; /* division by r */ 00164 gam = pow(mu,n) * exp(mu*H) * (mur*H+mu*Hr) * pow(H,n); 00165 for (i=0; i<Mz; i++) { 00166 I4 = p4(mu*H) * exp(mu*H) - p4(mu*(H-z[i])) * exp(mu*(H-z[i])); 00167 w[i] = omega * ((mur/mu - phi)*I4/mu + (phi*(H-z[i])+Hr)*I3[i] - gam*z[i]); 00168 } 00169 00170 /* compute compensatory accumulation M */ 00171 I4H = p4(mu*H) * exp(mu*H) - 24.0; 00172 divQ = - omega * (mur/mu - phi) * I4H / mu + omega * gam * H; 00173 Ht = (Cp*2.0*pi/Tp) * cos(2.0*pi*t/Tp) * f; 00174 *M = Ht + divQ; 00175 00176 /* compute compensatory heating */ 00177 nut = Ht/nusqrt; 00178 for (i=0; i<Mz; i++) { 00179 if (z[i] < H) { 00180 dTt = Ts * ((nut+Ht)*(nu+z[i])-(nu+H)*nut) * pow(nu+z[i],-2.0); 00181 Tr = Tsr*(nu+H)/(nu+z[i]) 00182 + Ts * ((nur+Hr)*(nu+z[i])-(nu+H)*nur) * pow(nu+z[i],-2.0); 00183 Tz = -Ts * (nu+H) * pow(nu+z[i],-2.0); 00184 Tzz = 2.0 * Ts * (nu+H) * pow(nu+z[i],-3.0); 00185 Sigc[i] = dTt + U[i]*Tr + w[i]*Tz - Kcond*Tzz - Sig[i]; 00186 } else { 00187 Sigc[i] = 0.0; 00188 } 00189 } 00190 00191 /* return duplicate copies to avoid conflicts */ 00192 *Hreturn = H; 00193 for (i=0; i<Mz; i++) { 00194 Ureturn[i] = U[i]; 00195 wreturn[i] = w[i]; 00196 Sigreturn[i] = Sig[i]; 00197 } 00198 00199 free(I3); free(U); free(w); free(Sig); 00200 return 0; 00201 } 00202
1.7.3