|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 /* 00002 Copyright (C) 2007, 2011 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 #include <stdio.h> 00022 #include <math.h> 00023 #include <gsl/gsl_errno.h> 00024 #include <gsl/gsl_math.h> 00025 #include <gsl/gsl_roots.h> 00026 #include "exactTestK.h" 00027 00028 #define pi 3.1415926535897931 00029 #define SperA 31556926.0 /* seconds per year; 365.2422 days */ 00030 00031 #define c_p_ICE 2009.0 /* J/(kg K) specific heat capacity of ice */ 00032 #define rho_ICE 910.0 /* kg/(m^3) density of ice */ 00033 #define k_ICE 2.10 /* J/(m K s) = W/(m K) thermal conductivity of ice */ 00034 #define c_p_BRdefault 1000.0 /* J/(kg K) specific heat capacity of bedrock */ 00035 #define rho_BRdefault 3300.0 /* kg/(m^3) density of bedrock */ 00036 #define k_BRdefault 3.0 /* J/(m K s) = W/(m K) thermal conductivity of bedrock */ 00037 00038 #define H0 3000.0 /* m */ 00039 #define B0 1000.0 /* m */ 00040 #define Ts 223.15 /* K */ 00041 #define G 0.042 /* W/(m^2) */ 00042 #define phi 0.0125 /* K/m */ 00043 00044 #define Nsum 30 /* number of terms in eigenfunction expansion; the exact 00045 solution is deliberately chosen to have finite expansion */ 00046 00047 00048 int exactK(const double t, const double z, double *TT, double *FF, const int bedrockIsIce_p) { 00049 int k; 00050 int belowB0; 00051 double ZZ, alpha, lambda, beta, my_gamma, XkSQR, Xk, 00052 theta, dthetakdz, P, dPdz, 00053 Ck, I1, I2, aH, bB, mI, mR; 00054 double c_p_BR, rho_BR, k_BR; 00055 /* following constants were produced by calling print_alpha_k(30) (below) */ 00056 double alf[Nsum] = {3.350087528822397e-04, 1.114576827617396e-03, 1.953590840303518e-03, 00057 2.684088585781064e-03, 3.371114869333445e-03, 4.189442265117592e-03, 00058 5.008367405382524e-03, 5.696044031764593e-03, 6.425563506942886e-03, 00059 7.264372872913219e-03, 8.044853066396166e-03, 8.714877612414516e-03, 00060 9.493529164160654e-03, 1.033273985210279e-02, 1.106421822502108e-02, 00061 1.175060460132703e-02, 1.256832682090360e-02, 1.338784224692084e-02, 00062 1.407617951778051e-02, 1.480472324161026e-02, 1.564331999062109e-02, 00063 1.642470780103220e-02, 1.709475346624607e-02, 1.787248418996684e-02, 00064 1.871188358061674e-02, 1.944434477688470e-02, 2.013010181370026e-02, 00065 2.094721145334310e-02, 2.176730968036079e-02, 2.245631776169424e-02}; 00066 00067 if (bedrockIsIce_p) { 00068 c_p_BR = c_p_ICE; 00069 rho_BR = rho_ICE; 00070 k_BR = k_ICE; 00071 for (k = 0; k < Nsum; k++) { /* overwrite alpha_k with ice-meets-ice values; see preprint */ 00072 alf[k] = (2.0 * k + 1.0) * pi / (2.0 * (H0 + B0)); 00073 } 00074 } else { 00075 c_p_BR = c_p_BRdefault; 00076 rho_BR = rho_BRdefault; 00077 k_BR = k_BRdefault; 00078 } 00079 if (z > H0) { 00080 *TT = Ts; 00081 return 0; 00082 } 00083 belowB0 = (z < -B0); 00084 00085 ZZ = sqrt((rho_BR * c_p_BR * k_ICE) / (rho_ICE * c_p_ICE * k_BR)); 00086 mI = (G / k_ICE) - phi; mR = (G / k_BR) - phi; 00087 /* DEBUG: printf("ZZ = %10e, mI = %10e, mR = %10e\n", ZZ,mI,mR); */ 00088 *TT = 0.0; 00089 *FF = 0.0; 00090 for (k = Nsum-1; k >= 0; k--) { 00091 /* constants only having to do with eigenfunctions; theta = theta_k(z) is the 00092 normalized eigenfunction */ 00093 alpha = alf[k]; 00094 beta = ZZ * alpha; 00095 my_gamma = sin(alpha * H0) / cos(beta * B0); 00096 XkSQR = (rho_BR * c_p_BR * my_gamma * my_gamma * B0 + rho_ICE * c_p_ICE * H0) / 2.0; 00097 Xk = sqrt(XkSQR); 00098 /* theta = ( (z > 0) ? sin(alpha * (H0 - z)) : my_gamma * cos(beta * (B0 + z)) ) / Xk; */ 00099 theta = (z > 0) ? sin(alpha * (H0 - z)) 00100 : my_gamma * cos(beta * (B0 + z)); 00101 theta /= Xk; 00102 dthetakdz = (z > 0) ? - alpha * cos(alpha * (H0 - z)) 00103 : - beta * my_gamma * sin(beta * (B0 + z)); 00104 dthetakdz /= Xk; 00105 lambda = (k_ICE * alpha * alpha) / (rho_ICE * c_p_ICE); 00106 /* DEBUG: printf("k = %3d: alpha = %10e, Xk = %10e, theta = %10e, dthetakdz = %10e, lambda = %10e,\n", 00107 k,alpha,Xk,theta,dthetakdz,lambda); */ 00108 /* constants involved in computing the expansion coefficients */ 00109 aH = alpha * H0; bB = beta * B0; 00110 I1 = - mI * (sin(aH) - aH * cos(aH)) / (alpha * alpha); 00111 I2 = mR * (cos(bB) - 1.0 + bB * sin(bB)) / (beta * beta) 00112 - (B0 * mR + H0 * mI) * sin(bB) / beta; 00113 Ck = (rho_ICE * c_p_ICE * I1 + rho_BR * c_p_BR * my_gamma * I2) / Xk; 00114 /* add the term to the expansion */ 00115 *TT += Ck * exp(- lambda * t) * theta; 00116 *FF += - ((z > 0) ? k_ICE : k_BR) * Ck * exp(- lambda * t) * dthetakdz; 00117 /* DEBUG: printf(" I1 = %10e, I2 = %10e, Ck = %10e, term = %10f\n", 00118 I1,I2,Ck, Ck * exp(- lambda * t) * theta ); */ 00119 } 00120 /* P = (z >= 0) ? (z / k_ICE) - (H0 / k_ICE) : (z / k_BR) - (H0 / k_ICE); */ 00121 P = (z / ((z > 0) ? k_ICE : k_BR)) - (H0 / k_ICE); 00122 dPdz = 1.0 / ((z > 0) ? k_ICE : k_BR); 00123 *TT += Ts - G * P; 00124 *FF += ((z > 0) ? k_ICE : k_BR) * G * dPdz; 00125 00126 return belowB0; 00127 00128 } 00129 00130 00131 #define COMPUTE_ALPHA 0 00132 #if COMPUTE_ALPHA 00133 00134 #define ALPHA_RELTOL 1.0e-14 00135 #define ITER_MAXED_OUT 999 00136 00137 /* parameters needed for root problem: */ 00138 struct coscross_params { 00139 double Afrac, HZBsum, HZBdiff; 00140 }; 00141 00142 /* the root problem is to make this function zero: */ 00143 double coscross(double alpha, void *params) { 00144 struct coscross_params *p = (struct coscross_params *) params; 00145 return cos(p->HZBsum * alpha) - p->Afrac * cos(p->HZBdiff * alpha); 00146 } 00147 00148 /* compute the first N roots alpha_k of the equation 00149 ((A-1)/(A+1)) cos((H - Z B) alpha) = cos((H + Z B) alpha) 00150 where H and B are heights and A, Z are defined in terms of material 00151 constants */ 00152 int print_alpha_k(const int N) { 00153 int status, iter, k, max_iter = 200; 00154 double Z, A; 00155 double alpha, alpha_lo, alpha_hi, temp_lo; 00156 const gsl_root_fsolver_type *solvT; 00157 gsl_root_fsolver *solv; 00158 gsl_function F; 00159 struct coscross_params params; 00160 00161 Z = sqrt((rho_BR * c_p_BR * k_ICE) / (rho_ICE * c_p_ICE * k_BR)); 00162 A = (k_BR / k_ICE) * Z; 00163 params.Afrac = (A - 1.0) / (A + 1.0); 00164 params.HZBsum = H0 + Z * B0; 00165 params.HZBdiff = H0 - Z * B0; 00166 00167 F.function = &coscross; 00168 F.params = ¶ms; 00169 solvT = gsl_root_fsolver_brent; /* faster than bisection but still bracketing */ 00170 solv = gsl_root_fsolver_alloc(solvT); 00171 00172 for (k = 0; k < N; k++) { 00173 /* these numbers bracket exactly one solution */ 00174 alpha_lo = (double(k) * pi) / params.HZBsum; 00175 alpha_hi = (double(k + 1) * pi) / params.HZBsum; 00176 gsl_root_fsolver_set(solv, &F, alpha_lo, alpha_hi); 00177 00178 iter = 0; 00179 do { 00180 iter++; 00181 status = gsl_root_fsolver_iterate(solv); 00182 alpha = gsl_root_fsolver_root(solv); 00183 alpha_lo = gsl_root_fsolver_x_lower(solv); 00184 alpha_hi = gsl_root_fsolver_x_upper(solv); 00185 temp_lo = (alpha_lo > 0) ? alpha_lo : (alpha_hi/2.0); 00186 status = gsl_root_test_interval(temp_lo, alpha_hi, 0, ALPHA_RELTOL); 00187 } while ((status == GSL_CONTINUE) && (iter < max_iter)); 00188 if (iter >= max_iter) { 00189 printf("!!!ERROR: root finding iteration reached maximum iterations; QUITING!\n"); 00190 return ITER_MAXED_OUT; 00191 } 00192 printf("%19.15e,\n",alpha); 00193 /* DEBUG: printf("%19.15e (in orig bracket [%19.15e,%19.15e])\n",alpha, 00194 (double(k) * pi) / params.HZBsum, (double(k+1) * pi) / params.HZBsum); */ 00195 } 00196 00197 gsl_root_fsolver_free(solv); 00198 return status; 00199 } 00200 #endif /* COMPUTE_ALPHA */ 00201
1.7.3