|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 // Copyright (C) 2004--2011 Jed Brown, Craig Lingle, 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 "SIAFD.hh" 00020 #include "Mask.hh" 00021 00023 PetscErrorCode SIAFD::allocate() { 00024 PetscErrorCode ierr; 00025 00026 // 2D temporary storage: 00027 for (int i = 0; i < 2; ++i) { 00028 char namestr[30]; 00029 00030 ierr = work_2d[i].create(grid, "work_vector", true, WIDE_STENCIL); CHKERRQ(ierr); 00031 ierr = work_2d_stag[i].create(grid, "work_vector", true); CHKERRQ(ierr); 00032 00033 snprintf(namestr, sizeof(namestr), "work_vector_2d_%d", i); 00034 ierr = work_2d[i].set_name(namestr); CHKERRQ(ierr); 00035 00036 snprintf(namestr, sizeof(namestr), "work_vector_2d_stag_%d", i); 00037 ierr = work_2d_stag[i].set_name(namestr); CHKERRQ(ierr); 00038 } 00039 00040 ierr = delta[0].create(grid, "delta_0", true); CHKERRQ(ierr); 00041 ierr = delta[1].create(grid, "delta_1", true); CHKERRQ(ierr); 00042 00043 // 3D temporary storage: 00044 ierr = work_3d[0].create(grid, "work_3d_0", true); CHKERRQ(ierr); 00045 ierr = work_3d[1].create(grid, "work_3d_1", true); CHKERRQ(ierr); 00046 00047 // bed smoother 00048 bed_smoother = new PISMBedSmoother(grid, config, WIDE_STENCIL); 00049 00050 return 0; 00051 } 00052 00054 PetscErrorCode SIAFD::init(PISMVars &vars) { 00055 PetscErrorCode ierr; 00056 00057 ierr = SSB_Modifier::init(vars); CHKERRQ(ierr); 00058 00059 ierr = verbPrintf(2, grid.com, 00060 "* Initializing the SIA stress balance modifier...\n"); CHKERRQ(ierr); 00061 00062 mask = dynamic_cast<IceModelVec2Int*>(vars.get("mask")); 00063 if (mask == NULL) SETERRQ(1, "mask is not available"); 00064 00065 thickness = dynamic_cast<IceModelVec2S*>(vars.get("land_ice_thickness")); 00066 if (thickness == NULL) SETERRQ(1, "land_ice_thickness is not available"); 00067 00068 surface = dynamic_cast<IceModelVec2S*>(vars.get("surface_altitude")); 00069 if (surface == NULL) SETERRQ(1, "surface_altitude is not available"); 00070 00071 bed = dynamic_cast<IceModelVec2S*>(vars.get("bedrock_altitude")); 00072 if (bed == NULL) SETERRQ(1, "bedrock_altitude is not available"); 00073 00074 enthalpy = dynamic_cast<IceModelVec3*>(vars.get("enthalpy")); 00075 if (enthalpy == NULL) SETERRQ(1, "enthalpy is not available"); 00076 00077 if (config.get_flag("do_age")) { 00078 age = dynamic_cast<IceModelVec3*>(vars.get("age")); 00079 if (age == NULL) SETERRQ(1, "age is not available"); 00080 } else { 00081 age = NULL; 00082 } 00083 00084 event_sia = grid.profiler->create("siafd_update", "time spent inside SIAFD update"); 00085 00086 // set bed_state_counter to -1 so that the smoothed bed is computed the first 00087 // time update() is called. 00088 bed_state_counter = -1; 00089 return 0; 00090 } 00091 00094 PetscErrorCode SIAFD::update(IceModelVec2V *vel_input, IceModelVec2S *D2_input, 00095 bool fast) { 00096 PetscErrorCode ierr; 00097 IceModelVec2Stag h_x = work_2d_stag[0], h_y = work_2d_stag[1]; 00098 00099 grid.profiler->begin(event_sia); 00100 00101 // Check if the smoothed bed computed by PISMBedSmoother is out of date and 00102 // recompute if necessary. 00103 if (bed->get_state_counter() > bed_state_counter) { 00104 ierr = bed_smoother->preprocess_bed(*bed, 00105 config.get("Glen_exponent"), 00106 config.get("bed_smoother_range")); 00107 CHKERRQ(ierr); 00108 bed_state_counter = bed->get_state_counter(); 00109 } 00110 00111 ierr = compute_surface_gradient(h_x, h_y); CHKERRQ(ierr); 00112 00113 ierr = compute_diffusive_flux(h_x, h_y, diffusive_flux, fast); CHKERRQ(ierr); 00114 00115 if (!fast) { 00116 ierr = compute_sigma(D2_input, h_x, h_y); CHKERRQ(ierr); 00117 00118 ierr = compute_3d_horizontal_velocity(h_x, h_y, vel_input, u, v); CHKERRQ(ierr); 00119 } 00120 00121 grid.profiler->end(event_sia); 00122 00123 return 0; 00124 } 00125 00126 00128 00163 PetscErrorCode SIAFD::compute_surface_gradient(IceModelVec2Stag &h_x, IceModelVec2Stag &h_y) { 00164 PetscErrorCode ierr; 00165 00166 const string method = config.get_string("surface_gradient_method"); 00167 00168 if ((method != "eta") && (method != "mahaffy") && (method != "haseloff")) { 00169 verbPrintf(1, grid.com, 00170 "PISM ERROR: value of surface_gradient_method, option -gradient, not valid ... ending\n"); 00171 PISMEnd(); 00172 } 00173 00174 if (method == "eta") { 00175 00176 ierr = surface_gradient_eta(h_x, h_y); CHKERRQ(ierr); 00177 00178 } else if (method == "haseloff") { 00179 00180 ierr = surface_gradient_haseloff(h_x, h_y); CHKERRQ(ierr); 00181 00182 } else if (method == "mahaffy") { 00183 00184 ierr = surface_gradient_mahaffy(h_x, h_y); CHKERRQ(ierr); 00185 00186 } else { 00187 SETERRQ(1, "can't happen"); 00188 } 00189 00190 return 0; 00191 } 00192 00194 PetscErrorCode SIAFD::surface_gradient_eta(IceModelVec2Stag &h_x, IceModelVec2Stag &h_y) { 00195 PetscErrorCode ierr; 00196 00197 const PetscScalar n = ice.exponent(), // presumably 3.0 00198 etapow = (2.0 * n + 2.0)/n, // = 8/3 if n = 3 00199 invpow = 1.0 / etapow, 00200 dinvpow = (- n - 2.0) / (2.0 * n + 2.0); 00201 const PetscScalar dx = grid.dx, dy = grid.dy; // convenience 00202 IceModelVec2S eta = work_2d[0]; 00203 00204 // compute eta = H^{8/3}, which is more regular, on reg grid 00205 ierr = thickness->begin_access(); CHKERRQ(ierr); 00206 ierr = eta.begin_access(); CHKERRQ(ierr); 00207 PetscInt GHOSTS = 2; 00208 for (PetscInt i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) { 00209 for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) { 00210 eta(i,j) = pow((*thickness)(i,j), etapow); 00211 } 00212 } 00213 ierr = eta.end_access(); CHKERRQ(ierr); 00214 ierr = thickness->end_access(); CHKERRQ(ierr); 00215 00216 ierr = h_x.begin_access(); CHKERRQ(ierr); 00217 ierr = h_y.begin_access(); CHKERRQ(ierr); 00218 00219 // now use Mahaffy on eta to get grad h on staggered; 00220 // note grad h = (3/8) eta^{-5/8} grad eta + grad b because h = H + b 00221 ierr = bed->begin_access(); CHKERRQ(ierr); 00222 ierr = eta.begin_access(); CHKERRQ(ierr); 00223 for (PetscInt o=0; o<2; o++) { 00224 00225 GHOSTS = 1; 00226 for (PetscInt i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) { 00227 for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) { 00228 if (o==0) { // If I-offset 00229 const PetscScalar mean_eta = 0.5 * (eta(i+1,j) + eta(i,j)); 00230 if (mean_eta > 0.0) { 00231 const PetscScalar factor = invpow * pow(mean_eta, dinvpow); 00232 h_x(i,j,o) = factor * (eta(i+1,j) - eta(i,j)) / dx; 00233 h_y(i,j,o) = factor * (+ eta(i+1,j+1) + eta(i,j+1) 00234 - eta(i+1,j-1) - eta(i,j-1)) / (4.0*dy); 00235 } else { 00236 h_x(i,j,o) = 0.0; 00237 h_y(i,j,o) = 0.0; 00238 } 00239 // now add bed slope to get actual h_x,h_y 00240 h_x(i,j,o) += bed->diff_x_stagE(i,j); 00241 h_y(i,j,o) += bed->diff_y_stagE(i,j); 00242 } else { // J-offset 00243 const PetscScalar mean_eta = 0.5 * (eta(i,j+1) + eta(i,j)); 00244 if (mean_eta > 0.0) { 00245 const PetscScalar factor = invpow * pow(mean_eta, dinvpow); 00246 h_y(i,j,o) = factor * (eta(i,j+1) - eta(i,j)) / dy; 00247 h_x(i,j,o) = factor * (+ eta(i+1,j+1) + eta(i+1,j) 00248 - eta(i-1,j+1) - eta(i-1,j)) / (4.0*dx); 00249 } else { 00250 h_y(i,j,o) = 0.0; 00251 h_x(i,j,o) = 0.0; 00252 } 00253 // now add bed slope to get actual h_x,h_y 00254 h_y(i,j,o) += bed->diff_y_stagN(i,j); 00255 h_x(i,j,o) += bed->diff_x_stagN(i,j); 00256 } 00257 } 00258 } 00259 } 00260 ierr = eta.end_access(); CHKERRQ(ierr); 00261 ierr = bed->end_access(); CHKERRQ(ierr); 00262 00263 ierr = h_y.end_access(); CHKERRQ(ierr); 00264 ierr = h_x.end_access(); CHKERRQ(ierr); 00265 00266 return 0; 00267 } 00268 00270 00274 PetscErrorCode SIAFD::surface_gradient_haseloff(IceModelVec2Stag &h_x, IceModelVec2Stag &h_y) { 00275 PetscErrorCode ierr; 00276 00277 const PetscScalar Hicefree = 0.0; // standard for ice-free, in Haseloff 00278 const PetscScalar dx = grid.dx, dy = grid.dy; // convenience 00279 00280 ierr = h_x.begin_access(); CHKERRQ(ierr); 00281 ierr = h_y.begin_access(); CHKERRQ(ierr); 00282 00283 PetscScalar **h, **b, **H; 00284 ierr = bed->get_array(b); CHKERRQ(ierr); 00285 ierr = thickness->get_array(H); CHKERRQ(ierr); 00286 ierr = surface->get_array(h); CHKERRQ(ierr); 00287 for (PetscInt o=0; o<2; o++) { 00288 00289 PetscInt GHOSTS = 1; 00290 for (PetscInt i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) { 00291 for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) { 00292 if (o==0) { // If I-offset 00293 const bool icefreeP = (H[i][j] <= Hicefree), 00294 icefreeE = (H[i+1][j] <= Hicefree), 00295 icefreeN = (H[i][j+1] <= Hicefree), 00296 icefreeS = (H[i][j-1] <= Hicefree), 00297 icefreeNE = (H[i+1][j+1] <= Hicefree), 00298 icefreeSE = (H[i+1][j-1] <= Hicefree); 00299 00300 PetscScalar hhE = h[i+1][j]; // east pseudo-surface elevation 00301 if (icefreeE && (b[i+1][j] > h[i][j] )) hhE = h[i][j]; 00302 if (icefreeP && (b[i][j] > h[i+1][j] )) hhE = h[i][j]; 00303 h_x(i,j,o) = (hhE - h[i][j]) / dx; 00304 00305 PetscScalar hhN = h[i][j+1]; // north pseudo-surface elevation 00306 if (icefreeN && (b[i][j+1] > h[i][j] )) hhN = h[i][j]; 00307 if (icefreeP && (b[i][j] > h[i][j+1] )) hhN = h[i][j]; 00308 PetscScalar hhS = h[i][j-1]; // south pseudo-surface elevation 00309 if (icefreeS && (b[i][j-1] > h[i][j] )) hhS = h[i][j]; 00310 if (icefreeP && (b[i][j] > h[i][j-1] )) hhS = h[i][j]; 00311 PetscScalar hhNE = h[i+1][j+1];// northeast pseudo-surface elevation 00312 if (icefreeNE && (b[i+1][j+1] > h[i+1][j] )) hhNE = h[i+1][j]; 00313 if (icefreeE && (b[i+1][j] > h[i+1][j+1])) hhNE = h[i+1][j]; 00314 PetscScalar hhSE = h[i+1][j-1];// southeast pseudo-surface elevation 00315 if (icefreeSE && (b[i+1][j-1] > h[i+1][j] )) hhSE = h[i+1][j]; 00316 if (icefreeE && (b[i+1][j] > h[i+1][j-1])) hhSE = h[i+1][j]; 00317 h_y(i,j,o) = (hhNE + hhN - hhSE - hhS) / (4.0 * dy); 00318 } else { // J-offset 00319 const bool icefreeP = (H[i][j] <= Hicefree), 00320 icefreeN = (H[i][j+1] <= Hicefree), 00321 icefreeE = (H[i+1][j] <= Hicefree), 00322 icefreeW = (H[i-1][j] <= Hicefree), 00323 icefreeNE = (H[i+1][j+1] <= Hicefree), 00324 icefreeNW = (H[i-1][j+1] <= Hicefree); 00325 00326 PetscScalar hhN = h[i][j+1]; // north pseudo-surface elevation 00327 if (icefreeN && (b[i][j+1] > h[i][j] )) hhN = h[i][j]; 00328 if (icefreeP && (b[i][j] > h[i][j+1] )) hhN = h[i][j]; 00329 h_y(i,j,o) = (hhN - h[i][j]) / dy; 00330 00331 PetscScalar hhE = h[i+1][j]; // east pseudo-surface elevation 00332 if (icefreeE && (b[i+1][j] > h[i][j] )) hhE = h[i][j]; 00333 if (icefreeP && (b[i][j] > h[i+1][j] )) hhE = h[i][j]; 00334 PetscScalar hhW = h[i-1][j]; // west pseudo-surface elevation 00335 if (icefreeW && (b[i-1][j] > h[i][j] )) hhW = h[i][j]; 00336 if (icefreeP && (b[i][j] > h[i-1][j] )) hhW = h[i][j]; 00337 PetscScalar hhNE = h[i+1][j+1];// northeast pseudo-surface elevation 00338 if (icefreeNE && (b[i+1][j+1] > h[i][j+1] )) hhNE = h[i][j+1]; 00339 if (icefreeN && (b[i][j+1] > h[i+1][j+1])) hhNE = h[i][j+1]; 00340 PetscScalar hhNW = h[i-1][j+1];// northwest pseudo-surface elevation 00341 if (icefreeNW && (b[i-1][j+1] > h[i][j+1] )) hhNW = h[i][j+1]; 00342 if (icefreeN && (b[i][j+1] > h[i-1][j+1])) hhNW = h[i][j+1]; 00343 h_x(i,j,o) = (hhNE + hhE - hhNW - hhW) / (4.0 * dx); 00344 } 00345 00346 } // j 00347 } // i 00348 } // o 00349 ierr = thickness->end_access(); CHKERRQ(ierr); 00350 ierr = bed->end_access(); CHKERRQ(ierr); 00351 ierr = surface->end_access(); CHKERRQ(ierr); 00352 00353 ierr = h_y.end_access(); CHKERRQ(ierr); 00354 ierr = h_x.end_access(); CHKERRQ(ierr); 00355 00356 return 0; 00357 } 00358 00361 PetscErrorCode SIAFD::surface_gradient_mahaffy(IceModelVec2Stag &h_x, IceModelVec2Stag &h_y) { 00362 PetscErrorCode ierr; 00363 const PetscScalar dx = grid.dx, dy = grid.dy; // convenience 00364 00365 PetscScalar **h; 00366 ierr = h_x.begin_access(); CHKERRQ(ierr); 00367 ierr = h_y.begin_access(); CHKERRQ(ierr); 00368 ierr = surface->get_array(h); CHKERRQ(ierr); 00369 00370 for (PetscInt o=0; o<2; o++) { 00371 PetscInt GHOSTS = 1; 00372 for (PetscInt i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) { 00373 for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) { 00374 if (o==0) { // If I-offset 00375 h_x(i,j,o) = (h[i+1][j] - h[i][j]) / dx; 00376 h_y(i,j,o) = (+ h[i+1][j+1] + h[i][j+1] 00377 - h[i+1][j-1] - h[i][j-1]) / (4.0*dy); 00378 } else { // J-offset 00379 h_y(i,j,o) = (h[i][j+1] - h[i][j]) / dy; 00380 h_x(i,j,o) = (+ h[i+1][j+1] + h[i+1][j] 00381 - h[i-1][j+1] - h[i-1][j]) / (4.0*dx); 00382 } 00383 } 00384 } 00385 } 00386 00387 ierr = surface->end_access(); CHKERRQ(ierr); 00388 ierr = h_y.end_access(); CHKERRQ(ierr); 00389 ierr = h_x.end_access(); CHKERRQ(ierr); 00390 00391 return 0; 00392 } 00393 00395 00435 PetscErrorCode SIAFD::compute_diffusive_flux(IceModelVec2Stag &h_x, IceModelVec2Stag &h_y, 00436 IceModelVec2Stag &result, bool fast) { 00437 PetscErrorCode ierr; 00438 IceModelVec2S thk_smooth = work_2d[0], 00439 theta = work_2d[1]; 00440 00441 bool full_update = !fast; 00442 00443 ierr = result.set(0.0); CHKERRQ(ierr); 00444 00445 PetscScalar *delta_ij; 00446 delta_ij = new PetscScalar[grid.Mz]; 00447 00448 const double enhancement_factor = config.get("enhancement_factor"), 00449 constant_grain_size = config.get("constant_grain_size"), 00450 standard_gravity = config.get("standard_gravity"); 00451 00452 bool compute_grain_size_using_age = config.get_flag("compute_grain_size_using_age"); 00453 00454 // some flow laws use grainsize, and even need age to update grainsize 00455 if (compute_grain_size_using_age && (!config.get_flag("do_age"))) { 00456 PetscPrintf(grid.com, 00457 "PISM ERROR in IceModel::velocitySIAStaggered(): do_age not set but\n" 00458 "age is needed for grain-size-based flow law ... ENDING! ...\n\n"); 00459 PISMEnd(); 00460 } 00461 00462 const bool use_age = (IceFlowLawUsesGrainSize(&ice) && 00463 compute_grain_size_using_age && 00464 config.get_flag("do_age")); 00465 00466 // get "theta" from Schoof (2003) bed smoothness calculation and the 00467 // thickness relative to the smoothed bed; each IceModelVec2S involved must 00468 // have stencil width WIDE_GHOSTS for this too work 00469 ierr = bed_smoother->get_theta(*surface, config.get("Glen_exponent"), 00470 WIDE_STENCIL, &theta); CHKERRQ(ierr); 00471 00472 ierr = bed_smoother->get_smoothed_thk(*surface, *thickness, *mask, 00473 WIDE_STENCIL, 00474 &thk_smooth); CHKERRQ(ierr); 00475 00476 ierr = theta.begin_access(); CHKERRQ(ierr); 00477 ierr = thk_smooth.begin_access(); CHKERRQ(ierr); 00478 ierr = result.begin_access(); CHKERRQ(ierr); 00479 00480 ierr = h_x.begin_access(); CHKERRQ(ierr); 00481 ierr = h_y.begin_access(); CHKERRQ(ierr); 00482 00483 PetscScalar *age_ij, *age_offset; 00484 if (use_age) { 00485 ierr = age->begin_access(); CHKERRQ(ierr); 00486 } 00487 00488 if (full_update) { 00489 ierr = delta[0].begin_access(); CHKERRQ(ierr); 00490 ierr = delta[1].begin_access(); CHKERRQ(ierr); 00491 } 00492 00493 // some flow laws use enthalpy while some ("cold ice methods") use temperature 00494 PetscScalar *E_ij, *E_offset; 00495 ierr = enthalpy->begin_access(); CHKERRQ(ierr); 00496 00497 PetscScalar my_D_max = 0.0; 00498 for (PetscInt o=0; o<2; o++) { 00499 PetscInt GHOSTS = 1; 00500 for (PetscInt i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) { 00501 for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) { 00502 // staggered point: o=0 is i+1/2, o=1 is j+1/2, (i,j) and (i+oi,j+oj) 00503 // are regular grid neighbors of a staggered point: 00504 const PetscInt oi = 1 - o, oj = o; 00505 00506 const PetscScalar 00507 thk = 0.5 * ( thk_smooth(i,j) + thk_smooth(i+oi,j+oj) ); 00508 00509 // zero thickness case: 00510 if (thk == 0.0) { 00511 result(i,j,o) = 0.0; 00512 if (full_update) { 00513 ierr = delta[o].setColumn(i, j, 0.0); CHKERRQ(ierr); 00514 } 00515 continue; 00516 } 00517 00518 if (use_age) { 00519 ierr = age->getInternalColumn(i, j, &age_ij); CHKERRQ(ierr); 00520 ierr = age->getInternalColumn(i+oi, j+oj, &age_offset); CHKERRQ(ierr); 00521 } 00522 00523 ierr = enthalpy->getInternalColumn(i, j, &E_ij); CHKERRQ(ierr); 00524 ierr = enthalpy->getInternalColumn(i+oi, j+oj, &E_offset); CHKERRQ(ierr); 00525 00526 const PetscScalar slope = (o==0) ? h_x(i,j,o) : h_y(i,j,o); 00527 const PetscInt ks = grid.kBelowHeight(thk); 00528 const PetscScalar alpha = 00529 sqrt(PetscSqr(h_x(i,j,o)) + PetscSqr(h_y(i,j,o))); 00530 const PetscReal theta_local = 0.5 * ( theta(i,j) + theta(i+oi,j+oj) ); 00531 00532 PetscScalar Dfoffset = 0.0; // diffusivity for deformational SIA flow 00533 for (PetscInt k = 0; k <= ks; ++k) { 00534 PetscReal depth = thk - grid.zlevels[k]; // FIXME task #7297 00535 // pressure added by the ice (i.e. pressure difference between the 00536 // current level and the top of the column) 00537 const PetscScalar pressure = ice.rho * standard_gravity * depth; 00538 00539 PetscScalar flow, grainsize = constant_grain_size; 00540 if (use_age) { 00541 grainsize = grainSizeVostok(0.5 * (age_ij[k] + age_offset[k])); 00542 } 00543 // If the flow law does not use grain size, it will just ignore it, 00544 // no harm there 00545 PetscScalar E = 0.5 * (E_ij[k] + E_offset[k]); 00546 flow = ice.flow_from_enth(alpha * pressure, E, pressure, grainsize); 00547 00548 delta_ij[k] = enhancement_factor * theta_local * 2.0 * pressure * flow; 00549 00550 if (k > 0) { // trapezoidal rule 00551 const PetscScalar dz = grid.zlevels[k] - grid.zlevels[k-1]; 00552 Dfoffset += 0.5 * dz * ((depth + dz) * delta_ij[k-1] + depth * delta_ij[k]); 00553 } 00554 } 00555 // finish off D with (1/2) dz (0 + (H-z[ks])*delta_ij[ks]), but dz=H-z[ks]: 00556 const PetscScalar dz = thk - grid.zlevels[ks]; 00557 Dfoffset += 0.5 * dz * dz * delta_ij[ks]; 00558 00559 my_D_max = PetscMax(my_D_max, Dfoffset); 00560 00561 // vertically-averaged SIA-only flux, sans sliding; note 00562 // result(i,j,0) is u at E (east) staggered point (i+1/2,j) 00563 // result(i,j,1) is v at N (north) staggered point (i,j+1/2) 00564 result(i,j,o) = - Dfoffset * slope; 00565 00566 // if doing the full update, fill the delta column above the ice and 00567 // store it: 00568 if (full_update) { 00569 for (PetscInt k = ks + 1; k < grid.Mz; ++k) { 00570 delta_ij[k] = 0.0; 00571 } 00572 ierr = delta[o].setInternalColumn(i,j,delta_ij); CHKERRQ(ierr); 00573 } 00574 } // o 00575 } // j 00576 } // i 00577 00578 ierr = h_y.end_access(); CHKERRQ(ierr); 00579 ierr = h_x.end_access(); CHKERRQ(ierr); 00580 00581 ierr = result.end_access(); CHKERRQ(ierr); 00582 ierr = theta.end_access(); CHKERRQ(ierr); 00583 ierr = thk_smooth.end_access(); CHKERRQ(ierr); 00584 00585 if (use_age) { 00586 ierr = age->end_access(); CHKERRQ(ierr); 00587 } 00588 00589 ierr = enthalpy->end_access(); CHKERRQ(ierr); 00590 00591 if (full_update) { 00592 ierr = delta[1].end_access(); CHKERRQ(ierr); 00593 ierr = delta[0].end_access(); CHKERRQ(ierr); 00594 } 00595 00596 ierr = PetscGlobalMax(&my_D_max, &D_max, grid.com); CHKERRQ(ierr); 00597 00598 delete [] delta_ij; 00599 00600 return 0; 00601 } 00602 00604 00615 PetscErrorCode SIAFD::compute_diffusivity(IceModelVec2S &result) { 00616 PetscErrorCode ierr; 00617 // delta on the staggered grid: 00618 IceModelVec2Stag D_stag = work_2d_stag[0]; 00619 PetscScalar *delta_ij; 00620 IceModelVec2S thk_smooth = work_2d[0]; 00621 00622 ierr = bed_smoother->get_smoothed_thk(*surface, *thickness, *mask, 00623 WIDE_STENCIL, 00624 &thk_smooth); CHKERRQ(ierr); 00625 00626 ierr = thk_smooth.begin_access(); CHKERRQ(ierr); 00627 ierr = delta[0].begin_access(); CHKERRQ(ierr); 00628 ierr = delta[1].begin_access(); CHKERRQ(ierr); 00629 ierr = D_stag.begin_access(); CHKERRQ(ierr); 00630 for (PetscInt i = grid.xs; i < grid.xs+grid.xm; ++i) { 00631 for (PetscInt j = grid.ys; j < grid.ys+grid.ym; ++j) { 00632 for (int o = 0; o < 2; ++o) { 00633 const PetscInt oi = 1 - o, oj = o; 00634 00635 ierr = delta[o].getInternalColumn(i,j,&delta_ij); CHKERRQ(ierr); 00636 00637 const PetscScalar 00638 thk = 0.5 * ( thk_smooth(i,j) + thk_smooth(i+oi,j+oj) ); 00639 00640 if (thk == 0) { 00641 D_stag(i,j,o) = 0.0; 00642 continue; 00643 } 00644 00645 const PetscInt ks = grid.kBelowHeight(thk); 00646 PetscScalar Dfoffset = 0.0; 00647 00648 for (PetscInt k = 1; k <= ks; ++k) { 00649 PetscReal depth = thk - grid.zlevels[k]; 00650 00651 const PetscScalar dz = grid.zlevels[k] - grid.zlevels[k-1]; 00652 // trapezoidal rule 00653 Dfoffset += 0.5 * dz * ((depth + dz) * delta_ij[k-1] + depth * delta_ij[k]); 00654 } 00655 00656 // finish off D with (1/2) dz (0 + (H-z[ks])*delta_ij[ks]), but dz=H-z[ks]: 00657 const PetscScalar dz = thk - grid.zlevels[ks]; 00658 Dfoffset += 0.5 * dz * dz * delta_ij[ks]; 00659 00660 D_stag(i,j,o) = Dfoffset; 00661 } 00662 } 00663 } 00664 ierr = D_stag.end_access(); CHKERRQ(ierr); 00665 ierr = delta[1].end_access(); CHKERRQ(ierr); 00666 ierr = delta[0].end_access(); CHKERRQ(ierr); 00667 ierr = thk_smooth.end_access(); CHKERRQ(ierr); 00668 00669 ierr = D_stag.beginGhostComm(); CHKERRQ(ierr); 00670 ierr = D_stag.endGhostComm(); CHKERRQ(ierr); 00671 00672 ierr = D_stag.staggered_to_regular(result); CHKERRQ(ierr); 00673 00674 return 0; 00675 } 00676 00678 PetscErrorCode SIAFD::extend_the_grid(PetscInt old_Mz) { 00679 PetscErrorCode ierr; 00680 00681 ierr = SSB_Modifier::extend_the_grid(old_Mz); CHKERRQ(ierr); 00682 00683 ierr = delta[0].extend_vertically(old_Mz, 0.0); CHKERRQ(ierr); 00684 ierr = delta[1].extend_vertically(old_Mz, 0.0); CHKERRQ(ierr); 00685 00686 ierr = work_3d[0].extend_vertically(old_Mz, 0.0); CHKERRQ(ierr); 00687 ierr = work_3d[1].extend_vertically(old_Mz, 0.0); CHKERRQ(ierr); 00688 00689 return 0; 00690 } 00691 00693 00711 PetscErrorCode SIAFD::compute_sigma(IceModelVec2S *D2_input, 00712 IceModelVec2Stag &h_x, 00713 IceModelVec2Stag &h_y) { 00714 PetscErrorCode ierr; 00715 PetscScalar *sigma_ij, *delta_ij, *E; 00716 00717 // aliases 00718 IceModelVec2S thk_smooth = work_2d[0]; 00719 IceModelVec3 sigma[2] = {work_3d[0], work_3d[1]}; 00720 00721 ierr = bed_smoother->get_smoothed_thk(*surface, *thickness, *mask, 00722 WIDE_STENCIL, 00723 &thk_smooth); CHKERRQ(ierr); 00724 00725 ierr = delta[0].begin_access(); CHKERRQ(ierr); 00726 ierr = delta[1].begin_access(); CHKERRQ(ierr); 00727 ierr = sigma[0].begin_access(); CHKERRQ(ierr); 00728 ierr = sigma[1].begin_access(); CHKERRQ(ierr); 00729 ierr = enthalpy->begin_access(); CHKERRQ(ierr); 00730 00731 ierr = h_x.begin_access(); CHKERRQ(ierr); 00732 ierr = h_y.begin_access(); CHKERRQ(ierr); 00733 ierr = D2_input->begin_access(); CHKERRQ(ierr); 00734 ierr = thk_smooth.begin_access(); CHKERRQ(ierr); 00735 ierr = mask->begin_access(); CHKERRQ(ierr); 00736 00737 MaskQuery M(*mask); 00738 00739 double enhancement_factor = config.get("enhancement_factor"), 00740 n_glen = ice.exponent(), 00741 Sig_pow = (1.0 + n_glen) / (2.0 * n_glen); 00742 00743 for (PetscInt o = 0; o < 2; ++o) { 00744 PetscInt GHOSTS = 1; 00745 for (PetscInt i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) { 00746 for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) { 00747 const PetscInt oi = 1-o, oj=o; 00748 00749 ierr = delta[o].getInternalColumn(i,j,&delta_ij); CHKERRQ(ierr); 00750 ierr = sigma[o].getInternalColumn(i,j,&sigma_ij); CHKERRQ(ierr); 00751 ierr = enthalpy->getInternalColumn(i,j,&E); CHKERRQ(ierr); 00752 00753 const PetscScalar 00754 thk = 0.5 * ( thk_smooth(i,j) + thk_smooth(i+oi,j+oj) ); 00755 00756 const PetscInt ks = grid.kBelowHeight(thk); 00757 00758 // alpha_squared is the square of the magnitude of the surface gradient 00759 const PetscScalar alpha_squared = 00760 PetscSqr(h_x(i,j,o)) + PetscSqr(h_y(i,j,o)); 00761 00762 // in the ice: 00763 for (PetscInt k=0; k<=ks; ++k) { 00764 PetscReal depth = thk - grid.zlevels[k]; 00765 PetscReal pressure = EC.getPressureFromDepth(depth); 00766 00767 PetscReal sigma_sia = delta_ij[k] * alpha_squared * pressure, 00768 BofT = ice.hardnessParameter_from_enth(E[k], pressure) * pow(enhancement_factor,-1/n_glen), 00769 D2_ssa = (*D2_input)(i,j); 00770 00771 if (M.grounded_ice(i, j)) { 00772 // combine SIA and SSA contributions 00773 PetscReal D2_sia = pow(sigma_sia / (2 * BofT), 1.0 / Sig_pow); 00774 sigma_ij[k] = 2.0 * BofT * pow(D2_sia + D2_ssa, Sig_pow); 00775 } else { 00776 // must be floating or ice-free, use the SSA contribution only 00777 sigma_ij[k] = 2.0 * BofT * pow(D2_ssa, Sig_pow); 00778 } 00779 } 00780 00781 // above the ice: 00782 for (PetscInt k=ks+1; k<grid.Mz; ++k) { 00783 sigma_ij[k] = 0.0; 00784 } 00785 } // j 00786 } // i 00787 } // o 00788 00789 ierr = mask->end_access(); CHKERRQ(ierr); 00790 ierr = D2_input->end_access(); CHKERRQ(ierr); 00791 ierr = h_y.end_access(); CHKERRQ(ierr); 00792 ierr = h_x.end_access(); CHKERRQ(ierr); 00793 00794 ierr = delta[1].end_access(); CHKERRQ(ierr); 00795 ierr = delta[0].end_access(); CHKERRQ(ierr); 00796 ierr = enthalpy->end_access(); CHKERRQ(ierr); 00797 00798 // Now transfer Sigma from the staggered onto the regular grid. 00799 PetscScalar *Sigmareg, *SigmaEAST, *SigmaWEST, *SigmaNORTH, *SigmaSOUTH; 00800 ierr = Sigma.begin_access(); CHKERRQ(ierr); 00801 for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) { 00802 for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) { 00803 PetscReal thk = thk_smooth(i,j); 00804 if (thk > 0.0) { 00805 // horizontally average Sigma onto regular grid 00806 const PetscInt ks = grid.kBelowHeight(thk); 00807 ierr = Sigma.getInternalColumn(i,j,&Sigmareg); CHKERRQ(ierr); 00808 ierr = sigma[0].getInternalColumn(i,j,&SigmaEAST); CHKERRQ(ierr); 00809 ierr = sigma[0].getInternalColumn(i-1,j,&SigmaWEST); CHKERRQ(ierr); 00810 ierr = sigma[1].getInternalColumn(i,j,&SigmaNORTH); CHKERRQ(ierr); 00811 ierr = sigma[1].getInternalColumn(i,j-1,&SigmaSOUTH); CHKERRQ(ierr); 00812 for (PetscInt k = 0; k <= ks; ++k) { 00813 Sigmareg[k] = 0.25 * (SigmaEAST[k] + SigmaWEST[k] + SigmaNORTH[k] + SigmaSOUTH[k]); 00814 } 00815 for (PetscInt k = ks+1; k < grid.Mz; ++k) { 00816 Sigmareg[k] = 0.0; 00817 } 00818 } else { // zero thickness case 00819 ierr = Sigma.setColumn(i,j,0.0); CHKERRQ(ierr); 00820 } 00821 } 00822 } 00823 ierr = Sigma.end_access(); CHKERRQ(ierr); 00824 00825 ierr = thk_smooth.end_access(); CHKERRQ(ierr); 00826 ierr = sigma[1].end_access(); CHKERRQ(ierr); 00827 ierr = sigma[0].end_access(); CHKERRQ(ierr); 00828 00829 return 0; 00830 } 00831 00833 00844 PetscErrorCode SIAFD::compute_I() { 00845 PetscErrorCode ierr; 00846 PetscScalar *I_ij, *delta_ij; 00847 00848 IceModelVec2S thk_smooth = work_2d[0]; 00849 IceModelVec3 I[2] = {work_3d[0], work_3d[1]}; 00850 00851 ierr = bed_smoother->get_smoothed_thk(*surface, *thickness, *mask, 00852 WIDE_STENCIL, 00853 &thk_smooth); CHKERRQ(ierr); 00854 00855 ierr = delta[0].begin_access(); CHKERRQ(ierr); 00856 ierr = delta[1].begin_access(); CHKERRQ(ierr); 00857 ierr = I[0].begin_access(); CHKERRQ(ierr); 00858 ierr = I[1].begin_access(); CHKERRQ(ierr); 00859 ierr = thk_smooth.begin_access(); CHKERRQ(ierr); 00860 00861 for (PetscInt o = 0; o < 2; ++o) { 00862 PetscInt GHOSTS = 1; 00863 for (PetscInt i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) { 00864 for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) { 00865 const PetscInt oi = 1-o, oj=o; 00866 const PetscReal 00867 thk = 0.5 * ( thk_smooth(i,j) + thk_smooth(i+oi,j+oj) ); 00868 00869 ierr = delta[o].getInternalColumn(i,j,&delta_ij); CHKERRQ(ierr); 00870 ierr = I[o].getInternalColumn(i,j,&I_ij); CHKERRQ(ierr); 00871 00872 const PetscInt ks = grid.kBelowHeight(thk); 00873 00874 // within the ice: 00875 I_ij[0] = 0.0; 00876 for (int k = 1; k <= ks; ++k) { 00877 const PetscReal dz = grid.zlevels[k] - grid.zlevels[k-1]; 00878 // trapezoidal rule 00879 I_ij[k] = I_ij[k-1] + 0.5 * dz * (delta_ij[k-1] + delta_ij[k]); 00880 } 00881 // above the ice: 00882 for (PetscInt k = ks + 1; k < grid.Mz; ++k) { 00883 I_ij[k] = I_ij[ks]; 00884 } 00885 } 00886 } 00887 } 00888 00889 ierr = thk_smooth.end_access(); CHKERRQ(ierr); 00890 ierr = I[1].end_access(); CHKERRQ(ierr); 00891 ierr = I[0].end_access(); CHKERRQ(ierr); 00892 ierr = delta[1].end_access(); CHKERRQ(ierr); 00893 ierr = delta[0].end_access(); CHKERRQ(ierr); 00894 00895 return 0; 00896 } 00897 00899 00916 PetscErrorCode SIAFD::compute_3d_horizontal_velocity(IceModelVec2Stag &h_x, IceModelVec2Stag &h_y, 00917 IceModelVec2V *vel_input, 00918 IceModelVec3 &u_out, IceModelVec3 &v_out) { 00919 PetscErrorCode ierr; 00920 00921 ierr = compute_I(); CHKERRQ(ierr); 00922 // after the compute_I() call work_3d[0,1] contains I on the staggered grid 00923 IceModelVec3 I[2] = {work_3d[0], work_3d[1]}; 00924 00925 PetscScalar *u_ij, *v_ij, *IEAST, *IWEST, *INORTH, *ISOUTH; 00926 00927 ierr = u_out.begin_access(); CHKERRQ(ierr); 00928 ierr = v_out.begin_access(); CHKERRQ(ierr); 00929 00930 ierr = h_x.begin_access(); CHKERRQ(ierr); 00931 ierr = h_y.begin_access(); CHKERRQ(ierr); 00932 ierr = vel_input->begin_access(); CHKERRQ(ierr); 00933 00934 ierr = I[0].begin_access(); CHKERRQ(ierr); 00935 ierr = I[1].begin_access(); CHKERRQ(ierr); 00936 00937 for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) { 00938 for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) { 00939 ierr = I[0].getInternalColumn(i,j,&IEAST); CHKERRQ(ierr); 00940 ierr = I[0].getInternalColumn(i-1,j,&IWEST); CHKERRQ(ierr); 00941 ierr = I[1].getInternalColumn(i,j,&INORTH); CHKERRQ(ierr); 00942 ierr = I[1].getInternalColumn(i,j-1,&ISOUTH); CHKERRQ(ierr); 00943 00944 ierr = u_out.getInternalColumn(i, j, &u_ij); CHKERRQ(ierr); 00945 ierr = v_out.getInternalColumn(i, j, &v_ij); CHKERRQ(ierr); 00946 00947 for (PetscInt k = 0; k < grid.Mz; ++k) { 00948 u_ij[k] = - 0.25 * ( IEAST[k] * h_x(i,j,0) + IWEST[k] * h_x(i-1,j,0) + 00949 INORTH[k] * h_x(i,j,1) + ISOUTH[k] * h_x(i,j-1,1) ); 00950 v_ij[k] = - 0.25 * ( IEAST[k] * h_y(i,j,0) + IWEST[k] * h_y(i-1,j,0) + 00951 INORTH[k] * h_y(i,j,1) + ISOUTH[k] * h_y(i,j-1,1) ); 00952 00953 // Add the "SSA" velocity: 00954 u_ij[k] += (*vel_input)(i,j).u; 00955 v_ij[k] += (*vel_input)(i,j).v; 00956 } 00957 } 00958 } 00959 00960 ierr = I[1].end_access(); CHKERRQ(ierr); 00961 ierr = I[0].end_access(); CHKERRQ(ierr); 00962 00963 ierr = vel_input->end_access(); CHKERRQ(ierr); 00964 ierr = h_y.end_access(); CHKERRQ(ierr); 00965 ierr = h_x.end_access(); CHKERRQ(ierr); 00966 00967 ierr = u_out.end_access(); CHKERRQ(ierr); 00968 ierr = v_out.end_access(); CHKERRQ(ierr); 00969 00970 // Communicate to get ghosts: 00971 ierr = u_out.beginGhostComm(); CHKERRQ(ierr); 00972 ierr = v_out.beginGhostComm(); CHKERRQ(ierr); 00973 ierr = u_out.endGhostComm(); CHKERRQ(ierr); 00974 ierr = v_out.endGhostComm(); CHKERRQ(ierr); 00975 00976 return 0; 00977 } 00978 00980 00992 PetscScalar SIAFD::grainSizeVostok(PetscScalar age_seconds) const { 00993 const PetscInt numPoints = 22; 00994 const PetscScalar ageAt[numPoints] = { // ages in ka 00995 0.0000e+00, 5.0000e+01, 1.0000e+02, 1.2500e+02, 1.5000e+02, 00996 1.5800e+02, 1.6500e+02, 1.7000e+02, 1.8000e+02, 1.8800e+02, 00997 2.0000e+02, 2.2500e+02, 2.4500e+02, 2.6000e+02, 3.0000e+02, 00998 3.2000e+02, 3.5000e+02, 4.0000e+02, 5.0000e+02, 6.0000e+02, 00999 8.0000e+02, 1.0000e+04 }; 01000 const PetscScalar gsAt[numPoints] = { // grain sizes in m 01001 1.8000e-03, 2.2000e-03, 3.0000e-03, 4.0000e-03, 4.3000e-03, 01002 3.0000e-03, 3.0000e-03, 4.6000e-03, 3.4000e-03, 3.3000e-03, 01003 5.9000e-03, 6.2000e-03, 5.4000e-03, 6.8000e-03, 3.5000e-03, 01004 6.0000e-03, 8.0000e-03, 8.3000e-03, 3.6000e-03, 3.8000e-03, 01005 9.5000e-03, 1.0000e-02 }; 01006 const PetscScalar a = age_seconds * 1.0e-3 / secpera; // Age in ka 01007 PetscInt l = 0; // Left end of the binary search 01008 PetscInt r = numPoints - 1; // Right end 01009 01010 // If we are out of range 01011 if (a < ageAt[l]) { 01012 return gsAt[l]; 01013 } else if (a > ageAt[r]) { 01014 return gsAt[r]; 01015 } 01016 // Binary search for the interval 01017 while (r > l + 1) { 01018 const PetscInt j = (r + l) / 2; 01019 if (a < ageAt[j]) { 01020 r = j; 01021 } else { 01022 l = j; 01023 } 01024 } 01025 if ((r == l) || (PetscAbsReal(r - l) > 1)) { 01026 PetscPrintf(grid.com, "binary search in grainSizeVostok: oops.\n"); 01027 } 01028 // Linear interpolation on the interval 01029 return gsAt[l] + (a - ageAt[l]) * (gsAt[r] - gsAt[l]) / (ageAt[r] - ageAt[l]); 01030 }
1.7.3