PISM, A Parallel Ice Sheet Model  stable v0.5
src/base/iMicebergs.cc
Go to the documentation of this file.
00001 // Copyright (C) 2004--2011 Torsten Albrecht 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 <petscdmda.h>
00021 
00022 #include "iceModel.hh"
00023 #include "Mask.hh"
00024 #include "PISMOcean.hh"
00025 
00027 
00028 
00031 
00053 PetscErrorCode IceModel::killIceBergs() {
00054   PetscErrorCode ierr;
00055 
00056   ierr = findIceBergCandidates(); CHKERRQ(ierr);
00057   ierr = identifyNotAnIceBerg(); CHKERRQ(ierr);
00058   ierr = killIdentifiedIceBergs(); CHKERRQ(ierr);
00059   ierr = killEasyIceBergs(); CHKERRQ(ierr);
00060   return 0;
00061 }
00062 
00063 
00069 PetscErrorCode IceModel::findIceBergCandidates() {
00070   PetscErrorCode ierr;
00071   ierr = verbPrintf(4, grid.com, "######### findIceBergCandidates() start\n"); CHKERRQ(ierr);
00072 
00073   const PetscInt Mx = grid.Mx, My = grid.My;
00074 
00075   PetscReal sea_level;
00076   if (ocean != NULL) {
00077     ierr = ocean->sea_level_elevation(sea_level); CHKERRQ(ierr);
00078   } else { SETERRQ(grid.com, 2, "PISM ERROR: ocean == NULL"); }
00079 
00080   double ocean_rho = config.get("sea_water_density"),
00081     ice_rho = config.get("ice_density");
00082 
00083   ierr = vH.begin_access(); CHKERRQ(ierr);
00084   ierr = vMask.begin_access(); CHKERRQ(ierr);
00085   ierr = vIcebergMask.begin_access(); CHKERRQ(ierr);
00086   ierr = vbed.begin_access(); CHKERRQ(ierr);
00087   for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00088     for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00089 
00090       const PetscScalar hgrounded = vbed(i, j) + vH(i, j),
00091         hfloating = sea_level + (1.0 - ice_rho / ocean_rho) * vH(i, j);
00092 
00093       //cut of border of computational domain
00094       if (hgrounded < hfloating && (i <= 0 || i >= Mx - 1 || j <= 0 || j >= My - 1)) {
00095         vH(i, j) = 0.0;
00096         vIcebergMask(i, j) = ICEBERGMASK_STOP_OCEAN;
00097         vMask(i, j) = MASK_ICE_FREE_OCEAN;
00098       } else {
00099         vIcebergMask(i, j) = ICEBERGMASK_NOT_SET;
00100       }
00101     }
00102   }
00103   ierr = vH.end_access(); CHKERRQ(ierr);
00104   ierr = vMask.end_access(); CHKERRQ(ierr);
00105   ierr = vIcebergMask.end_access(); CHKERRQ(ierr);
00106   ierr = vbed.end_access(); CHKERRQ(ierr);
00107 
00108   ierr = vMask.beginGhostComm(); CHKERRQ(ierr);
00109   ierr = vMask.endGhostComm(); CHKERRQ(ierr);
00110 
00111   ierr = vIcebergMask.beginGhostComm(); CHKERRQ(ierr);
00112   ierr = vIcebergMask.endGhostComm(); CHKERRQ(ierr);
00113 
00114   // set all floating points to ICEBERGMASK_ICEBERG_CAND
00115   MaskQuery M(vMask);
00116   ierr = vMask.begin_access(); CHKERRQ(ierr);
00117   ierr = vIcebergMask.begin_access(); CHKERRQ(ierr);
00118   for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00119     for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00120       if (vIcebergMask(i, j) == ICEBERGMASK_NOT_SET) {
00121         if (M.floating_ice(i, j)) {
00122           vIcebergMask(i, j) = ICEBERGMASK_ICEBERG_CAND;
00123         }
00124       }
00125     }
00126   }
00127   ierr = vIcebergMask.end_access(); CHKERRQ(ierr);
00128 
00129   ierr = vIcebergMask.beginGhostComm(); CHKERRQ(ierr);
00130   ierr = vIcebergMask.endGhostComm(); CHKERRQ(ierr);
00131 
00132   // set borders of shelves/icebergs to ICEBERGMASK_STOP_ATTACHED or ICEBERGMASK_STOP_OCEAN respectively.
00133   ierr = vIcebergMask.begin_access(); CHKERRQ(ierr);
00134   for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00135     for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00136 
00137       if (vIcebergMask(i, j) == ICEBERGMASK_NOT_SET) {
00138 
00139         planeStar<int> mask = vIcebergMask.int_star(i, j);
00140 
00141         bool neighbor_is_candidate = ( mask.e == ICEBERGMASK_ICEBERG_CAND ||
00142                                        mask.w == ICEBERGMASK_ICEBERG_CAND ||
00143                                        mask.n == ICEBERGMASK_ICEBERG_CAND ||
00144                                        mask.s == ICEBERGMASK_ICEBERG_CAND ||
00145                                        // checks below should not be needed
00146                                        vIcebergMask(i + 1, j + 1) == ICEBERGMASK_ICEBERG_CAND ||
00147                                        vIcebergMask(i + 1, j - 1) == ICEBERGMASK_ICEBERG_CAND ||
00148                                        vIcebergMask(i - 1, j + 1) == ICEBERGMASK_ICEBERG_CAND ||
00149                                        vIcebergMask(i - 1, j - 1) == ICEBERGMASK_ICEBERG_CAND);
00150 
00151         if (M.grounded(i, j) && neighbor_is_candidate)
00152           vIcebergMask(i, j) = ICEBERGMASK_STOP_ATTACHED;
00153         else if (M.ice_free_ocean(i, j) && neighbor_is_candidate)
00154           vIcebergMask(i, j) = ICEBERGMASK_STOP_OCEAN;
00155       }
00156     }
00157   }
00158   ierr = vMask.end_access(); CHKERRQ(ierr);
00159   ierr = vIcebergMask.end_access(); CHKERRQ(ierr);
00160 
00161   ierr = vIcebergMask.beginGhostComm(); CHKERRQ(ierr);
00162   ierr = vIcebergMask.endGhostComm(); CHKERRQ(ierr);
00163   return 0;
00164 }
00165 
00166 
00167 PetscErrorCode IceModel::identifyNotAnIceBerg() {
00168   PetscErrorCode ierr;
00169 
00170   ierr = verbPrintf(4, grid.com, "######### identifyNotAnIceBerg() start\n"); CHKERRQ(ierr);
00171 
00172   // this communication of ghost values is done here to make sure that asking
00173   // about neighbouring values in this routine doesn't lead to inconsistencies
00174   // in parallel computation, if the neighbour belongs to another processor
00175   // domain.
00176   // FIXME: this is probably redundant
00177   ierr = vIcebergMask.beginGhostComm(); CHKERRQ(ierr);
00178   ierr = vIcebergMask.endGhostComm(); CHKERRQ(ierr);
00179 
00180   bool done = false;
00181   PetscInt loopcount = 0;
00182   while(! done){
00183 
00184     done = true;
00185 
00186     ierr = vIcebergMask.begin_access(); CHKERRQ(ierr);
00187     for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00188       for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00189 
00190         planeStar<int> mask = vIcebergMask.int_star(i, j);
00191 
00192         bool attached_to_grounded = (mask.e == ICEBERGMASK_STOP_ATTACHED ||
00193                                      mask.w == ICEBERGMASK_STOP_ATTACHED ||
00194                                      mask.n == ICEBERGMASK_STOP_ATTACHED ||
00195                                      mask.s == ICEBERGMASK_STOP_ATTACHED),
00196 
00197           attached_to_no_iceberg = (mask.e == ICEBERGMASK_NO_ICEBERG ||
00198                                     mask.w == ICEBERGMASK_NO_ICEBERG ||
00199                                     mask.n == ICEBERGMASK_NO_ICEBERG ||
00200                                     mask.s == ICEBERGMASK_NO_ICEBERG);
00201 
00202         if (vIcebergMask(i, j) == ICEBERGMASK_ICEBERG_CAND &&
00203             (attached_to_grounded || attached_to_no_iceberg)) {
00204 
00205           vIcebergMask(i, j) = ICEBERGMASK_NO_ICEBERG;
00206           done = false;
00207         }
00208 
00209       }
00210     }
00211     ierr = vIcebergMask.end_access(); CHKERRQ(ierr);
00212 
00213     ierr = vIcebergMask.beginGhostComm(); CHKERRQ(ierr);
00214     ierr = vIcebergMask.endGhostComm(); CHKERRQ(ierr);
00215 
00216     // We're "done" only if the iceberg mask stopped changing on *all*
00217     // processor sub-domains.
00218     int flag = done;
00219     MPI_Allreduce(MPI_IN_PLACE, &flag, 1, MPI_INT, MPI_LAND, grid.com);
00220     done = flag;
00221 
00222     loopcount += 1;
00223   }
00224 
00225   ierr = verbPrintf(3, grid.com,
00226     "PISM-PIK INFO:  %d loop(s) were needed to identify whether there are icebergs \n",
00227     loopcount); CHKERRQ(ierr);
00228 
00229   return 0;
00230 }
00231 
00232 
00239 PetscErrorCode IceModel::killIdentifiedIceBergs() {
00240   PetscErrorCode ierr;
00241   ierr = verbPrintf(4, grid.com, "######### killIdentifiedIceBergs() start\n"); CHKERRQ(ierr);
00242   const bool vpik = config.get_flag("verbose_pik_messages");
00243   
00244   PetscScalar
00245     my_discharge_flux = 0,
00246     discharge_flux = 0; 
00247   const PetscScalar dx = grid.dx, dy = grid.dy;
00248 
00249   ierr = vMask.begin_access(); CHKERRQ(ierr);
00250   ierr = vIcebergMask.begin_access(); CHKERRQ(ierr);
00251   ierr = vH.begin_access(); CHKERRQ(ierr);
00252   ierr = vh.begin_access(); CHKERRQ(ierr);
00253   for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00254     for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00255 
00256       if (vIcebergMask(i, j) == ICEBERGMASK_ICEBERG_CAND) {
00257          // it is not a candidate any more, it is an iceberg!
00258          my_discharge_flux -= vH(i, j);
00259          vH(i, j) = 0.0;
00260          vh(i, j) = 0.0;
00261          vMask(i, j) = MASK_ICE_FREE_OCEAN;
00262          if (vpik) {
00263            PetscSynchronizedPrintf(grid.com, 
00264                      "PISM-PIK INFO: [rank %d] killed iceberg at i=%d, j=%d\n", 
00265                      grid.rank, i, j);
00266          }
00267       }
00268 
00269     }
00270   }
00271 
00272   ierr = vMask.end_access(); CHKERRQ(ierr);
00273   ierr = vIcebergMask.end_access(); CHKERRQ(ierr);
00274   ierr = vH.end_access(); CHKERRQ(ierr);
00275   ierr = vh.end_access(); CHKERRQ(ierr);
00276   
00277   ierr = PISMGlobalSum(&my_discharge_flux,     &discharge_flux,     grid.com); CHKERRQ(ierr);
00278   PetscScalar factor = config.get("ice_density") * (dx * dy);
00279   cumulative_discharge_flux     += discharge_flux     * factor;
00280 
00281   ierr = vMask.beginGhostComm(); CHKERRQ(ierr);
00282   ierr = vMask.endGhostComm(); CHKERRQ(ierr);
00283 
00284   ierr = vH.beginGhostComm(); CHKERRQ(ierr);
00285   ierr = vH.endGhostComm(); CHKERRQ(ierr);
00286 
00287   ierr = vh.beginGhostComm(); CHKERRQ(ierr);
00288   ierr = vh.endGhostComm(); CHKERRQ(ierr);
00289 
00290   return 0;
00291 }
00292 
00293 
00299 PetscErrorCode IceModel::killEasyIceBergs() {
00300   PetscErrorCode ierr;
00301   ierr = verbPrintf(4, grid.com, "######### killEasyIceBergs() start\n"); CHKERRQ(ierr);
00302   const bool vpik = config.get_flag("verbose_pik_messages");
00303   
00304   PetscScalar
00305     my_discharge_flux = 0,
00306     discharge_flux = 0;
00307   const PetscScalar dx = grid.dx, dy = grid.dy;
00308 
00309   IceModelVec2S vHnew = vWork2d[0];
00310   ierr = vH.copy_to(vHnew); CHKERRQ(ierr);
00311 
00312   PetscReal sea_level;
00313   if (ocean != NULL) {
00314     ierr = ocean->sea_level_elevation(sea_level); CHKERRQ(ierr);
00315   } else { SETERRQ(grid.com, 2, "PISM ERROR: ocean == NULL"); }
00316 
00317   double ocean_rho = config.get("sea_water_density"),
00318     ice_rho = config.get("ice_density");
00319 
00320   // looking for grid-cell wide floating ice noses that have at least six neighbors
00321   // of thickness H=0 like this (o ocean, fl and x floating):
00322   //
00323   // o  o  o        o o o        o  o  o
00324   // fl x fl   OR   o x o   OR   o  x fl
00325   // o  o  o        o o o        o  o  o
00326 
00327   PetscReal C = (1.0 - ice_rho / ocean_rho);
00328 
00329   ierr = vHnew.begin_access(); CHKERRQ(ierr);
00330   ierr = vH.begin_access(); CHKERRQ(ierr);
00331   ierr = vMask.begin_access(); CHKERRQ(ierr);
00332   ierr = vh.begin_access(); CHKERRQ(ierr);
00333   ierr = vbed.begin_access(); CHKERRQ(ierr);
00334   for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00335     for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00336 
00337       planeStar<PetscScalar> thk = vH.star(i, j),
00338         bed = vbed.star(i, j);
00339 
00340       // instead of updating surface elevation, counting here floating or icefree neighbors
00341       const PetscScalar hgrounded = bed.ij + thk.ij,
00342         hfloating = sea_level + (1.0 - ice_rho / ocean_rho) * thk.ij;
00343 
00344       if (vH(i, j) > 0.0 && hgrounded < hfloating) { //is floating ice shelf
00345 
00346         const PetscScalar
00347           hgrounded_eb = bed.e + thk.e,
00348           hfloating_eb = sea_level + C * thk.e,
00349           hgrounded_wb = bed.w + thk.w,
00350           hfloating_wb = sea_level + C * thk.w,
00351           hgrounded_nb = bed.n + thk.n,
00352           hfloating_nb = sea_level + C * thk.n,
00353           hgrounded_sb = bed.s + thk.s,
00354           hfloating_sb = sea_level + C * thk.s;
00355 
00356         PetscInt jcount = 0, icount = 0; // grid-cell wide floating ice nose
00357 
00358         if (vH(i + 1, j + 1) == 0.0) {jcount += 1; icount += 1;}
00359         if (vH(i + 1, j - 1) == 0.0) {jcount += 1; icount += 1;}
00360         if (vH(i - 1, j + 1) == 0.0) {jcount += 1; icount += 1;}
00361         if (vH(i - 1, j - 1) == 0.0) {jcount += 1; icount += 1;}
00362 
00363         if (thk.e == 0.0) jcount += 1;
00364         if (thk.w == 0.0) jcount += 1;
00365         if (thk.n == 0.0) icount += 1;
00366         if (thk.s == 0.0) icount += 1;
00367 
00368         if ((icount == 6 && hgrounded_eb < hfloating_eb && hgrounded_wb < hfloating_wb) ||
00369             (jcount == 6 && hgrounded_nb < hfloating_nb && hgrounded_sb < hfloating_sb)) {
00370 
00371           my_discharge_flux -= vHnew(i, j);
00372           vHnew(i, j) = 0.0;
00373           vh(i, j) = 0.0;
00374           vMask(i, j) = MASK_ICE_FREE_OCEAN;
00375           if (vpik) {
00376             PetscSynchronizedPrintf(grid.com, 
00377               "PISM-PIK INFO: [rank %d] cut off nose or one-box-iceberg at i=%d, j=%d\n",
00378               grid.rank, i, j);
00379           }
00380         }
00381       }
00382     }
00383   }
00384   ierr = vH.end_access(); CHKERRQ(ierr);
00385   ierr = vHnew.end_access(); CHKERRQ(ierr);
00386 
00387   // finally copy vHnew into vH and communicate ghosted values
00388   ierr = vHnew.beginGhostComm(vH); CHKERRQ(ierr);
00389   ierr = vHnew.endGhostComm(vH); CHKERRQ(ierr);
00390 
00391   ierr = vH.copy_to(vHnew); CHKERRQ(ierr);
00392 
00393   // looking for one-grid-cell icebergs, that have 4 neighbors of thickness H=0
00394   ierr = vH.begin_access(); CHKERRQ(ierr);
00395   ierr = vHnew.begin_access(); CHKERRQ(ierr);
00396   for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00397     for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00398 
00399       planeStar<PetscScalar> thk = vH.star(i, j);
00400 
00401       // instead of updating surface elevation, counting here floating or icefree neighbors
00402       const PetscScalar hgrounded = vbed(i, j) + thk.ij,
00403         hfloating = sea_level + C * thk.ij;
00404 
00405       bool all_4neighbors_icefree = (thk.e == 0.0 && thk.w == 0.0 &&
00406                                      thk.n == 0.0 && thk.s == 0.0);
00407 
00408       if (thk.ij > 0.0 && hgrounded < hfloating && all_4neighbors_icefree) {
00409         my_discharge_flux -= vHnew(i, j);
00410         vHnew(i, j) = 0.0;
00411         vh(i, j) = 0.0;
00412         vMask(i, j) = MASK_ICE_FREE_OCEAN;
00413         if (vpik) {
00414           PetscSynchronizedPrintf(grid.com,
00415             "PISM-PIK INFO: [rank %d] killed isolated one-box-iceberg at i=%d, j=%d\n",
00416             grid.rank, i, j);
00417         }
00418       }
00419     }
00420   }
00421 
00422   ierr = vH.end_access(); CHKERRQ(ierr);
00423   ierr = vHnew.end_access(); CHKERRQ(ierr);
00424 
00425   ierr = vHnew.beginGhostComm(vH); CHKERRQ(ierr);
00426   ierr = vHnew.endGhostComm(vH); CHKERRQ(ierr);
00427 
00428   ierr = vH.copy_to(vHnew); CHKERRQ(ierr);
00429 
00430   // looking for one-grid-cell partially filled grid cells, that have 4 neighbors of thickness H=0
00431   ierr = vH.begin_access(); CHKERRQ(ierr);
00432   ierr = vHnew.begin_access(); CHKERRQ(ierr);
00433   ierr = vHref.begin_access(); CHKERRQ(ierr);
00434   for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00435     for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00436 
00437       // instead of updating surface elevation, counting here floating or icefree neighbors
00438       bool all_4neighbors_icefree = (vH(i + 1, j) == 0.0 &&
00439                                      vH(i - 1, j) == 0.0 &&
00440                                      vH(i, j + 1) == 0.0 &&
00441                                      vH(i, j - 1) == 0.0);
00442       if (vHref(i, j) > 0.0 && all_4neighbors_icefree) {
00443         my_discharge_flux -= vHref(i, j);
00444         vHref(i, j) = 0.0;
00445         if (vpik) {
00446           PetscSynchronizedPrintf(grid.com, 
00447             "PISM-PIK INFO: [rank %d] killed lonely partially filled grid cell at i = %d, j = %d\n",
00448             grid.rank, i, j);
00449         }
00450       }
00451     }
00452   }
00453   ierr = vbed.end_access(); CHKERRQ(ierr);
00454   ierr = vMask.end_access(); CHKERRQ(ierr);
00455   ierr = vh.end_access(); CHKERRQ(ierr);
00456   ierr = vHref.end_access(); CHKERRQ(ierr);
00457   ierr = vH.end_access(); CHKERRQ(ierr);
00458   ierr = vHnew.end_access(); CHKERRQ(ierr);
00459   
00460   ierr = PISMGlobalSum(&my_discharge_flux,     &discharge_flux,     grid.com); CHKERRQ(ierr);
00461   PetscScalar factor = config.get("ice_density") * (dx * dy);
00462   cumulative_discharge_flux     += discharge_flux     * factor;
00463 
00464   if (vpik)  // actually get output from PetscSynchronizedPrintf()
00465     PetscSynchronizedFlush(grid.com);
00466 
00467   ierr = vHnew.beginGhostComm(vH); CHKERRQ(ierr);
00468   ierr = vHnew.endGhostComm(vH); CHKERRQ(ierr);
00469 
00470   ierr = vMask.beginGhostComm(); CHKERRQ(ierr);
00471   ierr = vMask.endGhostComm(); CHKERRQ(ierr);
00472 
00473   ierr = vh.beginGhostComm(); CHKERRQ(ierr);
00474   ierr = vh.endGhostComm(); CHKERRQ(ierr);
00475 
00476   ierr = vHref.beginGhostComm(); CHKERRQ(ierr);
00477   ierr = vHref.endGhostComm(); CHKERRQ(ierr);
00478 
00479   return 0;
00480 }
00481 
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines