|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 // Copyright (C) 2009-2011 Andreas Aschwanden and 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 "enthalpyConverter.hh" 00020 #include "enthSystem.hh" 00021 #include <gsl/gsl_math.h> 00022 00023 00024 enthSystemCtx::enthSystemCtx( 00025 const NCConfigVariable &config, IceModelVec3 &my_Enth3, int my_Mz, string my_prefix) 00026 : columnSystemCtx(my_Mz, my_prefix) { // <- critical: sets size of sys 00027 Mz = my_Mz; 00028 00029 // set some values so we can check if init was called 00030 nuEQ = -1.0; 00031 iceRcold = -1.0; 00032 iceRtemp = -1.0; 00033 lambda = -1.0; 00034 a0 = GSL_NAN; 00035 a1 = GSL_NAN; 00036 b = GSL_NAN; 00037 00038 ice_rho = config.get("ice_density"); 00039 ice_c = config.get("ice_specific_heat_capacity"); 00040 ice_k = config.get("ice_thermal_conductivity"); 00041 00042 ice_K = ice_k / ice_c; 00043 ice_K0 = ice_K * config.get("enthalpy_temperate_conductivity_ratio"); 00044 00045 u = new PetscScalar[Mz]; 00046 v = new PetscScalar[Mz]; 00047 w = new PetscScalar[Mz]; 00048 Sigma = new PetscScalar[Mz]; 00049 Enth = new PetscScalar[Mz]; 00050 Enth_s = new PetscScalar[Mz]; // enthalpy of pressure-melting-point 00051 00052 Enth3 = &my_Enth3; // points to IceModelVec3 00053 } 00054 00055 00056 enthSystemCtx::~enthSystemCtx() { 00057 delete [] u; 00058 delete [] v; 00059 delete [] w; 00060 delete [] Sigma; 00061 delete [] Enth_s; 00062 delete [] Enth; 00063 } 00064 00065 00066 PetscErrorCode enthSystemCtx::initAllColumns( 00067 const PetscScalar my_dx, const PetscScalar my_dy, 00068 const PetscScalar my_dtTemp, const PetscScalar my_dzEQ) { 00069 dx = my_dx; 00070 dy = my_dy; 00071 dtTemp = my_dtTemp; 00072 dzEQ = my_dzEQ; 00073 nuEQ = dtTemp / dzEQ; 00074 iceRcold = (ice_K / ice_rho) * dtTemp / PetscSqr(dzEQ); 00075 iceRtemp = (ice_K0 / ice_rho) * dtTemp / PetscSqr(dzEQ); 00076 return 0; 00077 } 00078 00079 00080 PetscErrorCode enthSystemCtx::setSchemeParamsThisColumn( 00081 bool my_ismarginal, const PetscScalar my_lambda) { 00082 #ifdef PISM_DEBUG 00083 if ((nuEQ < 0.0) || (iceRcold < 0.0) || (iceRtemp < 0.0)) { SETERRQ(2, 00084 "setSchemeParamsThisColumn() should only be called after\n" 00085 " initAllColumns() in enthSystemCtx"); } 00086 if (lambda >= 0.0) { SETERRQ(3, 00087 "setSchemeParamsThisColumn() called twice (?) in enthSystemCtx"); } 00088 #endif 00089 ismarginal = my_ismarginal; 00090 lambda = my_lambda; 00091 return 0; 00092 } 00093 00094 00095 PetscErrorCode enthSystemCtx::setBoundaryValuesThisColumn( 00096 const PetscScalar my_Enth_surface) { 00097 #ifdef PISM_DEBUG 00098 if ((nuEQ < 0.0) || (iceRcold < 0.0) || (iceRtemp < 0.0)) { SETERRQ(2, 00099 "setBoundaryValuesThisColumn() should only be called after\n" 00100 " initAllColumns() in enthSystemCtx"); } 00101 #endif 00102 Enth_ks = my_Enth_surface; 00103 return 0; 00104 } 00105 00106 00107 PetscErrorCode enthSystemCtx::viewConstants( 00108 PetscViewer viewer, bool show_col_dependent) { 00109 PetscErrorCode ierr; 00110 00111 if (!viewer) { 00112 ierr = PetscViewerASCIIGetStdout(PETSC_COMM_SELF,&viewer); CHKERRQ(ierr); 00113 } 00114 00115 PetscTruth iascii; 00116 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii); CHKERRQ(ierr); 00117 if (!iascii) { SETERRQ(1,"Only ASCII viewer for enthSystemCtx::viewConstants()\n"); } 00118 00119 ierr = PetscViewerASCIIPrintf(viewer, 00120 "\n<<VIEWING enthSystemCtx:\n"); CHKERRQ(ierr); 00121 ierr = PetscViewerASCIIPrintf(viewer, 00122 "for ALL columns:\n"); CHKERRQ(ierr); 00123 ierr = PetscViewerASCIIPrintf(viewer, 00124 " dx,dy,dtTemp,dzEQ = %8.2f,%8.2f,%10.3e,%8.2f\n", 00125 dx,dy,dtTemp,dzEQ); CHKERRQ(ierr); 00126 ierr = PetscViewerASCIIPrintf(viewer, 00127 " ice_rho,ice_c,ice_k,ice_K,ice_K0 = %10.3e,%10.3e,%10.3e,%10.3e,%10.3e\n", 00128 ice_rho,ice_c,ice_k,ice_K,ice_K0); CHKERRQ(ierr); 00129 ierr = PetscViewerASCIIPrintf(viewer, 00130 " nuEQ = %10.3e\n", 00131 nuEQ); CHKERRQ(ierr); 00132 ierr = PetscViewerASCIIPrintf(viewer, 00133 " iceRcold,iceRtemp = %10.3e,%10.3e,\n", 00134 iceRcold,iceRtemp); CHKERRQ(ierr); 00135 if (show_col_dependent) { 00136 ierr = PetscViewerASCIIPrintf(viewer, 00137 "for THIS column:\n" 00138 " i,j,ks = %d,%d,%d\n", 00139 i,j,ks); CHKERRQ(ierr); 00140 ierr = PetscViewerASCIIPrintf(viewer, 00141 " ismarginal,lambda = %d,%10.3f\n", 00142 (int)ismarginal,lambda); CHKERRQ(ierr); 00143 ierr = PetscViewerASCIIPrintf(viewer, 00144 " Enth_ks = %10.3e\n", 00145 Enth_ks); CHKERRQ(ierr); 00146 ierr = PetscViewerASCIIPrintf(viewer, 00147 " a0,a1,b = %10.3e,%10.3e\n", 00148 a0,a1,b); CHKERRQ(ierr); 00149 } 00150 ierr = PetscViewerASCIIPrintf(viewer, 00151 ">>\n\n"); CHKERRQ(ierr); 00152 return 0; 00153 } 00154 00155 00156 PetscErrorCode enthSystemCtx::checkReadyToSolve() { 00157 if ((nuEQ < 0.0) || (iceRcold < 0.0) || (iceRtemp < 0.0)) { 00158 SETERRQ(2, "not ready to solve: need initAllColumns() in enthSystemCtx"); } 00159 if (lambda < 0.0) { 00160 SETERRQ(3, "not ready to solve: need setSchemeParamsThisColumn() in enthSystemCtx"); } 00161 return 0; 00162 } 00163 00164 00166 00170 PetscErrorCode enthSystemCtx::setDirichletBasal(PetscScalar Y) { 00171 #ifdef PISM_DEBUG 00172 PetscErrorCode ierr; 00173 ierr = checkReadyToSolve(); CHKERRQ(ierr); 00174 if ((!gsl_isnan(a0)) || (!gsl_isnan(a1)) || (!gsl_isnan(b))) { 00175 SETERRQ(1, "setting basal boundary conditions twice in enthSystemCtx"); 00176 } 00177 #endif 00178 a0 = 1.0; 00179 a1 = 0.0; 00180 b = Y; 00181 return 0; 00182 } 00183 00184 00186 00196 PetscErrorCode enthSystemCtx::setNeumannBasal(PetscScalar Y) { 00197 PetscErrorCode ierr; 00198 #ifdef PISM_DEBUG 00199 ierr = checkReadyToSolve(); CHKERRQ(ierr); 00200 if ((!gsl_isnan(a0)) || (!gsl_isnan(a1)) || (!gsl_isnan(b))) { 00201 SETERRQ(1, "setting basal boundary conditions twice in enthSystemCtx"); 00202 } 00203 #endif 00204 const PetscScalar 00205 Rc = (Enth[0] < Enth_s[0]) ? iceRcold : iceRtemp, 00206 Rr = (Enth[1] < Enth_s[1]) ? iceRcold : iceRtemp, 00207 Rminus = Rc, 00208 Rplus = 0.5 * (Rc + Rr); 00209 a0 = 1.0 + Rminus + Rplus; // = D[0] 00210 a1 = - Rminus - Rplus; // = U[0] 00211 const PetscScalar X = - 2.0 * dzEQ * Y; // E(-dz) = E(+dz) + X 00212 // zero vertical velocity contribution 00213 b = Enth[0] + Rminus * X; // = rhs[0] 00214 if (!ismarginal) { 00215 planeStar<PetscScalar> ss; 00216 ierr = Enth3->getPlaneStar_fine(i,j,0,&ss); CHKERRQ(ierr); 00217 const PetscScalar UpEnthu = (u[0] < 0) ? u[0] * (ss.e - ss.ij) / dx : 00218 u[0] * (ss.ij - ss.w) / dx; 00219 const PetscScalar UpEnthv = (v[0] < 0) ? v[0] * (ss.n - ss.ij) / dy : 00220 v[0] * (ss.ij - ss.s) / dy; 00221 b += dtTemp * ((Sigma[0] / ice_rho) - UpEnthu - UpEnthv); // = rhs[0] 00222 } 00223 return 0; 00224 } 00225 00226 00229 PetscErrorCode enthSystemCtx::solveThisColumn(PetscScalar **x, PetscErrorCode &pivoterrorindex) { 00230 PetscErrorCode ierr; 00231 #ifdef PISM_DEBUG 00232 ierr = checkReadyToSolve(); CHKERRQ(ierr); 00233 if ((gsl_isnan(a0)) || (gsl_isnan(a1)) || (gsl_isnan(b))) { 00234 SETERRQ(1, "solveThisColumn() should only be called after\n" 00235 " setting basal boundary condition in enthSystemCtx"); } 00236 #endif 00237 // k=0 equation is already established 00238 // L[0] = 0.0; // not allocated 00239 D[0] = a0; 00240 U[0] = a1; 00241 rhs[0] = b; 00242 00243 // generic ice segment in k location (if any; only runs if ks >= 2) 00244 for (PetscInt k = 1; k < ks; k++) { 00245 const PetscScalar 00246 Rl = (Enth[k-1] < Enth_s[k-1]) ? iceRcold : iceRtemp, 00247 Rc = (Enth[k] < Enth_s[k]) ? iceRcold : iceRtemp, 00248 Rr = (Enth[k+1] < Enth_s[k+1]) ? iceRcold : iceRtemp, 00249 Rminus = 0.5 * (Rl + Rc), 00250 Rplus = 0.5 * (Rc + Rr); 00251 L[k] = - Rminus; 00252 D[k] = 1.0 + Rminus + Rplus; 00253 U[k] = - Rplus; 00254 const PetscScalar AA = nuEQ * w[k]; 00255 if (w[k] >= 0.0) { // velocity upward 00256 L[k] -= AA * (1.0 - lambda/2.0); 00257 D[k] += AA * (1.0 - lambda); 00258 U[k] += AA * (lambda/2.0); 00259 } else { // velocity downward 00260 L[k] -= AA * (lambda/2.0); 00261 D[k] -= AA * (1.0 - lambda); 00262 U[k] += AA * (1.0 - lambda/2.0); 00263 } 00264 rhs[k] = Enth[k]; 00265 if (!ismarginal) { 00266 planeStar<PetscScalar> ss; 00267 ierr = Enth3->getPlaneStar_fine(i,j,k,&ss); CHKERRQ(ierr); 00268 const PetscScalar UpEnthu = (u[k] < 0) ? u[k] * (ss.e - ss.ij) / dx : 00269 u[k] * (ss.ij - ss.w) / dx; 00270 const PetscScalar UpEnthv = (v[k] < 0) ? v[k] * (ss.n - ss.ij) / dy : 00271 v[k] * (ss.ij - ss.s) / dy; 00272 rhs[k] += dtTemp * ((Sigma[k] / ice_rho) - UpEnthu - UpEnthv); 00273 } 00274 } 00275 00276 // set Dirichlet boundary condition at top 00277 if (ks > 0) L[ks] = 0.0; 00278 D[ks] = 1.0; 00279 if (ks < Mz-1) U[ks] = 0.0; 00280 rhs[ks] = Enth_ks; 00281 00282 // solve it; note drainage is not addressed yet and post-processing may occur 00283 pivoterrorindex = solveTridiagonalSystem(ks+1, x); 00284 00285 // air above 00286 for (PetscInt k = ks+1; k < Mz; k++) { 00287 (*x)[k] = Enth_ks; 00288 } 00289 00290 #ifdef PISM_DEBUG 00291 if (pivoterrorindex == 0) { 00292 // if success, mark column as done by making scheme params and b.c. coeffs invalid 00293 lambda = -1.0; 00294 a0 = GSL_NAN; 00295 a1 = GSL_NAN; 00296 b = GSL_NAN; 00297 } 00298 #endif 00299 return 0; 00300 } 00301
1.7.3