|
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 "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
1.7.3