PISM, A Parallel Ice Sheet Model  stable v0.5
src/base/iMpartgrid.cc
Go to the documentation of this file.
00001 // Copyright (C) 2011 Torsten Albrecht and 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 <petscdmda.h>
00022 
00023 #include "iceModel.hh"
00024 #include "Mask.hh"
00025 #include "PISMStressBalance.hh"
00026 #include "PISMOcean.hh"
00027 
00028 
00030 
00031 
00033 
00037 PetscErrorCode IceModel::cell_interface_velocities(bool do_part_grid,
00038                                                    int i, int j,
00039                                                    planeStar<PetscScalar> &vel) {
00040   PetscErrorCode ierr;
00041   IceModelVec2V *vel_advective;
00042   ierr = stress_balance->get_advective_2d_velocity(vel_advective); CHKERRQ(ierr);
00043 
00044   MaskQuery M(vMask);
00045   planeStar<PISMVector2> vreg = vel_advective->star(i, j);
00046 
00047   if (!do_part_grid) {
00048     // just compute (i, j) - centered "face" velocity components by average
00049     vel.e = 0.5 * (vreg.ij.u + vreg.e.u);
00050     vel.w = 0.5 * (vreg.w.u + vreg.ij.u);
00051     vel.n = 0.5 * (vreg.ij.v + vreg.n.v);
00052     vel.s = 0.5 * (vreg.s.v + vreg.ij.v);
00053     return 0;
00054   }
00055 
00056   if (M.icy(i, j) && (!M.ice_margin(i, j))) {
00057     // in the middle of ice or bedrock
00058     vel.e = 0.5 * (vreg.ij.u + vreg.e.u);
00059     vel.w = 0.5 * (vreg.w.u + vreg.ij.u);
00060     vel.n = 0.5 * (vreg.ij.v + vreg.n.v);
00061     vel.s = 0.5 * (vreg.s.v + vreg.ij.v);
00062   } else if (M.ice_margin(i, j)) {
00063     // on floating or grounded ice, but next to a ice-free grid cell 
00064     vel.e = (M.ice_free(i + 1, j) ? vreg.ij.u : 0.5 * (vreg.ij.u + vreg.e.u));
00065     vel.w = (M.ice_free(i - 1, j) ? vreg.ij.u : 0.5 * (vreg.w.u + vreg.ij.u));
00066     vel.n = (M.ice_free(i, j + 1) ? vreg.ij.v : 0.5 * (vreg.ij.v + vreg.n.v));
00067     vel.s = (M.ice_free(i, j - 1) ? vreg.ij.v : 0.5 * (vreg.s.v + vreg.ij.v));
00068   } else if (M.next_to_ice(i, j)){
00069     // on an ice-free (or partially filled) cell next to an icy grid cell
00070     vel.e = (M.icy(i + 1, j) ? vreg.e.u : 0.0);
00071     vel.w = (M.icy(i - 1, j) ? vreg.w.u : 0.0);
00072     vel.n = (M.icy(i, j + 1) ? vreg.n.v : 0.0);
00073     vel.s = (M.icy(i, j - 1) ? vreg.s.v : 0.0);
00074   } else {
00075     // on ice-free ocean or land and no ice neighbors
00076     vel.e = 0.0;
00077     vel.w = 0.0;
00078     vel.n = 0.0;
00079     vel.s = 0.0;
00080   }
00081 
00082   // specific case of the boundary of a floating ice shelf confined in a bay of ice free land
00083   if  (M.floating_ice_next_to_icefree_land(i, j)) {
00084     //avoid ice flux from the shelf onto the ice free land (better would be: ask for bed(i+1,j)>h(i,j))
00085     if (M.ice_free_land(i + 1, j)) vel.e = 0.0 ;
00086     if (M.ice_free_land(i - 1, j)) vel.w = 0.0 ;
00087     if (M.ice_free_land(i ,j + 1)) vel.n = 0.0 ;   
00088     if (M.ice_free_land(i ,j - 1)) vel.s = 0.0 ;
00089   } else if (M.ice_free_land(i, j) && M.next_to_floating_ice(i, j)) {
00090     if (M.floating_ice(i + 1, j)) vel.e = 0.0 ;
00091     if (M.floating_ice(i - 1, j)) vel.w = 0.0 ;
00092     if (M.floating_ice(i ,j + 1)) vel.n = 0.0 ;   
00093     if (M.floating_ice(i ,j - 1)) vel.s = 0.0 ;
00094   }
00095 
00096   return 0;
00097 }
00098 
00099 
00101 
00107 PetscReal IceModel::get_average_thickness(bool do_redist, planeStar<int> M, planeStar<PetscScalar> H) {
00108 
00109   // get mean ice thickness over adjacent floating ice shelf neighbors
00110   PetscReal H_average = 0.0;
00111   PetscInt N = 0;
00112   Mask m;
00113 
00114   if (m.floating_ice(M.e)) { H_average += H.e; N++; }
00115   if (m.floating_ice(M.w)) { H_average += H.w; N++; }
00116   if (m.floating_ice(M.n)) { H_average += H.n; N++; }
00117   if (m.floating_ice(M.s)) { H_average += H.s; N++; }
00118 
00119   if (N == 0) {
00120     SETERRQ(grid.com, 1, "N == 0;  call this only if a neighbor is floating!\n");
00121   }
00122 
00123   H_average = H_average / N;
00124 
00125   // reduces the guess at the front
00126   if (do_redist) {
00127     const PetscReal  mslope = 2.4511e-18*grid.dx / (300*600 / secpera);
00128     // for declining front C / Q0 according to analytical flowline profile in
00129     //   vandeveen with v0 = 300m / yr and H0 = 600m
00130     H_average -= 0.8*mslope*pow(H_average, 5);
00131   }
00132 
00133   return H_average;
00134 }
00135 
00136 
00138 
00147 PetscErrorCode IceModel::redistResiduals() {
00148   PetscErrorCode ierr;
00149   const PetscInt max_loopcount = 3;
00150   ierr = calculateRedistResiduals(); CHKERRQ(ierr); //while loop?
00151 
00152   for (int i = 0; i < max_loopcount && repeatRedist == PETSC_TRUE; ++i) {
00153     ierr = calculateRedistResiduals(); CHKERRQ(ierr); // sets repeatRedist
00154     ierr = verbPrintf(4, grid.com, "redistribution loopcount = %d\n", i); CHKERRQ(ierr);
00155   }
00156   return 0;
00157 }
00158 
00159 
00160 // This routine carries-over the ice mass when using -part_redist option, one step in the loop.
00161 PetscErrorCode IceModel::calculateRedistResiduals() {
00162   PetscErrorCode ierr;
00163   ierr = verbPrintf(4, grid.com, "######### calculateRedistResiduals() start\n"); CHKERRQ(ierr);
00164 
00165   IceModelVec2S vHnew = vWork2d[0];
00166   ierr = vH.copy_to(vHnew); CHKERRQ(ierr);
00167 
00168   IceModelVec2S vHresidualnew = vWork2d[1];
00169   ierr = vHresidual.copy_to(vHresidualnew); CHKERRQ(ierr);
00170 
00171   if (ocean == PETSC_NULL) { SETERRQ(grid.com, 1, "PISM ERROR: ocean == PETSC_NULL");  }
00172   PetscReal sea_level = 0.0; //FIXME
00173   ierr = ocean->sea_level_elevation(sea_level); CHKERRQ(ierr);
00174 
00175   PetscScalar minHRedist = 50.0; // to avoid the propagation of thin ice shelf tongues
00176 
00177   ierr = vHnew.begin_access(); CHKERRQ(ierr);
00178   ierr = vH.begin_access(); CHKERRQ(ierr);
00179   ierr = vHref.begin_access(); CHKERRQ(ierr);
00180   ierr = vbed.begin_access(); CHKERRQ(ierr);
00181   ierr = vHresidual.begin_access(); CHKERRQ(ierr);
00182   ierr = vHresidualnew.begin_access(); CHKERRQ(ierr);
00183   for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00184     for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00185       // first step: distributing residual ice masses
00186       if (vHresidual(i, j) > 0.0 && putOnTop==PETSC_FALSE) {
00187         
00188         planeStar<PetscScalar> thk = vH.star(i, j),
00189           bed = vbed.star(i, j);
00190 
00191         PetscInt N = 0; // counting empty / partially filled neighbors
00192         planeStar<bool> neighbors;
00193         neighbors.e = neighbors.w = neighbors.n = neighbors.s = false;
00194 
00195         // check for partially filled / empty grid cell neighbors (mask not updated yet, but vH is)
00196         if (thk.e == 0.0 && bed.e < sea_level) {N++; neighbors.e = true;}
00197         if (thk.w == 0.0 && bed.w < sea_level) {N++; neighbors.w = true;}
00198         if (thk.n == 0.0 && bed.n < sea_level) {N++; neighbors.n = true;}
00199         if (thk.s == 0.0 && bed.s < sea_level) {N++; neighbors.s = true;}
00200 
00201         if (N > 0)  {
00202           //remainder ice mass will be redistributed equally to all adjacent
00203           //imfrac boxes (is there a more physical way?)
00204           if (neighbors.e) vHref(i + 1, j) += vHresidual(i, j) / N;
00205           if (neighbors.w) vHref(i - 1, j) += vHresidual(i, j) / N;
00206           if (neighbors.n) vHref(i, j + 1) += vHresidual(i, j) / N;
00207           if (neighbors.s) vHref(i, j - 1) += vHresidual(i, j) / N;
00208           vHresidualnew(i, j) = 0.0;
00209         } else {
00210           vHnew(i, j) += vHresidual(i, j); // mass conservation, but thick ice at one grid cell possible
00211           vHresidualnew(i, j) = 0.0;
00212           ierr = verbPrintf(4, grid.com, 
00213                             "!!! PISM WARNING: Hresidual has %d partially filled neighbors, "
00214                             " set ice thickness to vHnew = %.2e at %d, %d \n", 
00215                             N, vHnew(i, j), i, j ); CHKERRQ(ierr);
00216         }
00217       }
00218     }
00219   }
00220   ierr = vHnew.end_access(); CHKERRQ(ierr);
00221   ierr = vH.end_access(); CHKERRQ(ierr);
00222 
00223   ierr = vHnew.beginGhostComm(vH); CHKERRQ(ierr);
00224   ierr = vHnew.endGhostComm(vH); CHKERRQ(ierr);
00225 
00226   double  ocean_rho = config.get("sea_water_density"),
00227     ice_rho = config.get("ice_density"),
00228     C = ice_rho / ocean_rho;
00229   PetscScalar     H_average;
00230   PetscScalar     Hcut = 0.0;
00231 
00232   ierr = vHnew.begin_access(); CHKERRQ(ierr);
00233   ierr = vH.begin_access(); CHKERRQ(ierr);
00234   for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00235     for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00236 
00237       // second step: if neighbors which gained redistributed ice also become
00238       // full, this needs to be redistributed in a repeated loop
00239       if (vHref(i, j) > 0.0) {
00240         H_average = 0.0;
00241         PetscInt N = 0; // number of full floating ice neighbors (mask not yet updated)
00242 
00243         planeStar<PetscScalar> thk = vH.star(i, j),
00244           bed = vbed.star(i, j);
00245 
00246         if (thk.e > 0.0 && bed.e < sea_level - C * thk.e) { N++; H_average += thk.e; }
00247         if (thk.w > 0.0 && bed.w < sea_level - C * thk.w) { N++; H_average += thk.w; }
00248         if (thk.n > 0.0 && bed.n < sea_level - C * thk.n) { N++; H_average += thk.n; }
00249         if (thk.s > 0.0 && bed.s < sea_level - C * thk.s) { N++; H_average += thk.s; }
00250 
00251         if (N > 0){
00252           H_average = H_average / N;
00253 
00254           PetscScalar coverageRatio = vHref(i, j) / H_average;
00255           if (coverageRatio > 1.0) { // partially filled grid cell is considered to be full
00256             vHresidualnew(i, j) = vHref(i, j) - H_average;
00257             Hcut += vHresidualnew(i, j); // summed up to decide, if methods needs to be run once more
00258             vHnew(i, j) += H_average; //SMB?
00259             vHref(i, j) = 0.0;
00260           }
00261         } else { // no full floating ice neighbor
00262           vHnew(i, j) += vHref(i, j); // mass conservation, but thick ice at one grid cell possible
00263           vHref(i, j) = 0.0;
00264           vHresidualnew(i, j) = 0.0;
00265               ierr = verbPrintf(4, grid.com, 
00266                             "!!! PISM WARNING: Hresidual=%.2f with %d partially filled neighbors, "
00267                             " set ice thickness to vHnew = %.2f at %d, %d \n", 
00268                             vHresidual(i, j), N , vHnew(i, j), i, j ); CHKERRQ(ierr);
00269         }
00270       }
00271     }
00272   }
00273   ierr = vH.end_access(); CHKERRQ(ierr);
00274   ierr = vHnew.end_access(); CHKERRQ(ierr);
00275   ierr = vHref.end_access(); CHKERRQ(ierr);
00276   ierr = vbed.end_access(); CHKERRQ(ierr);
00277   ierr = vHresidual.end_access(); CHKERRQ(ierr);
00278   ierr = vHresidualnew.end_access(); CHKERRQ(ierr);
00279   
00280   PetscScalar gHcut; //check, if redistribution should be run once more
00281   ierr = PISMGlobalSum(&Hcut, &gHcut, grid.com); CHKERRQ(ierr);
00282   putOnTop = PETSC_FALSE;
00283   if (gHcut > 0.0) {
00284     repeatRedist = PETSC_TRUE;
00285     // avoid repetition for the redistribution of very thin vHresiduals
00286     if (gHcut < minHRedist) { putOnTop = PETSC_TRUE; }
00287   } else {
00288     repeatRedist = PETSC_FALSE;
00289   }
00290 
00291   // finally copy vHnew into vH and communicate ghosted values
00292   ierr = vHnew.beginGhostComm(vH); CHKERRQ(ierr);
00293   ierr = vHnew.endGhostComm(vH); CHKERRQ(ierr);
00294 
00295   ierr = vHresidualnew.beginGhostComm(vHresidual); CHKERRQ(ierr);
00296   ierr = vHresidualnew.endGhostComm(vHresidual); CHKERRQ(ierr);
00297 
00298   return 0;
00299 }
00300 
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines