|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 // Copyright (C) 2009-2011 Andreas Aschwanden, Ed Bueler and Constantine Khroulev 00002 // 00003 // This file is part of PISM. 00004 // 00005 // PISM is free software; you can redistribute it and/or modify it under the 00006 // terms of the GNU General Public License as published by the Free Software 00007 // Foundation; either version 2 of the License, or (at your option) any later 00008 // version. 00009 // 00010 // PISM is distributed in the hope that it will be useful, but WITHOUT ANY 00011 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00012 // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 00013 // details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with PISM; if not, write to the Free Software 00017 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 #include <petsc.h> // for PetscErrorPrintf, etc. 00020 #include "pism_const.hh" 00021 #include "enthalpyConverter.hh" 00022 00023 00024 EnthalpyConverter::EnthalpyConverter(const NCConfigVariable &config) { 00025 beta = config.get("beta_CC"); // K Pa-1 00026 c_i = config.get("ice_specific_heat_capacity"); // J kg-1 K-1 00027 g = config.get("standard_gravity"); // m s-2 00028 L = config.get("water_latent_heat_fusion"); // J kg-1 00029 p_air = config.get("surface_pressure"); // Pa 00030 rho_i = config.get("ice_density"); // kg m-3 00031 T_melting = config.get("water_melting_point_temperature"); // K 00032 T_tol = config.get("cold_mode_is_temperate_ice_tolerance"); // K 00033 T_0 = config.get("enthalpy_converter_reference_temperature");// K 00034 00035 do_cold_ice_methods = config.get_flag("do_cold_ice_methods"); 00036 } 00037 00038 00040 PetscErrorCode EnthalpyConverter::viewConstants(PetscViewer viewer) const { 00041 PetscErrorCode ierr; 00042 00043 PetscTruth iascii; 00044 if (!viewer) { 00045 ierr = PetscViewerASCIIGetStdout(PETSC_COMM_WORLD,&viewer); CHKERRQ(ierr); 00046 } 00047 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii); CHKERRQ(ierr); 00048 if (!iascii) { SETERRQ(1,"Only ASCII viewer for EnthalpyConverter\n"); } 00049 00050 ierr = PetscViewerASCIIPrintf(viewer, 00051 "\n<showing EnthalpyConverter constants:\n"); CHKERRQ(ierr); 00052 ierr = PetscViewerASCIIPrintf(viewer, 00053 " beta = %12.5e (K Pa-1)\n", beta); CHKERRQ(ierr); 00054 ierr = PetscViewerASCIIPrintf(viewer, 00055 " c_i = %12.5f (J kg-1 K-1)\n",c_i); CHKERRQ(ierr); 00056 ierr = PetscViewerASCIIPrintf(viewer, 00057 " g = %12.5f (m s-2)\n", g); CHKERRQ(ierr); 00058 ierr = PetscViewerASCIIPrintf(viewer, 00059 " L = %12.5e (J kg-1)\n", L); CHKERRQ(ierr); 00060 ierr = PetscViewerASCIIPrintf(viewer, 00061 " p_air = %12.5e (Pa)\n", p_air); CHKERRQ(ierr); 00062 ierr = PetscViewerASCIIPrintf(viewer, 00063 " rho_i = %12.5f (kg m-3)\n", rho_i); CHKERRQ(ierr); 00064 ierr = PetscViewerASCIIPrintf(viewer, 00065 " T_melting = %12.5f (K)\n", T_melting); CHKERRQ(ierr); 00066 ierr = PetscViewerASCIIPrintf(viewer, 00067 " T_tol = %12.5f (K)\n", T_tol); CHKERRQ(ierr); 00068 ierr = PetscViewerASCIIPrintf(viewer, 00069 " T_0 = %12.5f (K)\n", T_0); CHKERRQ(ierr); 00070 ierr = PetscViewerASCIIPrintf(viewer, 00071 " do_cold_ice_methods = %s\n", (do_cold_ice_methods) ? "true" : "false"); 00072 CHKERRQ(ierr); 00073 ierr = PetscViewerASCIIPrintf(viewer, 00074 ">\n"); CHKERRQ(ierr); 00075 return 0; 00076 } 00077 00078 00080 00086 double EnthalpyConverter::getPressureFromDepth(double depth) const { 00087 if (depth <= 0.0) { // at or above surface of ice 00088 return p_air; 00089 } else { 00090 return p_air + rho_i * g * depth; 00091 } 00092 } 00093 00094 00096 00099 double EnthalpyConverter::getMeltingTemp(double p) const { 00100 return T_melting - beta * p; 00101 } 00102 00103 00105 00108 double EnthalpyConverter::getEnthalpyCTS(double p) const { 00109 return c_i * (getMeltingTemp(p) - T_0); 00110 } 00111 00112 00114 00118 PetscErrorCode EnthalpyConverter::getEnthalpyInterval( 00119 double p, double &E_s, double &E_l) const { 00120 E_s = getEnthalpyCTS(p); 00121 E_l = E_s + L; 00122 return 0; 00123 } 00124 00125 00127 00135 double EnthalpyConverter::getCTS(double E, double p) const { 00136 const double E_s = getEnthalpyCTS(p); 00137 return E / E_s; 00138 } 00139 00140 00142 bool EnthalpyConverter::isTemperate(double E, double p) const { 00143 if (do_cold_ice_methods) { 00144 double T_pa; 00145 getPATemp(E, p, T_pa); 00146 return (T_pa >= T_melting - T_tol); 00147 } else 00148 return (E >= getEnthalpyCTS(p)); 00149 } 00150 00151 00153 00162 PetscErrorCode EnthalpyConverter::getAbsTemp(double E, double p, double &T) const { 00163 double E_s, E_l; 00164 PetscErrorCode ierr = getEnthalpyInterval(p, E_s, E_l); CHKERRQ(ierr); 00165 if (E >= E_l) { // enthalpy equals or exceeds that of liquid water 00166 T = getMeltingTemp(p); 00167 return 1; 00168 } 00169 if (E < E_s) { 00170 T = (E / c_i) + T_0; 00171 } else { 00172 T = getMeltingTemp(p); 00173 } 00174 return 0; 00175 } 00176 00177 00179 00183 PetscErrorCode EnthalpyConverter::getPATemp(double E, double p, double &T_pa) const { 00184 PetscErrorCode ierr; 00185 double T = 0; // initialized to avoid a compiler warning 00186 ierr = getAbsTemp(E,p,T); CHKERRQ(ierr); 00187 T_pa = T - getMeltingTemp(p) + T_melting; 00188 return 0; 00189 } 00190 00191 00193 00202 PetscErrorCode EnthalpyConverter::getWaterFraction(double E, double p, double &omega) const { 00203 double E_s, E_l; 00204 PetscErrorCode ierr = getEnthalpyInterval(p, E_s, E_l); CHKERRQ(ierr); 00205 if (E >= E_l) { 00206 omega = 1.0; 00207 return 1; 00208 } 00209 if (E <= E_s) { 00210 omega = 0.0; 00211 } else { 00212 omega = (E - E_s) / L; 00213 } 00214 return 0; 00215 } 00216 00217 00219 bool EnthalpyConverter::isLiquified(double E, double p) const { 00220 double E_s, E_l; 00221 getEnthalpyInterval(p, E_s, E_l); 00222 return (E >= E_l); 00223 } 00224 00225 00227 00241 PetscErrorCode EnthalpyConverter::getEnth( 00242 double T, double omega, double p, double &E) const { 00243 const double T_m = getMeltingTemp(p); 00244 if (T <= 0.0) { 00245 SETERRQ1(1,"\n\nT = %f <= 0 is not a valid absolute temperature\n\n",T); 00246 } 00247 if ((omega < 0.0 - 1.0e-6) || (1.0 + 1.0e-6 < omega)) { 00248 SETERRQ1(2,"\n\nwater fraction omega=%f not in range [0,1]\n\n",omega); 00249 } 00250 if (T > T_m + 1.0e-6) { 00251 SETERRQ2(3,"T=%f exceeds T_m=%f; not allowed\n\n",T,T_m); 00252 } 00253 if ((T < T_m - 1.0e-6) && (omega > 0.0 + 1.0e-6)) { 00254 SETERRQ3(4,"T < T_m AND omega > 0 is contradictory\n\n",T,T_m,omega); 00255 } 00256 if (T < T_m) { 00257 E = c_i * (T - T_0); 00258 } else { 00259 E = getEnthalpyCTS(p) + omega * L; 00260 } 00261 return 0; 00262 } 00263 00264 00266 00285 PetscErrorCode EnthalpyConverter::getEnthPermissive( 00286 double T, double omega, double p, double &E) const { 00287 PetscErrorCode ierr; 00288 if (T <= 0.0) { 00289 SETERRQ1(1,"\n\nT = %f <= 0 is not a valid absolute temperature\n\n",T); 00290 } 00291 const double T_m = getMeltingTemp(p); 00292 if (T < T_m) { 00293 ierr = getEnth(T, 0.0, p, E); CHKERRQ(ierr); 00294 } else { // T >= T_m(p) replaced with T = T_m(p) 00295 ierr = getEnth(T_m, PetscMax(0.0,PetscMin(omega,1.0)), p, E); CHKERRQ(ierr); 00296 } 00297 return 0; 00298 } 00299 00300 00302 00308 PetscErrorCode EnthalpyConverter::getEnthAtWaterFraction( 00309 double omega, double p, double &E) const { 00310 if ((omega < 0.0 - 1.0e-6) || (1.0 + 1.0e-6 < omega)) { 00311 SETERRQ1(2,"\n\nwater fraction omega=%f not in range [0,1]\n\n",omega); 00312 } 00313 E = getEnthalpyCTS(p) + omega * L; 00314 return 0; 00315 } 00316
1.7.3