|
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 <cmath> 00020 #include <cstring> 00021 #include <petscda.h> 00022 #include "iceModel.hh" 00023 #include "Mask.hh" 00024 00026 00037 PetscErrorCode IceModel::updateSurfaceElevationAndMask() { 00038 PetscErrorCode ierr; 00039 00040 ierr = update_mask(); CHKERRQ(ierr); 00041 ierr = update_surface_elevation(); CHKERRQ(ierr); 00042 00043 if (config.get_flag("kill_icebergs")) { 00044 ierr = killIceBergs(); CHKERRQ(ierr); 00045 } 00046 00047 return 0; 00048 } 00049 00050 00051 PetscErrorCode IceModel::update_mask() { 00052 PetscErrorCode ierr; 00053 00054 if (ocean == PETSC_NULL) { SETERRQ(1, "PISM ERROR: ocean == PETSC_NULL"); } 00055 PetscReal sea_level; 00056 ierr = ocean->sea_level_elevation(sea_level); CHKERRQ(ierr); 00057 00058 GeometryCalculator gc(sea_level, *ice, config); 00059 MaskQuery mask(vMask); 00060 00061 ierr = vH.begin_access(); CHKERRQ(ierr); 00062 ierr = vbed.begin_access(); CHKERRQ(ierr); 00063 ierr = vMask.begin_access(); CHKERRQ(ierr); 00064 00065 PetscInt GHOSTS = 2; 00066 for (PetscInt i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) { 00067 for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) { 00068 vMask(i, j) = gc.mask(vbed(i, j), vH(i,j)); 00069 } // inner for loop (j) 00070 } // outer for loop (i) 00071 00072 ierr = vH.end_access(); CHKERRQ(ierr); 00073 ierr = vbed.end_access(); CHKERRQ(ierr); 00074 ierr = vMask.end_access(); CHKERRQ(ierr); 00075 00076 return 0; 00077 } 00078 00079 PetscErrorCode IceModel::update_surface_elevation() { 00080 PetscErrorCode ierr; 00081 00082 MaskQuery mask(vMask); 00083 00084 if (ocean == PETSC_NULL) { SETERRQ(1, "PISM ERROR: ocean == PETSC_NULL"); } 00085 PetscReal sea_level; 00086 ierr = ocean->sea_level_elevation(sea_level); CHKERRQ(ierr); 00087 00088 GeometryCalculator gc(sea_level, *ice, config); 00089 00090 ierr = vh.begin_access(); CHKERRQ(ierr); 00091 ierr = vH.begin_access(); CHKERRQ(ierr); 00092 ierr = vbed.begin_access(); CHKERRQ(ierr); 00093 ierr = vMask.begin_access(); CHKERRQ(ierr); 00094 00095 PetscInt GHOSTS = 2; 00096 for (PetscInt i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) { 00097 for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) { 00098 // take this opportunity to check that vH(i, j) >= 0 00099 if (vH(i, j) < 0) { 00100 SETERRQ2(1, "Thickness negative at point i=%d, j=%d", i, j); 00101 } 00102 vh(i, j) = gc.surface(vbed(i, j), vH(i, j)); 00103 } 00104 } 00105 00106 ierr = vh.end_access(); CHKERRQ(ierr); 00107 ierr = vH.end_access(); CHKERRQ(ierr); 00108 ierr = vbed.end_access(); CHKERRQ(ierr); 00109 ierr = vMask.end_access(); CHKERRQ(ierr); 00110 00111 return 0; 00112 } 00113 00114 00116 00178 PetscErrorCode IceModel::massContExplicitStep() { 00179 PetscErrorCode ierr; 00180 PetscScalar my_nonneg_rule_flux = 0, my_ocean_kill_flux = 0, my_float_kill_flux = 0; 00181 00182 const PetscScalar dx = grid.dx, dy = grid.dy; 00183 bool do_ocean_kill = config.get_flag("ocean_kill"), 00184 floating_ice_killed = config.get_flag("floating_ice_killed"), 00185 include_bmr_in_continuity = config.get_flag("include_bmr_in_continuity"); 00186 00187 if (surface != NULL) { 00188 ierr = surface->ice_surface_mass_flux(acab); CHKERRQ(ierr); 00189 } else { SETERRQ(1, "PISM ERROR: surface == NULL"); } 00190 00191 if (ocean != NULL) { 00192 ierr = ocean->shelf_base_mass_flux(shelfbmassflux); CHKERRQ(ierr); 00193 } else { SETERRQ(2, "PISM ERROR: ocean == NULL"); } 00194 00195 IceModelVec2S vHnew = vWork2d[0]; 00196 ierr = vH.copy_to(vHnew); CHKERRQ(ierr); 00197 00198 IceModelVec2Stag *Qdiff; 00199 ierr = stress_balance->get_diffusive_flux(Qdiff); CHKERRQ(ierr); 00200 00201 IceModelVec2V *vel_advective; 00202 ierr = stress_balance->get_advective_2d_velocity(vel_advective); CHKERRQ(ierr); 00203 IceModelVec2V vel = *vel_advective; // just an alias 00204 00205 PetscScalar **bmr_gnded; 00206 ierr = vH.begin_access(); CHKERRQ(ierr); 00207 ierr = vbmr.get_array(bmr_gnded); CHKERRQ(ierr); 00208 ierr = Qdiff->begin_access(); CHKERRQ(ierr); 00209 ierr = vel_advective->begin_access(); CHKERRQ(ierr); 00210 ierr = acab.begin_access(); CHKERRQ(ierr); 00211 ierr = shelfbmassflux.begin_access(); CHKERRQ(ierr); 00212 ierr = vMask.begin_access(); CHKERRQ(ierr); 00213 ierr = vHnew.begin_access(); CHKERRQ(ierr); 00214 00215 // related to PIK part_grid mechanism; see Albrecht et al 2011 00216 const bool do_part_grid = config.get_flag("part_grid"), 00217 do_redist = config.get_flag("part_redist"); 00218 if (do_part_grid) { 00219 ierr = vHref.begin_access(); CHKERRQ(ierr); 00220 if (do_redist) { 00221 ierr = vHresidual.begin_access(); CHKERRQ(ierr); 00222 // FIXME: next line causes mass loss if max_loopcount in redistResiduals() 00223 // was not sufficient to zero - out vHresidual already 00224 ierr = vHresidual.set(0.0); CHKERRQ(ierr); 00225 } 00226 } 00227 const bool dirichlet_bc = config.get_flag("dirichlet_bc"); 00228 if (dirichlet_bc) { 00229 ierr = vBCMask.begin_access(); CHKERRQ(ierr); 00230 ierr = vBCvel.begin_access(); CHKERRQ(ierr); 00231 ierr = vbed.begin_access(); CHKERRQ(ierr); 00232 } 00233 00234 if (do_ocean_kill) { 00235 ierr = ocean_kill_mask.begin_access(); CHKERRQ(ierr); 00236 } 00237 00238 MaskQuery mask(vMask); 00239 00240 for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) { 00241 for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) { 00242 00243 PetscScalar divQ = 0.0; 00244 00245 if (mask.grounded(i, j)) { 00246 // staggered grid Div(Q) for diffusive non-sliding SIA deformation part: 00247 // Qdiff = - D grad h 00248 divQ = ((*Qdiff)(i, j, 0) - (*Qdiff)(i - 1, j, 0)) / dx 00249 + ((*Qdiff)(i, j, 1) - (*Qdiff)(i, j - 1, 1)) / dy; 00250 } 00251 00252 // get non-diffusive velocities according to old or -part_grid scheme 00253 planeStar<int> M = vMask.int_star(i, j); 00254 planeStar<PetscScalar> v; 00255 00256 if (dirichlet_bc) { 00257 //the staggered velocities have to be adjusted to Dirichlet boundary conditions 00258 if (vBCMask.as_int(i,j) == 0) { 00259 if (vBCMask.as_int(i+1,j) == 1) v.e = vBCvel(i + 1, j).u; 00260 if (vBCMask.as_int(i-1,j) == 1) v.w = vBCvel(i - 1, j).u; 00261 if (vBCMask.as_int(i,j+1) == 1) v.n = vBCvel(i, j + 1).v; 00262 if (vBCMask.as_int(i,j-1) == 1) v.s = vBCvel(i, j - 1).v; 00263 } 00264 } else { 00265 ierr = cell_interface_velocities(do_part_grid, i, j, v); CHKERRQ(ierr); 00266 } 00267 00268 // membrane stress (and/or basal sliding) part: upwind by staggered grid 00269 // PIK method; this is \nabla \cdot [(u, v) H] 00270 divQ += ( v.e * (v.e > 0 ? vH(i, j) : vH(i + 1, j)) 00271 - v.w * (v.w > 0 ? vH(i - 1, j) : vH(i, j)) ) / dx; 00272 divQ += ( v.n * (v.n > 0 ? vH(i, j) : vH(i, j + 1)) 00273 - v.s * (v.s > 0 ? vH(i, j - 1) : vH(i, j)) ) / dy; 00274 00275 00276 PetscReal S = 0.0; 00277 if (include_bmr_in_continuity) { 00278 if (mask.ocean(i, j)) 00279 S = shelfbmassflux(i,j); 00280 else 00281 S = bmr_gnded[i][j]; 00282 } 00283 00284 // decide whether to apply Albrecht et al 2011 subgrid-scale parameterization (-part_grid) 00285 00286 // case where we apply -part_grid 00287 //if (do_part_grid && mask.next_to_floating_ice(i, j) && !mask.next_to_grounded_ice(i, j)) { 00288 if (do_part_grid && mask.next_to_floating_ice(i, j)) { 00289 vHref(i, j) -= divQ * dt; 00290 if (vHref(i, j) < 0.0) { 00291 my_nonneg_rule_flux += ( - vHref(i, j)); 00292 vHref(i, j) = 0.0; 00293 ierr = verbPrintf(2, grid.com,"!!! PISM_WARNING: vHref is negative at i=%d, j=%d\n",i,j); CHKERRQ(ierr); 00294 } 00295 00296 PetscReal H_average = get_average_thickness(do_redist, M, vH.star(i, j)); 00297 00298 // To calculate the surface balance contribution with respect to the 00299 // coverage ratio, let X = vHref_new be the new value of Href. We assume 00300 // X = vHref_old + (M - S) * dt * coverageRatio 00301 // equivalently 00302 // X = vHref_old + (M - S) * dt * X / H_average. 00303 // where M = acab and S = shelfbaseflux for floating ice. Solving for X we get 00304 // X = vHref_old / (1.0 - (M - S) * dt * H_average)) 00305 /* 00306 if ((acab(i, j) - S) * dt < H_average) { 00307 vHref(i, j) = vHref(i, j) / (1.0 - (acab(i, j) - S) * dt / H_average); 00308 } else { 00309 ierr = verbPrintf(4, grid.com,"!!! PISM_WARNING: H_average is smaller than surface mass balance at i=%d, j=%d.\n",i,j); CHKERRQ(ierr); 00310 } 00311 */ 00312 00313 const PetscScalar coverageRatio = vHref(i, j) / H_average; 00314 00315 if (coverageRatio > 1.0) { // partially filled grid cell is considered to be full 00316 if (do_redist) { vHresidual(i, j) = vHref(i, j) - H_average; } //residual ice thickness 00317 vHnew(i, j) = H_average; // gets a "real" ice thickness 00318 vHnew(i, j)+= (acab(i, j) - S) * dt; // no implicit SMB in partially filled cells any more 00319 vHref(i, j) = 0.0; 00320 } else { 00321 vHnew(i, j) = 0.0; // no change from vH value, actually 00322 // vHref(i, j) not changed 00323 } 00324 00325 } else if (mask.grounded(i, j) || 00326 mask.floating_ice(i, j) || 00327 mask.next_to_grounded_ice(i, j) ) { 00328 // grounded/floating default case, and case of ice-free ocean adjacent to grounded 00329 vHnew(i, j) += (acab(i, j) - S - divQ) * dt; 00330 } else { 00331 // last possibility: ice-free, not adjacent to a "full" cell at all 00332 vHnew(i, j) = 0.0; 00333 } 00334 00335 if (dirichlet_bc && vBCMask.as_int(i,j) == 1) { 00336 vHnew(i, j) = vH(i,j); 00337 } 00338 00339 // apply free boundary rule: negative thickness becomes zero 00340 if (vHnew(i, j) < 0) { 00341 my_nonneg_rule_flux += ( - vHnew(i, j)); 00342 vHnew(i, j) = 0.0; 00343 } 00344 00345 // the following conditionals, both -ocean_kill and -float_kill, are also applied in 00346 // IceModel::computeMax2DSlidingSpeed() when determining CFL 00347 00348 // force zero thickness at points which were originally ocean (if "-ocean_kill"); 00349 // this is calving at original calving front location 00350 if ( do_ocean_kill && ocean_kill_mask.as_int(i, j) == 1) { 00351 my_ocean_kill_flux -= vHnew(i, j); 00352 vHnew(i, j) = 0.0; 00353 } 00354 00355 // force zero thickness at points which are floating (if "-float_kill"); 00356 // this is calving at grounding line 00357 if ( floating_ice_killed && mask.ocean(i, j) ) { 00358 my_float_kill_flux -= vHnew(i, j); 00359 vHnew(i, j) = 0.0; 00360 } 00361 00362 } // end of the inner for loop 00363 } // end of the outer for loop 00364 00365 ierr = vbmr.end_access(); CHKERRQ(ierr); 00366 ierr = vMask.end_access(); CHKERRQ(ierr); 00367 ierr = Qdiff->end_access(); CHKERRQ(ierr); 00368 ierr = vel_advective->end_access(); CHKERRQ(ierr); 00369 ierr = acab.end_access(); CHKERRQ(ierr); 00370 ierr = shelfbmassflux.end_access(); CHKERRQ(ierr); 00371 ierr = vH.end_access(); CHKERRQ(ierr); 00372 ierr = vHnew.end_access(); CHKERRQ(ierr); 00373 00374 if (do_part_grid) { 00375 ierr = vHref.end_access(); CHKERRQ(ierr); 00376 if (do_redist) { 00377 ierr = vHresidual.end_access(); CHKERRQ(ierr); 00378 } 00379 } 00380 00381 if (dirichlet_bc) { 00382 ierr = vBCMask.end_access(); CHKERRQ(ierr); 00383 ierr = vBCvel.end_access(); CHKERRQ(ierr); 00384 ierr = vbed.end_access(); CHKERRQ(ierr); 00385 } 00386 00387 if (do_ocean_kill) { 00388 ierr = ocean_kill_mask.end_access(); CHKERRQ(ierr); 00389 } 00390 00391 // flux accounting 00392 { 00393 ierr = PetscGlobalSum(&my_nonneg_rule_flux, &nonneg_rule_flux, grid.com); CHKERRQ(ierr); 00394 ierr = PetscGlobalSum(&my_ocean_kill_flux, &ocean_kill_flux, grid.com); CHKERRQ(ierr); 00395 ierr = PetscGlobalSum(&my_float_kill_flux, &float_kill_flux, grid.com); CHKERRQ(ierr); 00396 00397 // FIXME: use corrected cell areas (when available) 00398 PetscScalar ice_density = config.get("ice_density"), 00399 factor = ice_density * (dx * dy) / dt; 00400 nonneg_rule_flux *= factor; 00401 ocean_kill_flux *= factor; 00402 float_kill_flux *= factor; 00403 } //FIXME: flux reporting not yet adjusted to part_grid scheme 00404 00405 // compute dH/dt (thickening rate) for viewing and for saving at end; only diagnostic 00406 ierr = vHnew.add(-1.0, vH, vdHdt); CHKERRQ(ierr); // vdHdt = vHnew - vH 00407 ierr = vdHdt.scale(1.0 / dt); CHKERRQ(ierr); // vdHdt = vdHdt / dt 00408 00409 // d(volume) / dt 00410 { 00411 PetscScalar dvol = 0.0; 00412 00413 ierr = vdHdt.begin_access(); CHKERRQ(ierr); 00414 ierr = cell_area.begin_access(); CHKERRQ(ierr); 00415 for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) { 00416 for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) { 00417 dvol += vdHdt(i, j) * cell_area(i, j); 00418 } 00419 } 00420 ierr = cell_area.end_access(); CHKERRQ(ierr); 00421 ierr = vdHdt.end_access(); CHKERRQ(ierr); 00422 00423 ierr = PetscGlobalSum(&dvol, &dvoldt, grid.com); CHKERRQ(ierr); 00424 } 00425 00426 // average value of dH / dt; 00427 PetscScalar ice_area; 00428 ierr = compute_ice_area(ice_area); CHKERRQ(ierr); 00429 00430 ierr = vdHdt.sum(gdHdtav); CHKERRQ(ierr); 00431 gdHdtav = gdHdtav / ice_area; // m/s 00432 00433 // finally copy vHnew into vH and communicate ghosted values 00434 ierr = vHnew.beginGhostComm(vH); CHKERRQ(ierr); 00435 ierr = vHnew.endGhostComm(vH); CHKERRQ(ierr); 00436 00437 // the following calls are new routines adopted from PISM-PIK. The place and 00438 // order is not clear yet! 00439 00440 // There is no reporting of single ice fluxes yet in comparison to total ice 00441 // thickness change. 00442 00443 // distribute residual ice mass if desired 00444 if (do_redist) { 00445 ierr = redistResiduals(); CHKERRQ(ierr); 00446 } 00447 00448 // FIXME: maybe calving should be applied *before* the redistribution part? 00449 if (config.get_flag("do_eigen_calving") && config.get_flag("use_ssa_velocity")) { 00450 ierr = stress_balance->get_principal_strain_rates(vPrinStrain1, vPrinStrain2); CHKERRQ(ierr); 00451 ierr = eigenCalving(); CHKERRQ(ierr); 00452 } 00453 00454 if (config.get_flag("do_thickness_calving")) { 00455 if (config.get_flag("part_grid") == true) { 00456 ierr = calvingAtThickness(); CHKERRQ(ierr); 00457 } else { 00458 ierr = verbPrintf(4, grid.com, 00459 "PISM - WARNING: calving at certain terminal ice thickness without application\n" 00460 " of partially filled grid cell scheme may lead to non-moving\n" 00461 " ice shelf front!\n"); CHKERRQ(ierr); 00462 } 00463 } 00464 00465 // Check if the ice thickness exceeded the height of the computational box 00466 // and extend the grid if necessary: 00467 ierr = check_maximum_thickness(); CHKERRQ(ierr); 00468 00469 return 0; 00470 } 00471
1.7.3