PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/iMenthalpy.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 "iceModel.hh"
00020 #include "enthSystem.hh"
00021 #include "Mask.hh"
00022 
00023 
00025 
00026 
00028 
00040 PetscErrorCode IceModel::compute_enthalpy_cold(IceModelVec3 &temperature, IceModelVec3 &result) {
00041   PetscErrorCode ierr;
00042   
00043   ierr = temperature.begin_access(); CHKERRQ(ierr);
00044   ierr = result.begin_access(); CHKERRQ(ierr);
00045   ierr = vH.begin_access(); CHKERRQ(ierr);
00046 
00047   PetscScalar *Tij, *Enthij; // columns of these values
00048   for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00049     for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00050       ierr = temperature.getInternalColumn(i,j,&Tij); CHKERRQ(ierr);
00051       ierr = result.getInternalColumn(i,j,&Enthij); CHKERRQ(ierr);
00052       for (PetscInt k=0; k<grid.Mz; ++k) {
00053         const PetscScalar depth = vH(i,j) - grid.zlevels[k]; // FIXME task #7297
00054         ierr = EC->getEnthPermissive(Tij[k],0.0,EC->getPressureFromDepth(depth),
00055                                     Enthij[k]); CHKERRQ(ierr);
00056       }
00057     }
00058   }
00059 
00060   ierr = result.end_access(); CHKERRQ(ierr);
00061   ierr = temperature.end_access(); CHKERRQ(ierr);
00062   ierr = vH.end_access(); CHKERRQ(ierr);
00063 
00064   ierr = result.beginGhostComm(); CHKERRQ(ierr);
00065   ierr = result.endGhostComm(); CHKERRQ(ierr);
00066   return 0;
00067 }
00068 
00069 
00071 
00074 PetscErrorCode IceModel::compute_enthalpy(IceModelVec3 &temperature,
00075                                           IceModelVec3 &liquid_water_fraction,
00076                                           IceModelVec3 &result) {
00077   PetscErrorCode ierr;
00078   
00079   ierr = temperature.begin_access(); CHKERRQ(ierr);
00080   ierr = liquid_water_fraction.begin_access(); CHKERRQ(ierr);
00081   ierr = result.begin_access(); CHKERRQ(ierr);
00082   ierr = vH.begin_access(); CHKERRQ(ierr);
00083 
00084   PetscScalar *Tij, *Liqfracij, *Enthij; // columns of these values
00085   for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00086     for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00087       ierr = temperature.getInternalColumn(i,j,&Tij); CHKERRQ(ierr);
00088       ierr = liquid_water_fraction.getInternalColumn(i,j,&Liqfracij); CHKERRQ(ierr);
00089       ierr = result.getInternalColumn(i,j,&Enthij); CHKERRQ(ierr);
00090       for (PetscInt k=0; k<grid.Mz; ++k) {
00091         const PetscScalar depth = vH(i,j) - grid.zlevels[k]; // FIXME task #7297
00092         ierr = EC->getEnthPermissive(Tij[k],Liqfracij[k],
00093                       EC->getPressureFromDepth(depth), Enthij[k]); CHKERRQ(ierr);
00094       }
00095     }
00096   }
00097 
00098   ierr = result.end_access(); CHKERRQ(ierr);
00099   ierr = temperature.end_access(); CHKERRQ(ierr);
00100   ierr = liquid_water_fraction.end_access(); CHKERRQ(ierr);
00101   ierr = vH.end_access(); CHKERRQ(ierr);
00102 
00103   ierr = result.beginGhostComm(); CHKERRQ(ierr);
00104   ierr = result.endGhostComm(); CHKERRQ(ierr);
00105   return 0;
00106 }
00107 
00109 
00112 PetscErrorCode IceModel::compute_liquid_water_fraction(IceModelVec3 &enthalpy,
00113                                                        IceModelVec3 &result) {
00114   PetscErrorCode ierr;
00115 
00116   ierr = result.set_name("liqfrac"); CHKERRQ(ierr);
00117   ierr = result.set_attrs(
00118      "diagnostic",
00119      "liquid water fraction in ice (between 0 and 1)",
00120      "", ""); CHKERRQ(ierr);
00121 
00122   PetscScalar *omegaij, *Enthij; // columns of these values
00123   ierr = result.begin_access(); CHKERRQ(ierr);
00124   ierr = enthalpy.begin_access(); CHKERRQ(ierr);
00125   ierr = vH.begin_access(); CHKERRQ(ierr);
00126   for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00127     for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00128       ierr = result.getInternalColumn(i,j,&omegaij); CHKERRQ(ierr);
00129       ierr = enthalpy.getInternalColumn(i,j,&Enthij); CHKERRQ(ierr);
00130       for (PetscInt k=0; k<grid.Mz; ++k) {
00131         const PetscScalar depth = vH(i,j) - grid.zlevels[k]; // FIXME task #7297
00132         ierr = EC->getWaterFraction(Enthij[k],EC->getPressureFromDepth(depth),
00133                                    omegaij[k]); CHKERRQ(ierr);
00134       }
00135     }
00136   }
00137   ierr = enthalpy.end_access(); CHKERRQ(ierr);
00138   ierr = result.end_access(); CHKERRQ(ierr);
00139   ierr = vH.end_access(); CHKERRQ(ierr);
00140   return 0;
00141 }
00142 
00144 
00149 PetscErrorCode IceModel::setCTSFromEnthalpy(IceModelVec3 &useForCTS) {
00150   PetscErrorCode ierr;
00151 
00152   ierr = useForCTS.set_name("cts"); CHKERRQ(ierr);
00153   ierr = useForCTS.set_attrs(
00154      "diagnostic",
00155      "cts = E/E_s(p), so cold-temperate transition surface is at cts = 1",
00156      "", ""); CHKERRQ(ierr);
00157 
00158   PetscScalar *CTSij, *Enthij; // columns of these values
00159   ierr = useForCTS.begin_access(); CHKERRQ(ierr);
00160   ierr = Enth3.begin_access(); CHKERRQ(ierr);
00161   ierr = vH.begin_access(); CHKERRQ(ierr);
00162   for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00163     for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00164       ierr = useForCTS.getInternalColumn(i,j,&CTSij); CHKERRQ(ierr);
00165       ierr = Enth3.getInternalColumn(i,j,&Enthij); CHKERRQ(ierr);
00166       for (PetscInt k=0; k<grid.Mz; ++k) {
00167         const PetscScalar depth = vH(i,j) - grid.zlevels[k]; // FIXME task #7297
00168         CTSij[k] = EC->getCTS(Enthij[k], EC->getPressureFromDepth(depth));
00169       }
00170     }
00171   }
00172   ierr = Enth3.end_access(); CHKERRQ(ierr);
00173   ierr = useForCTS.end_access(); CHKERRQ(ierr);
00174   ierr = vH.end_access(); CHKERRQ(ierr);
00175   return 0;
00176 }
00177 
00178 
00180 
00184 PetscErrorCode IceModel::getEnthalpyCTSColumn(PetscScalar p_air,
00185                                               PetscScalar thk,
00186                                               PetscInt ks,
00187                                               const PetscScalar *Enth,
00188                                               const PetscScalar *w,
00189                                               PetscScalar *lambda,
00190                                               PetscScalar **Enth_s) {
00191 
00192   *lambda = 1.0;  // start with centered implicit for more accuracy
00193   const PetscScalar
00194       ice_rho_c = ice->rho * ice->c_p,
00195       ice_k     = ice->k;
00196   for (PetscInt k = 0; k <= ks; k++) {
00197     (*Enth_s)[k] = EC->getEnthalpyCTS(EC->getPressureFromDepth(thk - grid.zlevels_fine[k]));
00198 
00199     if (Enth[k] > (*Enth_s)[k]) { // lambda = 0 if temperate ice present in column
00200       *lambda = 0.0;
00201     } else {
00202       const PetscScalar 
00203           denom = (PetscAbs(w[k]) + 0.000001/secpera) * ice_rho_c * grid.dz_fine;
00204       *lambda = PetscMin(*lambda, 2.0 * ice_k / denom);
00205     }
00206   }
00207 
00208   for (PetscInt k = ks+1; k < grid.Mz_fine; k++) {
00209     (*Enth_s)[k] = EC->getEnthalpyCTS(p_air);
00210   }
00211 
00212   return 0;
00213 }
00214 
00215 
00217 class DrainageCalculator {
00218 
00219 public:
00220   DrainageCalculator(const NCConfigVariable &config) {
00221     OM1 = config.get("drainage_target_water_frac"); // 0.01
00222     OM2 = 2.0 * OM1;
00223     OM3 = 3.0 * OM1;
00224     DR3 = config.get("drainage_max_rate"); // 0.05 a-1 
00225     DR2 = 0.1 * DR3;
00226   }
00227   virtual ~DrainageCalculator() {}
00228 
00230   virtual PetscReal get_drainage_rate(PetscReal omega) {
00231     if (omega > OM1) {
00232       if (omega > OM2) {
00233         if (omega > OM3) {
00234           return DR3;
00235         } else
00236           return DR2 + (DR3 - DR2) * (omega - OM2) / OM1;
00237       } else
00238         return DR2 * (omega - OM1) / OM1;
00239     } else {
00240       return 0.0;
00241     }
00242   }
00243 
00244 private:
00245   PetscReal OM1, OM2, OM3, DR2, DR3;
00246 };
00247 
00248 
00250 
00261 PetscErrorCode IceModel::enthalpyAndDrainageStep(
00262                       PetscScalar* vertSacrCount, PetscScalar* liquifiedVol,
00263                       PetscScalar* bulgeCount) {
00264   PetscErrorCode  ierr;
00265 
00266   if (config.get_flag("do_cold_ice_methods")) {
00267     SETERRQ(1,
00268       "PISM ERROR:  enthalpyAndDrainageStep() called but do_cold_ice_methods==true\n");
00269   }
00270 
00271   const PetscReal dt_secs = dt_years_TempAge * secpera;
00272 
00273   // get fine grid levels in ice
00274   PetscInt    fMz = grid.Mz_fine;  
00275   PetscScalar fdz = grid.dz_fine;
00276   vector<double> &fzlev = grid.zlevels_fine;
00277 
00278   const PetscScalar
00279     p_air     = config.get("surface_pressure"),
00280     ice_k     = config.get("ice_thermal_conductivity"),
00281     ice_c     = config.get("ice_specific_heat_capacity"),
00282     ice_K     = ice_k / ice_c, // enthalpy-conductivity for cold ice
00283     L         = config.get("water_latent_heat_fusion"),  // J kg-1
00284     bulgeEnthMax  = config.get("enthalpy_cold_bulge_max"), // J kg-1
00285     hmelt_decay_rate = config.get("hmelt_decay_rate"),   // m s-1
00286     hmelt_max = config.get("hmelt_max");                 // m
00287 
00288   DrainageCalculator dc(config);
00289   
00290   IceModelVec2S *Rb;
00291   IceModelVec3 *u3, *v3, *w3, *Sigma3;
00292   ierr = stress_balance->get_basal_frictional_heating(Rb); CHKERRQ(ierr);
00293   ierr = stress_balance->get_3d_velocity(u3, v3, w3); CHKERRQ(ierr);
00294   ierr = stress_balance->get_volumetric_strain_heating(Sigma3); CHKERRQ(ierr); 
00295 
00296   PetscScalar *Enthnew;
00297   Enthnew = new PetscScalar[fMz];  // new enthalpy in column
00298 
00299   enthSystemCtx esys(config, Enth3, fMz, "enth");
00300   ierr = esys.initAllColumns(grid.dx, grid.dy, dt_secs, fdz); CHKERRQ(ierr);
00301 
00302   bool viewOneColumn;
00303   ierr = PISMOptionsIsSet("-view_sys", viewOneColumn); CHKERRQ(ierr);
00304 
00305   if (getVerbosityLevel() >= 4) {  // view: all column-independent constants correct?
00306     ierr = EC->viewConstants(NULL); CHKERRQ(ierr);
00307     ierr = esys.viewConstants(NULL, false); CHKERRQ(ierr);
00308   }
00309 
00310   // now get map-plane coupler fields: Dirichlet upper surface boundary and
00311   //    mass balance lower boundary under shelves
00312   if (surface != PETSC_NULL) {
00313     ierr = surface->ice_surface_temperature(artm);
00314     ierr = surface->ice_surface_liquid_water_fraction(liqfrac_surface); CHKERRQ(ierr);
00315     CHKERRQ(ierr);
00316   } else {
00317     SETERRQ(4,"PISM ERROR: surface == PETSC_NULL");
00318   }
00319   if (ocean != PETSC_NULL) {
00320     ierr = ocean->shelf_base_mass_flux(shelfbmassflux);
00321         CHKERRQ(ierr);
00322     ierr = ocean->shelf_base_temperature(shelfbtemp);
00323         CHKERRQ(ierr);
00324   } else {
00325     SETERRQ(5,"PISM ERROR: ocean == PETSC_NULL");
00326   }
00327 
00328   IceModelVec2S G0 = vWork2d[0];
00329   ierr = G0.set_attrs("internal","upward geothermal flux at z=0","W m-2", ""); CHKERRQ(ierr);
00330   ierr = G0.set_glaciological_units("mW m-2");
00331   if (btu) {
00332     ierr = btu->get_upward_geothermal_flux(G0); CHKERRQ(ierr);
00333   } else {
00334     SETERRQ(3,"PISM ERROR: PISMBedThermalUnit* btu == PETSC_NULL in enthalpyAndDrainageStep()");
00335   }
00336 
00337   ierr = artm.begin_access(); CHKERRQ(ierr);
00338   ierr = shelfbmassflux.begin_access(); CHKERRQ(ierr);
00339   ierr = shelfbtemp.begin_access(); CHKERRQ(ierr);
00340 
00341   // get other map-plane fields
00342   ierr = liqfrac_surface.begin_access(); CHKERRQ(ierr);
00343   ierr = vH.begin_access(); CHKERRQ(ierr);
00344   ierr = vHmelt.begin_access(); CHKERRQ(ierr);
00345   ierr = vbmr.begin_access(); CHKERRQ(ierr);
00346   ierr = Rb->begin_access(); CHKERRQ(ierr);
00347   ierr = G0.begin_access(); CHKERRQ(ierr);
00348   ierr = vMask.begin_access(); CHKERRQ(ierr);
00349 
00350   // these are accessed a column at a time
00351   ierr = u3->begin_access(); CHKERRQ(ierr);
00352   ierr = v3->begin_access(); CHKERRQ(ierr);
00353   ierr = w3->begin_access(); CHKERRQ(ierr);
00354   ierr = Sigma3->begin_access(); CHKERRQ(ierr);
00355   ierr = Enth3.begin_access(); CHKERRQ(ierr);
00356   ierr = vWork3d.begin_access(); CHKERRQ(ierr);
00357 
00358   PetscInt liquifiedCount = 0;
00359 
00360   MaskQuery mask(vMask);
00361 
00362   for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00363     for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00364 
00365       // for fine grid; this should *not* be replaced by call to grid.kBelowHeight()
00366       const PetscInt ks = static_cast<PetscInt>(floor(vH(i,j)/fdz));
00367 #ifdef PISM_DEBUG
00368       // check if ks is valid
00369       if ((ks < 0) || (ks >= grid.Mz_fine)) {
00370         PetscPrintf(grid.com,
00371                     "ERROR: ks = %d computed at i = %d, j = %d is invalid,"
00372                     " possibly because of invalid ice thickness.\n",
00373                     ks, i, j);
00374         SETERRQ(1, "invalid ks");
00375       }
00376 #endif
00377 
00378       const bool ice_free_column = (ks == 0),
00379                  is_floating     = mask.ocean(i,j);
00380 
00381       // enthalpy and pressures at top of ice
00382       const PetscScalar p_ks = EC->getPressureFromDepth(vH(i,j) - fzlev[ks]); // FIXME task #7297
00383       PetscScalar Enth_ks;
00384       ierr = EC->getEnthPermissive(artm(i,j), liqfrac_surface(i,j), p_ks, Enth_ks); CHKERRQ(ierr);
00385 
00386       // deal completely with columns with no ice; enthalpy, vHmelt, vbmr all need setting
00387       if (ice_free_column) {
00388         ierr = vWork3d.setColumn(i,j,Enth_ks); CHKERRQ(ierr);
00389         if (mask.floating_ice(i,j)) {
00390           // if floating then assume-maximally saturated till to avoid "shock"
00391           //   when grounding line advances
00392           vHmelt(i,j) = hmelt_max;
00393           vbmr(i,j) = shelfbmassflux(i,j);
00394         } else {
00395           // either truely no ice or grounded or both; either way zero-out subglacial fields
00396           vHmelt(i,j) = 0.0;  // no stored water on ice free land
00397           vbmr(i,j) = 0.0;    // no basal melt rate; melting is a surface process
00398                               //   on ice free land
00399         }
00400 
00401         goto donewithcolumn;
00402       } // end of if (ice_free_column)
00403 
00404       { // explicit scoping to deal with goto and initializers
00405 
00406         // ignore advection and strain heating in ice if isMarginal
00407         const bool isMarginal = checkThinNeigh(
00408                                  vH(i+1,j),vH(i+1,j+1),vH(i,j+1),vH(i-1,j+1),
00409                                  vH(i-1,j),vH(i-1,j-1),vH(i,j-1),vH(i+1,j-1)  );
00410 
00411         ierr = Enth3.getValColumn(i,j,ks,esys.Enth); CHKERRQ(ierr);
00412         ierr = w3->getValColumn(i,j,ks,esys.w); CHKERRQ(ierr);
00413 
00414         PetscScalar lambda;
00415         ierr = getEnthalpyCTSColumn(p_air, vH(i,j), ks, esys.Enth, esys.w, // FIXME task #7297
00416                                     &lambda, &esys.Enth_s); CHKERRQ(ierr);
00417         if (lambda < 1.0)  *vertSacrCount += 1; // count columns with lambda < 1
00418 
00419         // if there is subglacial water, don't allow ice base enthalpy to be below
00420         // pressure-melting; that is, assume subglacial water is at the pressure-
00421         // melting temperature and enforce continuity of temperature
00422         if ((vHmelt(i,j) > 0.0) && (esys.Enth[0] < esys.Enth_s[0])) { 
00423           esys.Enth[0] = esys.Enth_s[0];
00424         }
00425 
00426         const bool base_is_cold = (esys.Enth[0] < esys.Enth_s[0]);
00427         const PetscScalar p1 = EC->getPressureFromDepth(vH(i,j) - fdz); // FIXME task #7297
00428         const bool k1_istemperate = EC->isTemperate(esys.Enth[1], p1); // level  z = + \Delta z
00429 
00430         // can now determine melt, but only preliminarily because of drainage,
00431         //   from heat flux out of bedrock, heat flux into ice, and frictional heating
00432         if (is_floating) {
00433           vbmr(i,j) = shelfbmassflux(i,j);
00434         } else {
00435           if (base_is_cold) {
00436               vbmr(i,j) = 0.0;  // zero melt rate if cold base
00437           } else {
00438             PetscScalar hf_up;
00439             if (k1_istemperate) {
00440               const PetscScalar pbasal = EC->getPressureFromDepth(vH(i,j)); // FIXME task #7297
00441               hf_up = - ice->k * (EC->getMeltingTemp(p1) - EC->getMeltingTemp(pbasal)) / fdz;
00442             } else {
00443               hf_up = - ice_K * (esys.Enth[1] - esys.Enth[0]) / fdz;
00444             }
00445             // compute basal melt rate from flux balance; vbmr = - Mb / rho in
00446             //   efgis paper; after we compute it we make sure there is no
00447             //   refreeze if there is no available basal water
00448             vbmr(i,j) = ( (*Rb)(i,j) + G0(i,j) - hf_up ) / (ice->rho * L);
00449             if ((vHmelt(i,j) <= 0) && (vbmr(i,j) < 0))    vbmr(i,j) = 0.0;
00450           }
00451         }
00452 
00453         // now set-up for solve in ice; note esys.Enth[], esys.w[],
00454         //   esys.Enth_s[] are already filled
00455         ierr = esys.setIndicesAndClearThisColumn(i,j,ks); CHKERRQ(ierr);
00456 
00457         ierr = u3->getValColumn(i,j,ks,esys.u); CHKERRQ(ierr);
00458         ierr = v3->getValColumn(i,j,ks,esys.v); CHKERRQ(ierr);
00459         ierr = Sigma3->getValColumn(i,j,ks,esys.Sigma); CHKERRQ(ierr);
00460 
00461         ierr = esys.setSchemeParamsThisColumn(isMarginal, lambda); CHKERRQ(ierr);
00462         ierr = esys.setBoundaryValuesThisColumn(Enth_ks); CHKERRQ(ierr);
00463 
00464         // determine lowest-level equation at bottom of ice; see decision chart
00465         //   in [\ref AschwandenBuelerKhroulevBlatter], and page documenting BOMBPROOF
00466         if (is_floating) {
00467           // floating base: Dirichlet application of known temperature from ocean
00468           //   coupler; assumes base of ice shelf has zero liquid fraction
00469           PetscScalar Enth0;
00470           ierr = EC->getEnthPermissive(shelfbtemp(i,j), 0.0, EC->getPressureFromDepth(vH(i,j)),
00471                                        Enth0); CHKERRQ(ierr);
00472           ierr = esys.setDirichletBasal(Enth0); CHKERRQ(ierr);
00473         } else if (base_is_cold) {
00474           // cold, grounded base case:  Neumann q . n = q_lith . n + F_b   and   q = - K_i \nabla H
00475           ierr = esys.setNeumannBasal(- (G0(i,j) + (*Rb)(i,j)) / ice_K); CHKERRQ(ierr);
00476         } else {
00477           // warm, grounded base case
00478           if (k1_istemperate) {
00479             // positive thickness of temperate ice:  Neumann q . n = 0 and q = - K_0 \nabla H
00480             //   so H(k=1)-H(k=0) = 0
00481             ierr = esys.setNeumannBasal(0.0); CHKERRQ(ierr);
00482           } else {
00483             // no thickness of temperate ice:  Dirichlet  H = H_s(pbasal)
00484             ierr = esys.setDirichletBasal(esys.Enth_s[0]); CHKERRQ(ierr);
00485           }
00486         }
00487 
00488         // solve the system
00489         PetscErrorCode pivoterr;
00490         ierr = esys.solveThisColumn(&Enthnew,pivoterr); CHKERRQ(ierr);
00491         if (pivoterr != 0) {
00492           ierr = PetscPrintf(PETSC_COMM_SELF,
00493             "\n\ntridiagonal solve of enthSystemCtx in enthalpyAndDrainageStep() FAILED at (%d,%d)\n"
00494                 " with zero pivot position %d; viewing system to m-file ... \n",
00495             i, j, pivoterr); CHKERRQ(ierr);
00496           ierr = esys.reportColumnZeroPivotErrorMFile(pivoterr); CHKERRQ(ierr);
00497           SETERRQ(1,"PISM ERROR in enthalpyDrainageStep()\n");
00498         }
00499         if (viewOneColumn && issounding(i,j)) {
00500           ierr = PetscPrintf(PETSC_COMM_SELF,
00501             "\n\nin enthalpyAndDrainageStep(): viewing enthSystemCtx at (i,j)=(%d,%d) to m-file ... \n\n",
00502             i, j); CHKERRQ(ierr);
00503           ierr = esys.viewColumnInfoMFile(Enthnew, fMz); CHKERRQ(ierr);
00504         }
00505 
00506         // thermodynamic basal melt rate causes water to be added to layer
00507         PetscScalar Hmeltnew = vHmelt(i,j);
00508         if (mask.grounded(i,j)) {
00509           Hmeltnew += vbmr(i,j) * dt_secs;
00510         }
00511 
00512         // drain ice segments by mechanism in [\ref AschwandenBuelerKhroulevBlatter],
00513         //   using DrainageCalculator dc
00514         PetscScalar Hdrainedtotal = 0.0;
00515         for (PetscInt k=0; k < ks; k++) {
00516           if (Enthnew[k] > esys.Enth_s[k]) { // avoid doing any more work if cold
00517             if (Enthnew[k] >= esys.Enth_s[k] + 0.5 * L) {
00518               liquifiedCount++; // count these rare events ...
00519               Enthnew[k] = esys.Enth_s[k] + 0.5 * L; //  but lose the energy
00520             }
00521             const PetscReal p = EC->getPressureFromDepth(vH(i,j) - fzlev[k]); // FIXME task #7297
00522             PetscReal omega;
00523             EC->getWaterFraction(Enthnew[k], p, omega);  // return code not checked
00524             if (omega > 0.01) {
00525               PetscReal fractiondrained = dc.get_drainage_rate(omega) * dt_secs; // pure number
00526               fractiondrained = PetscMin(fractiondrained, omega - 0.01); // only drain down to 0.01
00527               Hdrainedtotal += fractiondrained * fdz;  // always a positive contribution
00528               Enthnew[k] -= fractiondrained * L;
00529             }
00530           }
00531         }
00532 
00533         // in grounded case, add to both basal melt rate and Hmelt; if floating,
00534         // Hdrainedtotal is discarded because ocean determines basal melt rate
00535         if (mask.grounded(i,j)) {
00536           vbmr(i,j) += Hdrainedtotal / dt_secs;
00537           Hmeltnew += Hdrainedtotal;
00538         }
00539 
00540         // finalize Enthnew[]:  apply bulge limiter and transfer column
00541         //   into vWork3d; communication will occur later
00542         const PetscReal lowerEnthLimit = Enth_ks - bulgeEnthMax;
00543         for (PetscInt k=0; k < ks; k++) {
00544           if (Enthnew[k] < lowerEnthLimit) {
00545             *bulgeCount += 1;      // count the columns which have very large cold 
00546             Enthnew[k] = lowerEnthLimit;  // limit advection bulge ... enthalpy not too low
00547           }
00548         }
00549         ierr = vWork3d.setValColumnPL(i,j,Enthnew); CHKERRQ(ierr);
00550 
00551         // finalize Hmelt value
00552         Hmeltnew -= hmelt_decay_rate * dt_secs;
00553         if (is_floating) {
00554           // if floating assume maximally saturated till to avoid "shock" if grounding line advances
00555           // UNACCOUNTED MASS & ENERGY (LATENT) LOSS/GAIN (TO/FROM OCEAN)!!
00556           vHmelt(i,j) = hmelt_max;
00557         } else {
00558           // limit Hmelt to be in [0.0, hmelt_max]
00559           // UNACCOUNTED MASS & ENERGY (LATENT) LOSS (TO INFINITY AND BEYOND)!!
00560           vHmelt(i,j) = PetscMax(0.0, PetscMin(hmelt_max, Hmeltnew) );
00561         }
00562 
00563       } // end explicit scoping
00564       
00565       donewithcolumn: 
00566       { }  // odd thing: something needs to follow goto target to get compilation
00567 
00568     }
00569   }
00570 
00571   ierr = artm.end_access(); CHKERRQ(ierr);
00572   ierr = shelfbmassflux.end_access(); CHKERRQ(ierr);
00573   ierr = shelfbtemp.end_access(); CHKERRQ(ierr);
00574 
00575   ierr = vH.end_access(); CHKERRQ(ierr);
00576   ierr = vMask.end_access(); CHKERRQ(ierr);
00577   ierr = vHmelt.end_access(); CHKERRQ(ierr);
00578   ierr = Rb->end_access(); CHKERRQ(ierr);
00579   ierr = G0.end_access(); CHKERRQ(ierr);
00580   ierr = vbmr.end_access(); CHKERRQ(ierr);
00581   ierr = liqfrac_surface.end_access(); CHKERRQ(ierr);
00582 
00583   ierr = u3->end_access(); CHKERRQ(ierr);
00584   ierr = v3->end_access(); CHKERRQ(ierr);
00585   ierr = w3->end_access(); CHKERRQ(ierr);
00586   ierr = Sigma3->end_access(); CHKERRQ(ierr);
00587   ierr = Enth3.end_access(); CHKERRQ(ierr);
00588   ierr = vWork3d.end_access(); CHKERRQ(ierr);
00589 
00590   delete [] Enthnew;
00591 
00592   *liquifiedVol = ((double) liquifiedCount) * fdz * grid.dx * grid.dy;
00593   return 0;
00594 }
00595 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines