|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 // Copyright (C) 2004-2011 Jed Brown, 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 "tempSystem.hh" 00021 #include "Mask.hh" 00022 00023 00025 00026 00028 PetscErrorCode IceModel::excessToFromBasalMeltLayer( 00029 const PetscScalar rho_c, const PetscScalar z, const PetscScalar dz, 00030 PetscScalar *Texcess, PetscScalar *Hmelt) { 00031 00032 const PetscScalar darea = grid.dx * grid.dy, 00033 dvol = darea * dz, 00034 dE = rho_c * (*Texcess) * dvol, 00035 massmelted = dE / ice->latentHeat; 00036 00037 if (allowAboveMelting == PETSC_TRUE) { 00038 SETERRQ(1,"IceModel::excessToBasalMeltLayer() called but allowAboveMelting==TRUE"); 00039 } 00040 if (*Texcess >= 0.0) { 00041 if (updateHmelt == PETSC_TRUE) { 00042 // T is at or above pressure-melting temp, so temp needs to be set to 00043 // pressure-melting; a fraction of excess energy is turned into melt water at base 00044 // note massmelted is POSITIVE! 00045 const PetscScalar FRACTION_TO_BASE 00046 = (z < 100.0) ? 0.2 * (100.0 - z) / 100.0 : 0.0; 00047 // note: ice-equiv thickness: 00048 *Hmelt += (FRACTION_TO_BASE * massmelted) / (ice->rho * darea); 00049 } 00050 *Texcess = 0.0; 00051 } else if (updateHmelt == PETSC_TRUE) { // neither Texcess nor Hmelt need to change 00052 // if Texcess < 0.0 00053 // Texcess negative; only refreeze (i.e. reduce Hmelt) if at base and Hmelt > 0.0 00054 // note ONLY CALLED IF AT BASE! note massmelted is NEGATIVE! 00055 if (z > 0.00001) { 00056 SETERRQ(1, "excessToBasalMeltLayer() called with z not at base and negative Texcess"); 00057 } 00058 if (*Hmelt > 0.0) { 00059 const PetscScalar thicknessToFreezeOn = - massmelted / (ice->rho * darea); 00060 if (thicknessToFreezeOn <= *Hmelt) { // the water *is* available to freeze on 00061 *Hmelt -= thicknessToFreezeOn; 00062 *Texcess = 0.0; 00063 } else { // only refreeze Hmelt thickness of water; update Texcess 00064 *Hmelt = 0.0; 00065 const PetscScalar dTemp = ice->latentHeat * ice->rho * (*Hmelt) / (rho_c * dz); 00066 *Texcess += dTemp; 00067 } 00068 } 00069 // note: if *Hmelt == 0 and Texcess < 0.0 then Texcess unmolested; temp will go down 00070 } 00071 return 0; 00072 } 00073 00074 00076 00127 PetscErrorCode IceModel::temperatureStep(PetscScalar* vertSacrCount, PetscScalar* bulgeCount) { 00128 PetscErrorCode ierr; 00129 00130 // set up fine grid in ice 00131 PetscInt fMz = grid.Mz_fine; 00132 PetscScalar fdz = grid.dz_fine; 00133 vector<double> &fzlev = grid.zlevels_fine; 00134 00135 ierr = verbPrintf(5,grid.com, 00136 "\n [entering temperatureStep(); fMz = %d, fdz = %5.3f]", 00137 fMz, fdz); CHKERRQ(ierr); 00138 00139 bool viewOneColumn; 00140 ierr = PISMOptionsIsSet("-view_sys", viewOneColumn); CHKERRQ(ierr); 00141 00142 tempSystemCtx system(fMz, "temperature"); 00143 system.dx = grid.dx; 00144 system.dy = grid.dy; 00145 system.dtTemp = dt_years_TempAge * secpera; // same time step for temp and age, currently 00146 system.dzEQ = fdz; 00147 system.ice_rho = ice->rho; 00148 system.ice_c_p = ice->c_p; 00149 system.ice_k = ice->k; 00150 00151 PetscScalar *x; 00152 x = new PetscScalar[fMz]; // space for solution of system 00153 00154 // constants needed after solution of system, in insertion phase 00155 const PetscScalar rho_c_I = ice->rho * ice->c_p; 00156 00157 // this is bulge limit constant in K; is max amount by which ice 00158 // or bedrock can be lower than surface temperature 00159 const PetscScalar bulgeMax = config.get("enthalpy_cold_bulge_max") / ice->c_p; 00160 00161 const PetscReal hmelt_decay_rate = config.get("hmelt_decay_rate"); // m s-1 00162 00163 PetscScalar *Tnew; 00164 // pointers to values in current column 00165 system.u = new PetscScalar[fMz]; 00166 system.v = new PetscScalar[fMz]; 00167 system.w = new PetscScalar[fMz]; 00168 system.Sigma = new PetscScalar[fMz]; 00169 system.T = new PetscScalar[fMz]; 00170 Tnew = new PetscScalar[fMz]; 00171 00172 // system needs access to T3 for T3.getPlaneStar_fine() 00173 system.T3 = &T3; 00174 00175 // checks that all needed constants and pointers got set: 00176 ierr = system.initAllColumns(); CHKERRQ(ierr); 00177 00178 // now get map-plane fields, starting with coupler fields 00179 PetscScalar **Hmelt, **basalMeltRate; 00180 00181 if (surface != PETSC_NULL) { 00182 ierr = surface->ice_surface_temperature(artm); CHKERRQ(ierr); 00183 } else { 00184 SETERRQ(1,"PISM ERROR: surface == PETSC_NULL"); 00185 } 00186 if (ocean != PETSC_NULL) { 00187 ierr = ocean->shelf_base_mass_flux(shelfbmassflux); CHKERRQ(ierr); 00188 ierr = ocean->shelf_base_temperature(shelfbtemp); CHKERRQ(ierr); 00189 } else { 00190 SETERRQ(1,"PISM ERROR: ocean == PETSC_NULL"); 00191 } 00192 00193 IceModelVec2S G0 = vWork2d[0]; 00194 ierr = G0.set_attrs("internal", "upward geothermal flux at z=0", "W m-2", ""); CHKERRQ(ierr); 00195 ierr = G0.set_glaciological_units("mW m-2"); 00196 if (btu) { 00197 ierr = btu->get_upward_geothermal_flux(G0); CHKERRQ(ierr); 00198 } else { 00199 SETERRQ(3,"PISM ERROR: PISMBedThermalUnit* btu == PETSC_NULL in temperatureStep()"); 00200 } 00201 00202 ierr = artm.begin_access(); CHKERRQ(ierr); 00203 ierr = shelfbmassflux.begin_access(); CHKERRQ(ierr); 00204 ierr = shelfbtemp.begin_access(); CHKERRQ(ierr); 00205 00206 ierr = vH.begin_access(); CHKERRQ(ierr); 00207 ierr = vHmelt.get_array(Hmelt); CHKERRQ(ierr); 00208 ierr = vbmr.get_array(basalMeltRate); CHKERRQ(ierr); 00209 ierr = vMask.begin_access(); CHKERRQ(ierr); 00210 ierr = G0.begin_access(); CHKERRQ(ierr); 00211 00212 IceModelVec2S *Rb; // basal frictional heating 00213 ierr = stress_balance->get_basal_frictional_heating(Rb); CHKERRQ(ierr); 00214 00215 IceModelVec3 *u3, *v3, *w3, *Sigma3; 00216 ierr = stress_balance->get_3d_velocity(u3, v3, w3); CHKERRQ(ierr); 00217 ierr = stress_balance->get_volumetric_strain_heating(Sigma3); CHKERRQ(ierr); 00218 00219 ierr = Rb->begin_access(); CHKERRQ(ierr); 00220 00221 ierr = u3->begin_access(); CHKERRQ(ierr); 00222 ierr = v3->begin_access(); CHKERRQ(ierr); 00223 ierr = w3->begin_access(); CHKERRQ(ierr); 00224 ierr = Sigma3->begin_access(); CHKERRQ(ierr); 00225 ierr = T3.begin_access(); CHKERRQ(ierr); 00226 ierr = vWork3d.begin_access(); CHKERRQ(ierr); 00227 00228 // counts unreasonably low temperature values; deprecated? 00229 PetscInt myLowTempCount = 0; 00230 PetscInt maxLowTempCount = static_cast<PetscInt>(config.get("max_low_temp_count")); 00231 PetscReal globalMinAllowedTemp = config.get("global_min_allowed_temp"); 00232 00233 PetscReal hmelt_max = config.get("hmelt_max"); 00234 00235 MaskQuery mask(vMask); 00236 00237 for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) { 00238 for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) { 00239 00240 // this should *not* be replaced by call to grid.kBelowHeight(): 00241 const PetscInt ks = static_cast<PetscInt>(floor(vH(i,j)/fdz)); 00242 00243 if (ks>0) { // if there are enough points in ice to bother ... 00244 ierr = system.setIndicesAndClearThisColumn(i,j,ks); CHKERRQ(ierr); 00245 00246 ierr = u3->getValColumn(i,j,ks,system.u); CHKERRQ(ierr); 00247 ierr = v3->getValColumn(i,j,ks,system.v); CHKERRQ(ierr); 00248 ierr = w3->getValColumn(i,j,ks,system.w); CHKERRQ(ierr); 00249 ierr = Sigma3->getValColumn(i,j,ks,system.Sigma); CHKERRQ(ierr); 00250 ierr = T3.getValColumn(i,j,ks,system.T); CHKERRQ(ierr); 00251 00252 // go through column and find appropriate lambda for BOMBPROOF 00253 PetscScalar lambda = 1.0; // start with centered implicit for more accuracy 00254 for (PetscInt k = 1; k < ks; k++) { 00255 const PetscScalar denom = (PetscAbs(system.w[k]) + 0.000001/secpera) 00256 * ice->rho * ice->c_p * fdz; 00257 lambda = PetscMin(lambda, 2.0 * ice->k / denom); 00258 } 00259 if (lambda < 1.0) *vertSacrCount += 1; // count columns with lambda < 1 00260 // if isMarginal then only do vertical conduction for ice; ignore advection 00261 // and strain heating if isMarginal 00262 const bool isMarginal = checkThinNeigh(vH(i+1,j),vH(i+1,j+1),vH(i,j+1),vH(i-1,j+1), 00263 vH(i-1,j),vH(i-1,j-1),vH(i,j-1),vH(i+1,j-1)); 00264 PismMask mask_value = static_cast<PismMask>(vMask.as_int(i,j)); 00265 ierr = system.setSchemeParamsThisColumn(mask_value, isMarginal, lambda); 00266 CHKERRQ(ierr); 00267 00268 // set boundary values for tridiagonal system 00269 ierr = system.setSurfaceBoundaryValuesThisColumn(artm(i,j)); CHKERRQ(ierr); 00270 ierr = system.setBasalBoundaryValuesThisColumn(G0(i,j),shelfbtemp(i,j),(*Rb)(i,j)); CHKERRQ(ierr); 00271 00272 // solve the system for this column; melting not addressed yet 00273 PetscErrorCode pivoterr; 00274 ierr = system.solveThisColumn(&x, pivoterr); CHKERRQ(ierr); 00275 00276 if (pivoterr != 0) { 00277 ierr = PetscPrintf(PETSC_COMM_SELF, 00278 "\n\ntridiagonal solve of tempSystemCtx in temperatureStep() FAILED at (%d,%d)\n" 00279 " with zero pivot position %d; viewing system to m-file ... \n", 00280 i, j, pivoterr); CHKERRQ(ierr); 00281 ierr = system.reportColumnZeroPivotErrorMFile(pivoterr); CHKERRQ(ierr); 00282 SETERRQ(1,"PISM ERROR in temperatureStep()\n"); 00283 } 00284 if (viewOneColumn && issounding(i,j)) { 00285 ierr = PetscPrintf(grid.com, 00286 "\n\nin temperatureStep(): viewing tempSystemCtx at (i,j)=(%d,%d) to m-file ... \n\n", 00287 i, j); CHKERRQ(ierr); 00288 ierr = system.viewColumnInfoMFile(x, fMz); CHKERRQ(ierr); 00289 } 00290 00291 } // end of "if there are enough points in ice to bother ..." 00292 00293 // prepare for melting/refreezing 00294 PetscScalar Hmeltnew = Hmelt[i][j]; 00295 00296 // insert solution for generic ice segments 00297 for (PetscInt k=1; k <= ks; k++) { 00298 if (allowAboveMelting == PETSC_TRUE) { // in the ice 00299 Tnew[k] = x[k]; 00300 } else { 00301 const PetscScalar 00302 Tpmp = ice->melting_point_temp - ice->beta_CC_grad * (vH(i,j) - fzlev[k]); // FIXME task #7297 00303 if (x[k] > Tpmp) { 00304 Tnew[k] = Tpmp; 00305 PetscScalar Texcess = x[k] - Tpmp; // always positive 00306 excessToFromBasalMeltLayer(rho_c_I, fzlev[k], fdz, &Texcess, &Hmeltnew); 00307 // Texcess will always come back zero here; ignore it 00308 } else { 00309 Tnew[k] = x[k]; 00310 } 00311 } 00312 if (Tnew[k] < globalMinAllowedTemp) { 00313 ierr = PetscPrintf(PETSC_COMM_SELF, 00314 " [[too low (<200) ice segment temp T = %f at %d,%d,%d;" 00315 " proc %d; mask=%d; w=%f]]\n", 00316 Tnew[k],i,j,k,grid.rank,vMask.as_int(i,j),system.w[k]*secpera); CHKERRQ(ierr); 00317 myLowTempCount++; 00318 } 00319 if (Tnew[k] < artm(i,j) - bulgeMax) { 00320 Tnew[k] = artm(i,j) - bulgeMax; bulgeCount++; } 00321 } 00322 00323 // insert solution for ice base segment 00324 if (ks > 0) { 00325 if (allowAboveMelting == PETSC_TRUE) { // ice/rock interface 00326 Tnew[0] = x[0]; 00327 } else { // compute diff between x[k0] and Tpmp; melt or refreeze as appropriate 00328 const PetscScalar Tpmp = ice->melting_point_temp - ice->beta_CC_grad * vH(i,j); // FIXME task #7297 00329 PetscScalar Texcess = x[0] - Tpmp; // positive or negative 00330 if (mask.ocean(i,j)) { 00331 // when floating, only half a segment has had its temperature raised 00332 // above Tpmp 00333 excessToFromBasalMeltLayer(rho_c_I/2, 0.0, fdz, &Texcess, &Hmeltnew); 00334 } else { 00335 excessToFromBasalMeltLayer(rho_c_I, 0.0, fdz, &Texcess, &Hmeltnew); 00336 } 00337 Tnew[0] = Tpmp + Texcess; 00338 if (Tnew[0] > (Tpmp + 0.00001)) { 00339 SETERRQ(1,"updated temperature came out above Tpmp"); 00340 } 00341 } 00342 if (Tnew[0] < globalMinAllowedTemp) { 00343 ierr = PetscPrintf(PETSC_COMM_SELF, 00344 " [[too low (<200) ice/bedrock segment temp T = %f at %d,%d;" 00345 " proc %d; mask=%d; w=%f]]\n", 00346 Tnew[0],i,j,grid.rank,vMask.as_int(i,j),system.w[0]*secpera); CHKERRQ(ierr); 00347 myLowTempCount++; 00348 } 00349 if (Tnew[0] < artm(i,j) - bulgeMax) { 00350 Tnew[0] = artm(i,j) - bulgeMax; bulgeCount++; } 00351 } else { 00352 Hmeltnew = 0.0; 00353 } 00354 00355 // set to air temp above ice 00356 for (PetscInt k=ks; k<fMz; k++) { 00357 Tnew[k] = artm(i,j); 00358 } 00359 00360 // transfer column into vWork3d; communication later 00361 ierr = vWork3d.setValColumnPL(i,j,Tnew); CHKERRQ(ierr); 00362 00363 // basalMeltRate[][] is rate of mass loss at bottom of ice; finalize it and Hmelt 00364 // note massContExplicitStep() calls PISMOceanCoupler; FIXME: does there 00365 // need to be a check that shelfbmassflux(i,j) is up to date? 00366 if (mask.ocean(i,j)) { 00367 if (mask.icy(i,j)) { 00368 // rate of mass loss at bottom of ice shelf; can be negative (marine freeze-on) 00369 basalMeltRate[i][j] = shelfbmassflux(i,j); // set by PISMOceanCoupler 00370 // if floating ice is present assume maximally saturated till to avoid "shock" if 00371 // grounding line advances 00372 Hmelt[i][j] = hmelt_max; 00373 } else { 00374 basalMeltRate[i][j] = 0.0; 00375 Hmelt[i][j] = 0.0; 00376 } 00377 } else { 00378 // basalMeltRate is rate of change of Hmelt[][]; can be negative 00379 // (subglacial water freezes-on); note this rate is calculated 00380 // *before* limiting Hmelt. 00381 basalMeltRate[i][j] = (Hmeltnew - Hmelt[i][j]) / (dt_years_TempAge * secpera); 00382 // model loss to undetermined exterior: 00383 Hmeltnew -= hmelt_decay_rate * (dt_years_TempAge * secpera); 00384 Hmelt[i][j] = PetscMin(hmelt_max, PetscMax(Hmeltnew, 0.0)); 00385 } 00386 00387 } 00388 } 00389 00390 if (myLowTempCount > maxLowTempCount) { SETERRQ(1,"too many low temps"); } 00391 00392 ierr = vH.end_access(); CHKERRQ(ierr); 00393 ierr = vMask.end_access(); CHKERRQ(ierr); 00394 ierr = vHmelt.end_access(); CHKERRQ(ierr); 00395 ierr = Rb->end_access(); CHKERRQ(ierr); 00396 ierr = G0.end_access(); CHKERRQ(ierr); 00397 ierr = vbmr.end_access(); CHKERRQ(ierr); 00398 00399 ierr = artm.end_access(); CHKERRQ(ierr); 00400 00401 ierr = shelfbmassflux.end_access(); CHKERRQ(ierr); 00402 ierr = shelfbtemp.end_access(); CHKERRQ(ierr); 00403 00404 ierr = u3->end_access(); CHKERRQ(ierr); 00405 ierr = v3->end_access(); CHKERRQ(ierr); 00406 ierr = w3->end_access(); CHKERRQ(ierr); 00407 ierr = Sigma3->end_access(); CHKERRQ(ierr); 00408 ierr = T3.end_access(); CHKERRQ(ierr); 00409 ierr = vWork3d.end_access(); CHKERRQ(ierr); 00410 00411 delete [] x; 00412 delete [] system.T; delete [] system.Sigma; 00413 delete [] system.u; delete [] system.v; delete [] system.w; 00414 delete [] Tnew; 00415 return 0; 00416 } 00417
1.7.3