|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 // Copyright (C) 2004--2011 Constantine Khroulev, Ed Bueler, Jed Brown, Torsten Albrecht 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 "SSA.hh" 00020 #include "Mask.hh" 00021 00022 SSA::SSA(IceGrid &g, IceBasalResistancePlasticLaw &b, 00023 IceFlowLaw &i, EnthalpyConverter &e, 00024 const NCConfigVariable &c) 00025 : ShallowStressBalance(g, b, i, e, c) 00026 { 00027 mask = NULL; 00028 thickness = NULL; 00029 tauc = NULL; 00030 surface = NULL; 00031 bed = NULL; 00032 enthalpy = NULL; 00033 00034 strength_extension = new SSAStrengthExtension(config); 00035 allocate(); 00036 } 00037 00038 00040 PetscErrorCode SSA::init(PISMVars &vars) { 00041 PetscErrorCode ierr; 00042 00043 ierr = ShallowStressBalance::init(vars); CHKERRQ(ierr); 00044 00045 ierr = verbPrintf(2,grid.com,"* Initializing the SSA stress balance...\n"); CHKERRQ(ierr); 00046 00047 mask = dynamic_cast<IceModelVec2Int*>(vars.get("mask")); 00048 if (mask == NULL) SETERRQ(1, "mask is not available"); 00049 00050 thickness = dynamic_cast<IceModelVec2S*>(vars.get("land_ice_thickness")); 00051 if (thickness == NULL) SETERRQ(1, "land_ice_thickness is not available"); 00052 00053 tauc = dynamic_cast<IceModelVec2S*>(vars.get("tauc")); 00054 if (tauc == NULL) SETERRQ(1, "tauc is not available"); 00055 00056 surface = dynamic_cast<IceModelVec2S*>(vars.get("surface_altitude")); 00057 if (surface == NULL) SETERRQ(1, "surface_altitude is not available"); 00058 00059 bed = dynamic_cast<IceModelVec2S*>(vars.get("bedrock_altitude")); 00060 if (bed == NULL) SETERRQ(1, "bedrock_altitude is not available"); 00061 00062 enthalpy = dynamic_cast<IceModelVec3*>(vars.get("enthalpy")); 00063 if (enthalpy == NULL) SETERRQ(1, "enthalpy is not available"); 00064 00065 00066 // Check if PISM is being initialized from an output file from a previous run 00067 // and read the initial guess (unless asked not to). 00068 bool i_set; 00069 string filename; 00070 ierr = PISMOptionsString("-i", "PISM input file", 00071 filename, i_set); CHKERRQ(ierr); 00072 00073 if (i_set) { 00074 bool dont_read_initial_guess, ubar_ssa_found, vbar_ssa_found; 00075 int start; 00076 NCTool nc(grid.com, grid.rank); 00077 00078 ierr = PISMOptionsIsSet("-dontreadSSAvels", dont_read_initial_guess); CHKERRQ(ierr); 00079 00080 ierr = nc.open_for_reading(filename.c_str()); CHKERRQ(ierr); 00081 ierr = nc.find_variable("ubar_ssa", NULL, ubar_ssa_found); CHKERRQ(ierr); 00082 ierr = nc.find_variable("vbar_ssa", NULL, vbar_ssa_found); CHKERRQ(ierr); 00083 ierr = nc.get_nrecords(start); CHKERRQ(ierr); 00084 ierr = nc.close(); CHKERRQ(ierr); 00085 start -= 1; 00086 00087 if (ubar_ssa_found && vbar_ssa_found && 00088 (! dont_read_initial_guess)) { 00089 ierr = verbPrintf(3,grid.com,"Reading ubar_ssa and vbar_ssa...\n"); CHKERRQ(ierr); 00090 00091 ierr = velocity.read(filename.c_str(), start); CHKERRQ(ierr); 00092 } 00093 00094 } else { 00095 ierr = velocity.set(0.0); CHKERRQ(ierr); // default initial guess 00096 } 00097 00098 if (config.get_flag("dirichlet_bc")) { 00099 00100 bc_locations = dynamic_cast<IceModelVec2Int*>(vars.get("bcflag")); 00101 if (bc_locations == NULL) SETERRQ(1, "bc_locations is not available"); 00102 00103 vel_bc = dynamic_cast<IceModelVec2V*>(vars.get("velbar")); 00104 if (vel_bc == NULL) SETERRQ(1, "velbar is not available"); 00105 } 00106 00107 event_ssa = grid.profiler->create("ssa_update", "time spent solving the SSA"); 00108 00109 return 0; 00110 } 00111 00113 PetscErrorCode SSA::allocate() { 00114 PetscErrorCode ierr; 00115 00116 ierr = taud.create(grid, "taud", false); CHKERRQ(ierr); 00117 ierr = taud.set_attrs("diagnostic", 00118 "X-component of the driving shear stress at the base of ice", 00119 "Pa", "", 0); CHKERRQ(ierr); 00120 ierr = taud.set_attrs("diagnostic", 00121 "Y-component of the driving shear stress at the base of ice", 00122 "Pa", "", 1); CHKERRQ(ierr); 00123 00124 ierr = velocity_old.create(grid, "velocity_old", true); CHKERRQ(ierr); 00125 ierr = velocity_old.set_attrs("internal", 00126 "old SSA velocity field; used for re-trying with a different epsilon", 00127 "m s-1", ""); CHKERRQ(ierr); 00128 00129 // override velocity metadata 00130 ierr = velocity.set_name("bar_ssa"); CHKERRQ(ierr); 00131 ierr = velocity.set_attrs("internal_restart", "SSA model ice velocity in the X direction", 00132 "m s-1", "", 0); CHKERRQ(ierr); 00133 00134 ierr = velocity.set_attrs("internal_restart", "SSA model ice velocity in the Y direction", 00135 "m s-1", "", 1); CHKERRQ(ierr); 00136 00137 ierr = velocity.set_glaciological_units("m year-1"); CHKERRQ(ierr); 00138 00139 // mimic IceGrid::createDA() with TRANSPOSE : 00140 PetscInt dof=2, stencil_width=1; 00141 ierr = DACreate2d(grid.com, DA_XYPERIODIC, DA_STENCIL_BOX, 00142 grid.My, grid.Mx, 00143 grid.Ny, grid.Nx, 00144 dof, stencil_width, 00145 grid.procs_y.data(), grid.procs_x.data(), 00146 &SSADA); CHKERRQ(ierr); 00147 00148 ierr = DACreateGlobalVector(SSADA, &SSAX); CHKERRQ(ierr); 00149 00150 return 0; 00151 } 00152 00153 00154 PetscErrorCode SSA::deallocate() { 00155 PetscErrorCode ierr; 00156 00157 if (SSAX != PETSC_NULL) { 00158 ierr = VecDestroy(SSAX); CHKERRQ(ierr); 00159 } 00160 00161 if (SSADA != PETSC_NULL) { 00162 ierr = DADestroy(SSADA);CHKERRQ(ierr); 00163 } 00164 00165 return 0; 00166 } 00167 00168 00170 PetscErrorCode SSA::update(bool fast) { 00171 PetscErrorCode ierr; 00172 00173 if (fast) 00174 return 0; 00175 00176 grid.profiler->begin(event_ssa); 00177 00178 ierr = solve(); CHKERRQ(ierr); 00179 00180 ierr = compute_basal_frictional_heating(basal_frictional_heating); CHKERRQ(ierr); 00181 ierr = compute_D2(D2); CHKERRQ(ierr); 00182 00183 ierr = compute_maximum_velocity(); CHKERRQ(ierr); 00184 00185 grid.profiler->end(event_ssa); 00186 00187 return 0; 00188 } 00189 00190 00192 00195 PetscErrorCode SSA::compute_D2(IceModelVec2S &result) { 00196 PetscErrorCode ierr; 00197 PetscReal dx = grid.dx, dy = grid.dy; 00198 00199 ierr = velocity.begin_access(); CHKERRQ(ierr); 00200 ierr = result.begin_access(); CHKERRQ(ierr); 00201 for (PetscInt i = grid.xs; i < grid.xs+grid.xm; ++i) { 00202 for (PetscInt j = grid.ys; j < grid.ys+grid.ym; ++j) { 00203 const PetscScalar 00204 u_x = (velocity(i+1,j).u - velocity(i-1,j).u)/(2*dx), 00205 u_y = (velocity(i,j+1).u - velocity(i,j-1).u)/(2*dy), 00206 v_x = (velocity(i+1,j).v - velocity(i-1,j).v)/(2*dx), 00207 v_y = (velocity(i,j+1).v - velocity(i,j-1).v)/(2*dy); 00208 result(i,j) = PetscSqr(u_x) + PetscSqr(v_y) + u_x * v_y 00209 + PetscSqr(0.5*(u_y + v_x)); 00210 } 00211 } 00212 ierr = result.end_access(); CHKERRQ(ierr); 00213 ierr = velocity.end_access(); CHKERRQ(ierr); 00214 return 0; 00215 } 00216 00217 00219 00238 PetscErrorCode SSA::compute_principal_strain_rates(IceModelVec2S &result_e1, 00239 IceModelVec2S &result_e2) { 00240 PetscErrorCode ierr; 00241 PetscScalar dx = grid.dx, dy = grid.dy; 00242 00243 IceModelVec2S H = *thickness; // an alias 00244 ierr = velocity.begin_access(); CHKERRQ(ierr); 00245 ierr = H.begin_access(); CHKERRQ(ierr); 00246 ierr = result_e1.begin_access(); CHKERRQ(ierr); 00247 ierr = result_e2.begin_access(); CHKERRQ(ierr); 00248 00249 for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) { 00250 for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) { 00251 00252 if ( velocity(i,j).u == 0.0 || velocity(i,j).v == 0.0) { 00253 result_e1(i,j) = 0.0; 00254 result_e2(i,j) = 0.0; 00255 continue; 00256 } 00257 00258 //centered difference scheme; strain in units s-1 00259 PetscScalar 00260 u_x = (velocity(i+1,j).u - velocity(i-1,j).u) / (2 * dx), 00261 u_y = (velocity(i,j+1).u - velocity(i,j-1).u) / (2 * dy), 00262 v_x = (velocity(i+1,j).v - velocity(i-1,j).v) / (2 * dx), 00263 v_y = (velocity(i,j+1).v - velocity(i,j-1).v) / (2 * dy); 00264 00265 //inward scheme at the ice-shelf front 00266 if (H(i+1,j)==0.0) { 00267 u_x = (velocity(i,j).u - velocity(i-1,j).u) / dx; 00268 v_x = (velocity(i,j).v - velocity(i-1,j).v) / dx; 00269 } 00270 if (H(i-1,j)==0.0) { 00271 u_x = (velocity(i+1,j).u - velocity(i,j).u) / dx; 00272 v_x = (velocity(i+1,j).v - velocity(i,j).v) / dx; 00273 } 00274 if (H(i-1,j)==0.0) { 00275 u_y = (velocity(i,j).u - velocity(i,j-1).u) / dy; 00276 v_y = (velocity(i,j).v - velocity(i,j-1).v) / dy; 00277 } 00278 if (H(i-1,j)==0.0) { 00279 u_y = (velocity(i,j+1).u - velocity(i,j).u) / dy; 00280 v_y = (velocity(i,j+1).v - velocity(i,j).v) / dy; 00281 } 00282 00283 // ice nose case 00284 if (H(i,j-1)==0.0 && H(i,j+1)==0.0) { 00285 u_y = 0.0; 00286 v_y = 0.0; 00287 } 00288 if (H(i+1,j)==0.0 && H(i-1,j)==0.0) { 00289 u_x = 0.0; 00290 v_x = 0.0; 00291 } 00292 00293 const PetscScalar A = 0.5 * (u_x + v_y), // A = (1/2) trace(D) 00294 B = 0.5 * (u_x - v_y), 00295 Dxy = 0.5 * (v_x + u_y), // B^2 = A^2 - u_x v_y 00296 q = sqrt(PetscSqr(B) + PetscSqr(Dxy)); 00297 result_e1(i,j) = A + q; 00298 result_e2(i,j) = A - q; // q >= 0 so e1 >= e2 00299 00300 } // j 00301 } // i 00302 00303 ierr = velocity.end_access(); CHKERRQ(ierr); 00304 ierr = H.end_access(); CHKERRQ(ierr); 00305 ierr = result_e1.end_access(); CHKERRQ(ierr); 00306 ierr = result_e2.end_access(); CHKERRQ(ierr); 00307 return 0; 00308 } 00309 00310 00312 00315 PetscErrorCode SSA::compute_basal_frictional_heating(IceModelVec2S &result) { 00316 PetscErrorCode ierr; 00317 00318 MaskQuery m(*mask); 00319 00320 ierr = velocity.begin_access(); CHKERRQ(ierr); 00321 ierr = result.begin_access(); CHKERRQ(ierr); 00322 ierr = tauc->begin_access(); CHKERRQ(ierr); 00323 ierr = mask->begin_access(); CHKERRQ(ierr); 00324 00325 for (PetscInt i = grid.xs; i < grid.xs+grid.xm; ++i) { 00326 for (PetscInt j = grid.ys; j < grid.ys+grid.ym; ++j) { 00327 if (m.ocean(i,j)) { 00328 result(i,j) = 0.0; 00329 } else { 00330 const PetscScalar 00331 C = basal.drag((*tauc)(i,j), velocity(i,j).u, velocity(i,j).v), 00332 basal_stress_x = - C * velocity(i,j).u, 00333 basal_stress_y = - C * velocity(i,j).v; 00334 result(i,j) = - basal_stress_x * velocity(i,j).u - basal_stress_y * velocity(i,j).v; 00335 } 00336 } 00337 } 00338 00339 ierr = mask->end_access(); CHKERRQ(ierr); 00340 ierr = tauc->end_access(); CHKERRQ(ierr); 00341 ierr = result.end_access(); CHKERRQ(ierr); 00342 ierr = velocity.end_access(); CHKERRQ(ierr); 00343 return 0; 00344 } 00345 00347 00360 PetscErrorCode SSA::compute_driving_stress(IceModelVec2V &result) { 00361 PetscErrorCode ierr; 00362 00363 IceModelVec2S &thk = *thickness; // to improve readability (below) 00364 00365 const PetscScalar n = ice.exponent(), // frequently n = 3 00366 etapow = (2.0 * n + 2.0)/n, // = 8/3 if n = 3 00367 invpow = 1.0 / etapow, // = 3/8 00368 dinvpow = (- n - 2.0) / (2.0 * n + 2.0); // = -5/8 00369 const PetscScalar minThickEtaTransform = 5.0; // m 00370 const PetscScalar dx=grid.dx, dy=grid.dy; 00371 00372 bool compute_surf_grad_inward_ssa = config.get_flag("compute_surf_grad_inward_ssa"); 00373 PetscReal standard_gravity = config.get("standard_gravity"); 00374 bool use_eta = (config.get_string("surface_gradient_method") == "eta"); 00375 00376 ierr = surface->begin_access(); CHKERRQ(ierr); 00377 ierr = bed->begin_access(); CHKERRQ(ierr); 00378 ierr = mask->begin_access(); CHKERRQ(ierr); 00379 ierr = thk.begin_access(); CHKERRQ(ierr); 00380 00381 MaskQuery m(*mask); 00382 00383 ierr = result.begin_access(); CHKERRQ(ierr); 00384 00385 for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) { 00386 for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) { 00387 const PetscScalar pressure = ice.rho * standard_gravity * thk(i,j); // FIXME task #7297 00388 if (pressure <= 0.0) { 00389 result(i,j).u = 0.0; 00390 result(i,j).v = 0.0; 00391 } else { 00392 PetscScalar h_x = 0.0, h_y = 0.0; 00393 // FIXME: we need to handle grid periodicity correctly. 00394 if (m.grounded(i,j) && (use_eta == true)) { 00395 // in grounded case, differentiate eta = H^{8/3} by chain rule 00396 if (thk(i,j) > 0.0) { 00397 const PetscScalar myH = (thk(i,j) < minThickEtaTransform ? 00398 minThickEtaTransform : thk(i,j)); 00399 const PetscScalar eta = pow(myH, etapow), factor = invpow * pow(eta, dinvpow); 00400 h_x = factor * (pow(thk(i+1,j),etapow) - pow(thk(i-1,j),etapow)) / (2*dx); 00401 h_y = factor * (pow(thk(i,j+1),etapow) - pow(thk(i,j-1),etapow)) / (2*dy); 00402 } 00403 // now add bed slope to get actual h_x,h_y 00404 // FIXME: there is no reason to assume user's bed is periodized 00405 h_x += bed->diff_x(i,j); 00406 h_y += bed->diff_y(i,j); 00407 } else { // floating or eta transformation is not used 00408 if (compute_surf_grad_inward_ssa) { 00409 h_x = surface->diff_x_p(i,j); 00410 h_y = surface->diff_y_p(i,j); 00411 } else { 00412 h_x = surface->diff_x(i,j); 00413 h_y = surface->diff_y(i,j); 00414 } 00415 } 00416 00417 result(i,j).u = - pressure * h_x; 00418 result(i,j).v = - pressure * h_y; 00419 } 00420 } 00421 } 00422 00423 ierr = thk.end_access(); CHKERRQ(ierr); 00424 ierr = bed->end_access(); CHKERRQ(ierr); 00425 ierr = surface->end_access(); CHKERRQ(ierr); 00426 ierr = mask->end_access(); CHKERRQ(ierr); 00427 ierr = result.end_access(); CHKERRQ(ierr); 00428 return 0; 00429 } 00430 00431 00434 PetscErrorCode SSA::compute_maximum_velocity() { 00435 PetscErrorCode ierr; 00436 PetscReal my_max_u = 0.0, 00437 my_max_v = 0.0; 00438 00439 ierr = velocity.begin_access(); CHKERRQ(ierr); 00440 ierr = mask->begin_access(); CHKERRQ(ierr); 00441 00442 MaskQuery m(*mask); 00443 00444 for (PetscInt i = grid.xs; i < grid.xs+grid.xm; ++i) { 00445 for (PetscInt j = grid.ys; j < grid.ys+grid.ym; ++j) { 00446 if (m.icy(i, j)) { 00447 my_max_u = PetscMax(my_max_u, PetscAbs(velocity(i,j).u)); 00448 my_max_v = PetscMax(my_max_v, PetscAbs(velocity(i,j).v)); 00449 } 00450 } 00451 } 00452 00453 ierr = mask->end_access(); CHKERRQ(ierr); 00454 ierr = velocity.end_access(); CHKERRQ(ierr); 00455 00456 ierr = PetscGlobalMax(&my_max_u, &max_u, grid.com); CHKERRQ(ierr); 00457 ierr = PetscGlobalMax(&my_max_v, &max_v, grid.com); CHKERRQ(ierr); 00458 return 0; 00459 } 00460 00461 PetscErrorCode SSA::stdout_report(string &result) { 00462 result = stdout_ssa; 00463 return 0; 00464 } 00465 00466 00468 PetscErrorCode SSA::set_initial_guess(IceModelVec2V &guess) { 00469 PetscErrorCode ierr; 00470 ierr = velocity.copy_from(guess); CHKERRQ(ierr); 00471 return 0; 00472 } 00473 00474 00475 void SSA::add_vars_to_output(string /*keyword*/, set<string> &result) { 00476 result.insert("velbar_ssa"); 00477 } 00478 00479 00480 PetscErrorCode SSA::define_variables(set<string> vars, const NCTool &nc, nc_type nctype) { 00481 PetscErrorCode ierr; 00482 00483 if (set_contains(vars, "velbar_ssa")) { 00484 ierr = velocity.define(nc, nctype); CHKERRQ(ierr); 00485 } 00486 00487 return 0; 00488 } 00489 00490 00491 PetscErrorCode SSA::write_variables(set<string> vars, string filename) { 00492 PetscErrorCode ierr; 00493 00494 if (set_contains(vars, "velbar_ssa")) { 00495 ierr = velocity.write(filename.c_str()); CHKERRQ(ierr); 00496 } 00497 00498 return 0; 00499 } 00500
1.7.3