PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/basal_strength/PISMYieldStress.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 "PISMYieldStress.hh"
00020 #include "Mask.hh"
00021 
00023 
00042 PetscErrorCode PISMDefaultYieldStress::allocate() {
00043   PetscErrorCode ierr;
00044 
00045   ierr = till_phi.create(grid, "tillphi", true, grid.max_stencil_width); CHKERRQ(ierr);
00046   ierr = till_phi.set_attrs("model_state",
00047                             "friction angle for till under grounded ice sheet",
00048                             "degrees", ""); CHKERRQ(ierr);
00049   till_phi.time_independent = true; // in this model; need not be
00050                                     // time-independent in general
00051 
00052   return 0;
00053 }
00054 
00056 
00086 PetscErrorCode PISMDefaultYieldStress::init(PISMVars &vars)
00087 {
00088   PetscErrorCode ierr;
00089   PetscScalar pseudo_plastic_q = config.get("pseudo_plastic_q");
00090   bool topg_to_phi_set, plastic_phi_set, bootstrap, i_set;
00091   string filename;
00092   int start;
00093 
00094   variables = &vars;
00095 
00096   ierr = verbPrintf(2, grid.com, "* Initializing the default basal yield stress model...\n"); CHKERRQ(ierr);
00097 
00098   basal_water_thickness = dynamic_cast<IceModelVec2S*>(vars.get("bwat"));
00099   if (basal_water_thickness == NULL) SETERRQ(1, "bwat is not available");
00100 
00101   basal_melt_rate = dynamic_cast<IceModelVec2S*>(vars.get("bmelt"));
00102   if (basal_melt_rate == NULL) SETERRQ(1, "bmelt is not available");
00103 
00104   ice_thickness = dynamic_cast<IceModelVec2S*>(vars.get("land_ice_thickness"));
00105   if (ice_thickness == NULL) SETERRQ(1, "land_ice_thickness is not available");
00106 
00107   bed_topography = dynamic_cast<IceModelVec2S*>(vars.get("bedrock_altitude"));
00108   if (bed_topography == NULL) SETERRQ(1, "bedrock_altitude is not available");
00109 
00110   mask = dynamic_cast<IceModelVec2Int*>(vars.get("mask"));
00111   if (mask == NULL) SETERRQ(1, "mask is not available");
00112 
00113   ierr = PetscOptionsBegin(grid.com, "", "Options controlling the basal till yield stress model", ""); CHKERRQ(ierr);
00114   {
00115     ierr = PISMOptionsIsSet("-plastic_phi", plastic_phi_set); CHKERRQ(ierr);
00116     ierr = PISMOptionsIsSet("-topg_to_phi",
00117                             "Use the till friction angle parameterization", topg_to_phi_set); CHKERRQ(ierr);
00118     ierr = PISMOptionsIsSet("-i", "PISM input file", i_set); CHKERRQ(ierr);
00119     ierr = PISMOptionsIsSet("-boot_file", "PISM bootstrapping file",
00120                             bootstrap); CHKERRQ(ierr);
00121 
00122     bool scaleSet;
00123     double slidescale;
00124     ierr = PISMOptionsReal("-sliding_scale",
00125                            "Divides pseudo-plastic tauc (yield stress) by given factor;"
00126                            " this would increase sliding by given factor in absence of membrane stresses",
00127                            slidescale, scaleSet); CHKERRQ(ierr);
00128     if (scaleSet) { // only modify config if option set; otherwise leave alone
00129       if (slidescale > 0.0) {
00130         ierr = verbPrintf(2, grid.com,
00131                           "option -sliding_scale read; pseudo yield stress tauc will be divided by %.4f to\n"
00132                           "  cause notional sliding speed-up by given factor %.4f ...\n",
00133                           pow(slidescale, pseudo_plastic_q), slidescale);  CHKERRQ(ierr);
00134         sliding_scale = slidescale;
00135       } else {
00136         ierr = verbPrintf(1, grid.com,
00137                           "PISM WARNING: negative or zero value given for option -sliding_scale ignored\n");
00138         CHKERRQ(ierr);
00139       }
00140     }
00141   }
00142   ierr = PetscOptionsEnd(); CHKERRQ(ierr);
00143 
00144 
00145   if (topg_to_phi_set && plastic_phi_set) {
00146     PetscPrintf(grid.com, "ERROR: only one of -plastic_phi and -topg_to_phi is allowed.\n");
00147     PISMEnd();
00148   }
00149 
00150   if (plastic_phi_set) {
00151 
00152     ierr = till_phi.set(config.get("default_till_phi")); CHKERRQ(ierr);
00153 
00154   } else if (topg_to_phi_set) {
00155 
00156     ierr = verbPrintf(2, grid.com,
00157                       "  option -topg_to_phi seen; creating tillphi map from bed elev ...\n");
00158     CHKERRQ(ierr);
00159 
00160     // note option -topg_to_phi will be read again to get comma separated array of parameters
00161     ierr = topg_to_phi(); CHKERRQ(ierr);
00162 
00163   } else if (i_set || bootstrap) {
00164 
00165     ierr = find_pism_input(filename, bootstrap, start); CHKERRQ(ierr);
00166 
00167     if (i_set) {
00168       ierr = till_phi.read(filename, start); CHKERRQ(ierr);
00169     } else {
00170       ierr = till_phi.regrid(filename,
00171                              config.get("bootstrapping_tillphi_value_no_var")); CHKERRQ(ierr);
00172     }
00173   }
00174 
00175   ierr = regrid(); CHKERRQ(ierr);
00176 
00177   return 0;
00178 }
00179 
00180 
00181 PetscErrorCode PISMDefaultYieldStress::regrid() {
00182   PetscErrorCode ierr;
00183   bool regrid_file_set, regrid_vars_set;
00184   string regrid_file;
00185   vector<string> regrid_vars;
00186 
00187   ierr = PetscOptionsBegin(grid.com, "", "PISMDefaultYieldStress regridding options", ""); CHKERRQ(ierr);
00188   {
00189     ierr = PISMOptionsString("-regrid_file", "regridding file name",
00190                              regrid_file, regrid_file_set); CHKERRQ(ierr);
00191     ierr = PISMOptionsStringArray("-regrid_vars", "comma-separated list of regridding variables",
00192                                   "", regrid_vars, regrid_vars_set); CHKERRQ(ierr);
00193   }
00194   ierr = PetscOptionsEnd(); CHKERRQ(ierr);
00195 
00196   if (! regrid_file_set) return 0;
00197 
00198   set<string> vars;
00199   for (unsigned int i = 0; i < regrid_vars.size(); ++i)
00200     vars.insert(regrid_vars[i]);
00201 
00202   // stop if the user did not ask to regrid tillphi
00203   if (!set_contains(vars, till_phi.string_attr("short_name")))
00204     return 0;
00205 
00206   ierr = till_phi.regrid(regrid_file, true); CHKERRQ(ierr);
00207 
00208   return 0;
00209 }
00210 
00211 
00212 
00213 void PISMDefaultYieldStress::add_vars_to_output(string /*keyword*/, set<string> &result) {
00214   result.insert("tillphi");
00215 }
00216 
00217 
00218 void PISMDefaultYieldStress::get_diagnostics(map<string, PISMDiagnostic*> &dict) {
00219   dict["bwp"] = new PYS_bwp(this, grid, *variables);
00220 }
00221 
00222 
00223 PetscErrorCode PISMDefaultYieldStress::define_variables(set<string> vars, const NCTool &nc,
00224                                                  nc_type nctype) {
00225   if (set_contains(vars, "tillphi")) {
00226     PetscErrorCode ierr = till_phi.define(nc, nctype); CHKERRQ(ierr);
00227   }
00228   return 0;
00229 }
00230 
00231 
00232 PetscErrorCode PISMDefaultYieldStress::write_variables(set<string> vars, string filename) {
00233   if (set_contains(vars, "tillphi")) {
00234     PetscErrorCode ierr = till_phi.write(filename); CHKERRQ(ierr);
00235   }
00236   return 0;
00237 }
00238 
00239 PetscErrorCode PISMDefaultYieldStress::update(PetscReal t_years, PetscReal dt_years) {
00240   t = t_years; dt = dt_years;
00241   // this model performs a "diagnostic" computation (i.e. without time-stepping)
00242   return 0;
00243 }
00244 
00246 
00269 PetscErrorCode PISMDefaultYieldStress::basal_material_yield_stress(IceModelVec2S &result) {
00270   PetscErrorCode ierr;
00271 
00272   bool use_ssa_when_grounded = config.get_flag("use_ssa_when_grounded");
00273   // only makes sense when use_ssa_when_grounded == TRUE
00274   if (use_ssa_when_grounded == PETSC_FALSE) {
00275     SETERRQ(1, "use_ssa_when_grounded == PETSC_FALSE but updateYieldStressFromHmelt() called");
00276   }
00277 
00278 
00279   const PetscScalar
00280     till_pw_fraction = config.get("till_pw_fraction"),
00281     till_c_0 = config.get("till_c_0") * 1e3, // convert from kPa to Pa
00282     hmelt_max = config.get("hmelt_max"),
00283     ice_density = config.get("ice_density"),
00284     standard_gravity = config.get("standard_gravity");
00285 
00286 
00287   ierr = mask->begin_access(); CHKERRQ(ierr);
00288   ierr = result.begin_access(); CHKERRQ(ierr);
00289   ierr = ice_thickness->begin_access(); CHKERRQ(ierr);
00290   ierr = basal_water_thickness->begin_access(); CHKERRQ(ierr);
00291   ierr = basal_melt_rate->begin_access(); CHKERRQ(ierr);
00292   ierr = till_phi.begin_access(); CHKERRQ(ierr);
00293 
00294   MaskQuery m(*mask);
00295 
00296   PetscInt GHOSTS = grid.max_stencil_width;
00297   for (PetscInt   i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) {
00298     for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) {
00299       if (m.ocean(i, j)) {
00300         result(i, j) = 0.0;
00301       } else if (m.ice_free(i, j)) {
00302         result(i, j) = 1000.0e3;  // large yield stress of 1000 kPa = 10 bar if no ice
00303       } else { // grounded and there is some ice
00304         const PetscScalar
00305           p_over = ice_density * standard_gravity * (*ice_thickness)(i, j), // FIXME task #7297
00306           p_w    = basal_water_pressure((*ice_thickness)(i, j),
00307                                         (*basal_water_thickness)(i, j),
00308                                         (*basal_melt_rate)(i, j),
00309                                         till_pw_fraction, hmelt_max),
00310           N      = p_over - p_w;  // effective pressure on till
00311 
00312         result(i, j) = till_c_0 + N * tan((pi/180.0) * till_phi(i, j));
00313       }
00314     }
00315   }
00316 
00317   ierr = mask->end_access(); CHKERRQ(ierr);
00318   ierr = result.end_access(); CHKERRQ(ierr);
00319   ierr = ice_thickness->end_access(); CHKERRQ(ierr);
00320   ierr = till_phi.end_access(); CHKERRQ(ierr);
00321   ierr = basal_melt_rate->end_access(); CHKERRQ(ierr);
00322   ierr = basal_water_thickness->end_access(); CHKERRQ(ierr);
00323 
00324 /* scale tauc if desired:
00325 A scale factor of \f$A\f$ is intended to increase basal sliding rate by
00326 \f$A\f$.  It would have exactly this effect \e if the driving stress were
00327 \e hypothetically completely held by the basal resistance.  Thus this scale factor
00328 is used to reduce (if \c -sliding_scale \f$A\f$ with \f$A > 1\f$) or increase
00329 (if \f$A < 1\f$) the value of the (pseudo-) yield stress \c tauc.  The concept
00330 behind this is described at
00331 http://websrv.cs.umt.edu/isis/index.php/Category_1:_Whole_Ice_Sheet#Initial_Experiment_-_E1_-_Increased_Basal_Lubrication.
00332 Specifically, the concept behind this mechanism is to suppose equality of driving
00333 and basal shear stresses,
00334     \f[ \rho g H \nabla h = \frac{\tau_c}{|\mathbf{U}|^{1-q} U_{\mathtt{th}}^q} \mathbf{U}. \f]
00335 (<i>For emphasis:</i> The membrane stress held by the ice itself is missing from
00336 this incomplete stress balance.)  Thus the pseudo yield stress
00337 \f$\tau_c\f$ would be related to the sliding speed \f$|\mathbf{U}|\f$ by
00338   \f[ |\mathbf{U}| = \frac{C}{\tau_c^{1/q}} \f]
00339 for some (geometry-dependent) constant \f$C\f$.  Multiplying \f$|\mathbf{U}|\f$
00340 by \f$A\f$ in this equation corresponds to dividing \f$\tau_c\f$ by \f$A^q\f$.
00341 The current method sets-up the mechanism, and updateYieldStressUsingBasalWater()
00342 actually computes it.  Note that the mechanism has no effect whatsoever if 
00343 \f$q=0\f$, which is the purely plastic case. In that case there is \e no direct
00344 relation between the yield stress and the sliding velocity, and the difference 
00345 between the driving stress and the yield stress is entirely held by the membrane
00346 stresses.  (There is also no singular mathematical operation as \f$A^q = A^0 = 1\f$.)
00347 */
00348   if (sliding_scale > 0.0) {
00349     const PetscScalar q = config.get("pseudo_plastic_q");
00350     result.scale(1.0 / pow(sliding_scale, q));
00351   }
00352 
00353   return 0;
00354 }
00355 
00357 
00381 PetscErrorCode PISMDefaultYieldStress::topg_to_phi() {
00382   PetscErrorCode ierr;
00383 
00384   PetscInt    Nparam=5;
00385   PetscReal   inarray[5] = {5.0, 15.0, -1000.0, 1000.0, 10.0};
00386 
00387   // read comma-separated array of zero to five values
00388   PetscTruth  topg_to_phi_set;
00389   ierr = PetscOptionsGetRealArray(PETSC_NULL, "-topg_to_phi", inarray, &Nparam, &topg_to_phi_set);
00390   CHKERRQ(ierr);
00391   if (topg_to_phi_set != PETSC_TRUE) {
00392     SETERRQ(1, "HOW DID I GET HERE? ... ending...\n");
00393   }
00394 
00395   if ((Nparam > 5) || (Nparam < 4)) {
00396     ierr = verbPrintf(1, grid.com,
00397                       "PISM ERROR: option -topg_to_phi provided with more than 5 or fewer than 4\n"
00398                       "            arguments ... ENDING ...\n");
00399     CHKERRQ(ierr);
00400     PISMEnd();
00401   }
00402 
00403   PetscReal phi_min = inarray[0], phi_max = inarray[1],
00404     topg_min = inarray[2], topg_max = inarray[3],
00405     phi_ocean = inarray[4];
00406 
00407   ierr = verbPrintf(2, grid.com,
00408                     "  till friction angle (phi) is piecewise-linear function of bed elev (topg):\n"
00409                     "            /  %5.2f                                 for   topg < %.f\n"
00410                     "      phi = |  %5.2f + (topg - %.f) * (%.2f / %.f)   for   %.f < topg < %.f\n"
00411                     "            \\  %5.2f                                 for   %.f < topg\n",
00412                     phi_min, topg_min,
00413                     phi_min, topg_min, phi_max - phi_min, topg_max - topg_min, topg_min, topg_max,
00414                     phi_max, topg_max); CHKERRQ(ierr);
00415 
00416   if (Nparam == 5) {
00417     ierr = verbPrintf(2, grid.com,
00418                       "      (also using phi = %5.2f in floating ice or ice free ocean)\n",
00419                       phi_ocean); CHKERRQ(ierr);
00420   }
00421 
00422   MaskQuery m(*mask);
00423 
00424   PetscReal slope = (phi_max - phi_min) / (topg_max - topg_min);
00425   ierr = mask->begin_access(); CHKERRQ(ierr);
00426   ierr = bed_topography->begin_access(); CHKERRQ(ierr);
00427   ierr = till_phi.begin_access(); CHKERRQ(ierr);
00428 
00429   for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00430     for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00431       PetscScalar bed = (*bed_topography)(i, j);
00432 
00433       if (m.grounded(i, j) || (Nparam < 5)) {
00434         if (bed <= topg_min) {
00435           till_phi(i, j) = phi_min;
00436         } else if (bed >= topg_max) {
00437           till_phi(i, j) = phi_max;
00438         } else {
00439           till_phi(i, j) = phi_min + (bed - topg_min) * slope;
00440         }
00441       } else {
00442         till_phi(i,j) = phi_ocean;
00443       }
00444     }
00445   }
00446 
00447   ierr = mask->end_access(); CHKERRQ(ierr);
00448   ierr = bed_topography->end_access(); CHKERRQ(ierr);
00449   ierr = till_phi.end_access(); CHKERRQ(ierr);
00450 
00451   // communicate ghosts so that the tauc computation can be performed locally
00452   // (including ghosts of tauc, that is)
00453   ierr = till_phi.beginGhostComm(); CHKERRQ(ierr);
00454   ierr = till_phi.endGhostComm(); CHKERRQ(ierr);
00455 
00456   return 0;
00457 }
00458 
00460 
00521 PetscScalar PISMDefaultYieldStress::basal_water_pressure(PetscScalar thk, PetscScalar bwat,
00522                                                   PetscScalar bmr, PetscScalar frac,
00523                                                   PetscScalar hmelt_max) {
00524   if (bwat > hmelt_max + 1.0e-6) {
00525     PetscPrintf(grid.com,
00526                 "PISM ERROR:  bwat = %12.8f exceeds hmelt_max = %12.8f\n"
00527                 "  in IceModel::getBasalWaterPressure()\n",bwat,hmelt_max);
00528     PISMEnd();
00529   }
00530 
00531   // the model; note 0 <= p_pw <= frac * p_overburden because  0 <= bwat <= hmelt_max
00532   const PetscScalar p_overburden = p.ice_density * p.standard_gravity * thk; // FIXME task #7297
00533   PetscScalar p_pw = frac * (bwat / hmelt_max) * p_overburden;
00534 
00535   if (p.usebmr) {
00536     // add to pressure from instantaneous basal melt rate;
00537     //   note  (additional) <= (1.0 - frac) * p_overburden so
00538     //   0 <= p_pw <= p_overburden
00539     p_pw += ( 1.0 - exp( - PetscMax(0.0,bmr) / p.bmr_scale ) )
00540       * (1.0 - frac) * p_overburden;
00541   }
00542 
00543   if (p.usethkeff) {
00544     // ice thickness is surrogate for distance to margin; near margin the till
00545     //   is presumably better drained so we reduce the water pressure
00546     if (thk < p.thkeff_H_high) {
00547       if (thk <= p.thkeff_H_low) {
00548         p_pw *= p.thkeff_reduce;
00549       } else {
00550         // case Hlow < thk < Hhigh; use linear to connect (Hlow, reduced * p_pw)
00551         //   to (Hhigh, 1.0 * p_w)
00552         p_pw *= p.thkeff_reduce
00553           + (1.0 - p.thkeff_reduce)
00554           * (thk - p.thkeff_H_low) / (p.thkeff_H_high - p.thkeff_H_low);
00555       }
00556     }
00557   }
00558 
00559   return p_pw;
00560 }
00561 
00562 
00563 PYS_bwp::PYS_bwp(PISMDefaultYieldStress *m, IceGrid &g, PISMVars &my_vars)
00564   : PISMDiag<PISMDefaultYieldStress>(m, g, my_vars) {
00565   
00566   // set metadata:
00567   vars[0].init_2d("bwp", grid);
00568   set_attrs("subglacial (pore) water pressure", "", "Pa", "Pa", 0);
00569   vars[0].set("_FillValue", -0.01);
00570   vars[0].set("valid_min", 0);
00571 }
00572 
00573 
00580 PetscErrorCode PYS_bwp::compute(IceModelVec* &output) {
00581   PetscErrorCode ierr;
00582 
00583   IceModelVec2S *result = new IceModelVec2S;
00584   ierr = result->create(grid, "bwp", false); CHKERRQ(ierr);
00585   ierr = result->set_metadata(vars[0], 0); CHKERRQ(ierr);
00586 
00587   const PetscScalar
00588     alpha     = model->config.get("till_pw_fraction"),
00589     wmax      = model->config.get("hmelt_max"),
00590     fillval   = -0.01;
00591 
00592   ierr = model->ice_thickness->begin_access(); CHKERRQ(ierr);
00593   ierr = model->basal_water_thickness->begin_access(); CHKERRQ(ierr);
00594   ierr = model->basal_melt_rate->begin_access(); CHKERRQ(ierr);
00595   ierr = result->begin_access(); CHKERRQ(ierr);
00596   for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00597     for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00598       PetscReal thk = (*model->ice_thickness)(i, j);
00599       if (thk > 0.0) {
00600         (*result)(i,j) = model->basal_water_pressure(thk, // FIXME task #7297
00601                                                      (*model->basal_water_thickness)(i,j),
00602                                                      (*model->basal_melt_rate)(i,j),
00603                                                      alpha, wmax);
00604       } else { // put negative value below valid range
00605         (*result)(i,j) = fillval;
00606       }
00607     }
00608   }
00609   ierr = model->ice_thickness->end_access(); CHKERRQ(ierr);
00610   ierr = model->basal_water_thickness->end_access(); CHKERRQ(ierr);
00611   ierr = model->basal_melt_rate->end_access(); CHKERRQ(ierr);
00612   ierr = result->end_access(); CHKERRQ(ierr);
00613 
00614   MaskQuery m(*model->mask);
00615 
00616   ierr = m.fill_where_floating(*result, fillval); CHKERRQ(ierr);
00617   
00618   output = result;
00619   return 0;
00620 }
00621 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines