PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/iMtemp.cc

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