PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/iMgeometry.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 <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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines