|
PISM, A Parallel Ice Sheet Model
stable v0.5
|
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
1.7.5.1