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