PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/enthalpyConverter.cc

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