PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/energy/enthSystem.cc

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