PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/stressbalance/SIAFD.cc

Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines