PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/stressbalance/SSA.cc

Go to the documentation of this file.
00001 // Copyright (C) 2004--2011 Constantine Khroulev, Ed Bueler, Jed Brown, Torsten Albrecht
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 "SSA.hh"
00020 #include "Mask.hh"
00021 
00022 SSA::SSA(IceGrid &g, IceBasalResistancePlasticLaw &b,
00023          IceFlowLaw &i, EnthalpyConverter &e,
00024          const NCConfigVariable &c)
00025   : ShallowStressBalance(g, b, i, e, c)
00026 {
00027   mask = NULL;
00028   thickness = NULL;
00029   tauc = NULL;
00030   surface = NULL;
00031   bed = NULL;
00032   enthalpy = NULL;
00033 
00034   strength_extension = new SSAStrengthExtension(config);
00035   allocate();
00036 }
00037 
00038 
00040 PetscErrorCode SSA::init(PISMVars &vars) {
00041   PetscErrorCode ierr;
00042 
00043   ierr = ShallowStressBalance::init(vars); CHKERRQ(ierr);
00044 
00045   ierr = verbPrintf(2,grid.com,"* Initializing the SSA stress balance...\n"); CHKERRQ(ierr);
00046 
00047   mask = dynamic_cast<IceModelVec2Int*>(vars.get("mask"));
00048   if (mask == NULL) SETERRQ(1, "mask is not available");
00049 
00050   thickness = dynamic_cast<IceModelVec2S*>(vars.get("land_ice_thickness"));
00051   if (thickness == NULL) SETERRQ(1, "land_ice_thickness is not available");
00052 
00053   tauc = dynamic_cast<IceModelVec2S*>(vars.get("tauc"));
00054   if (tauc == NULL) SETERRQ(1, "tauc is not available");
00055 
00056   surface = dynamic_cast<IceModelVec2S*>(vars.get("surface_altitude"));
00057   if (surface == NULL) SETERRQ(1, "surface_altitude is not available");
00058 
00059   bed = dynamic_cast<IceModelVec2S*>(vars.get("bedrock_altitude"));
00060   if (bed == NULL) SETERRQ(1, "bedrock_altitude is not available");
00061 
00062   enthalpy = dynamic_cast<IceModelVec3*>(vars.get("enthalpy"));
00063   if (enthalpy == NULL) SETERRQ(1, "enthalpy is not available");
00064 
00065 
00066   // Check if PISM is being initialized from an output file from a previous run
00067   // and read the initial guess (unless asked not to).
00068   bool i_set;
00069   string filename;
00070   ierr = PISMOptionsString("-i", "PISM input file",
00071                            filename, i_set); CHKERRQ(ierr);
00072 
00073   if (i_set) {
00074     bool dont_read_initial_guess, ubar_ssa_found, vbar_ssa_found;
00075     int start;
00076     NCTool nc(grid.com, grid.rank);
00077 
00078     ierr = PISMOptionsIsSet("-dontreadSSAvels", dont_read_initial_guess); CHKERRQ(ierr);
00079 
00080     ierr = nc.open_for_reading(filename.c_str()); CHKERRQ(ierr);
00081     ierr = nc.find_variable("ubar_ssa", NULL, ubar_ssa_found); CHKERRQ(ierr); 
00082     ierr = nc.find_variable("vbar_ssa", NULL, vbar_ssa_found); CHKERRQ(ierr); 
00083     ierr = nc.get_nrecords(start); CHKERRQ(ierr);
00084     ierr = nc.close(); CHKERRQ(ierr); 
00085     start -= 1;
00086 
00087     if (ubar_ssa_found && vbar_ssa_found &&
00088         (! dont_read_initial_guess)) {
00089       ierr = verbPrintf(3,grid.com,"Reading ubar_ssa and vbar_ssa...\n"); CHKERRQ(ierr);
00090 
00091       ierr = velocity.read(filename.c_str(), start); CHKERRQ(ierr); 
00092     }
00093     
00094   } else {
00095     ierr = velocity.set(0.0); CHKERRQ(ierr); // default initial guess
00096   }
00097 
00098   if (config.get_flag("dirichlet_bc")) {
00099 
00100       bc_locations = dynamic_cast<IceModelVec2Int*>(vars.get("bcflag"));
00101           if (bc_locations == NULL) SETERRQ(1, "bc_locations is not available");
00102 
00103            vel_bc = dynamic_cast<IceModelVec2V*>(vars.get("velbar"));
00104            if (vel_bc == NULL) SETERRQ(1, "velbar is not available");
00105   }
00106 
00107   event_ssa = grid.profiler->create("ssa_update", "time spent solving the SSA");
00108 
00109   return 0;
00110 }
00111 
00113 PetscErrorCode SSA::allocate() {
00114   PetscErrorCode ierr;
00115 
00116   ierr = taud.create(grid, "taud", false); CHKERRQ(ierr);
00117   ierr = taud.set_attrs("diagnostic",
00118                         "X-component of the driving shear stress at the base of ice",
00119                         "Pa", "", 0); CHKERRQ(ierr);
00120   ierr = taud.set_attrs("diagnostic",
00121                         "Y-component of the driving shear stress at the base of ice",
00122                         "Pa", "", 1); CHKERRQ(ierr);
00123 
00124   ierr = velocity_old.create(grid, "velocity_old", true); CHKERRQ(ierr);
00125   ierr = velocity_old.set_attrs("internal",
00126                                 "old SSA velocity field; used for re-trying with a different epsilon",
00127                                 "m s-1", ""); CHKERRQ(ierr);
00128 
00129   // override velocity metadata
00130   ierr = velocity.set_name("bar_ssa"); CHKERRQ(ierr);
00131   ierr = velocity.set_attrs("internal_restart", "SSA model ice velocity in the X direction",
00132                             "m s-1", "", 0); CHKERRQ(ierr);
00133 
00134   ierr = velocity.set_attrs("internal_restart", "SSA model ice velocity in the Y direction",
00135                             "m s-1", "", 1); CHKERRQ(ierr);
00136 
00137   ierr = velocity.set_glaciological_units("m year-1"); CHKERRQ(ierr);
00138 
00139   // mimic IceGrid::createDA() with TRANSPOSE :
00140   PetscInt dof=2, stencil_width=1;
00141   ierr = DACreate2d(grid.com, DA_XYPERIODIC, DA_STENCIL_BOX,
00142                     grid.My, grid.Mx,
00143                     grid.Ny, grid.Nx,
00144                     dof, stencil_width,
00145                     grid.procs_y.data(), grid.procs_x.data(),
00146                     &SSADA); CHKERRQ(ierr);
00147 
00148   ierr = DACreateGlobalVector(SSADA, &SSAX); CHKERRQ(ierr);
00149   
00150   return 0;
00151 }
00152 
00153 
00154 PetscErrorCode SSA::deallocate() {
00155   PetscErrorCode ierr;
00156 
00157   if (SSAX != PETSC_NULL) {
00158     ierr = VecDestroy(SSAX); CHKERRQ(ierr);
00159   }
00160 
00161   if (SSADA != PETSC_NULL) {
00162     ierr = DADestroy(SSADA);CHKERRQ(ierr);
00163   }
00164   
00165   return 0;
00166 }
00167 
00168 
00170 PetscErrorCode SSA::update(bool fast) {
00171   PetscErrorCode ierr;
00172 
00173   if (fast)
00174     return 0;
00175 
00176   grid.profiler->begin(event_ssa);
00177 
00178   ierr = solve(); CHKERRQ(ierr); 
00179 
00180   ierr = compute_basal_frictional_heating(basal_frictional_heating); CHKERRQ(ierr);
00181   ierr = compute_D2(D2); CHKERRQ(ierr);
00182 
00183   ierr = compute_maximum_velocity(); CHKERRQ(ierr);
00184 
00185   grid.profiler->end(event_ssa);
00186 
00187   return 0;
00188 }
00189 
00190 
00192 
00195 PetscErrorCode SSA::compute_D2(IceModelVec2S &result) {
00196   PetscErrorCode ierr;
00197   PetscReal dx = grid.dx, dy = grid.dy;
00198 
00199   ierr = velocity.begin_access(); CHKERRQ(ierr);
00200   ierr = result.begin_access(); CHKERRQ(ierr);
00201   for (PetscInt   i = grid.xs; i < grid.xs+grid.xm; ++i) {
00202     for (PetscInt j = grid.ys; j < grid.ys+grid.ym; ++j) {
00203       const PetscScalar 
00204           u_x   = (velocity(i+1,j).u - velocity(i-1,j).u)/(2*dx),
00205           u_y   = (velocity(i,j+1).u - velocity(i,j-1).u)/(2*dy),
00206           v_x   = (velocity(i+1,j).v - velocity(i-1,j).v)/(2*dx),
00207           v_y   = (velocity(i,j+1).v - velocity(i,j-1).v)/(2*dy);
00208       result(i,j) = PetscSqr(u_x) + PetscSqr(v_y) + u_x * v_y 
00209                       + PetscSqr(0.5*(u_y + v_x));
00210     }
00211   }
00212   ierr = result.end_access(); CHKERRQ(ierr);
00213   ierr = velocity.end_access(); CHKERRQ(ierr);
00214   return 0;
00215 }
00216 
00217 
00219 
00238 PetscErrorCode SSA::compute_principal_strain_rates(IceModelVec2S &result_e1,
00239                                                    IceModelVec2S &result_e2) {
00240   PetscErrorCode ierr;
00241   PetscScalar    dx = grid.dx, dy = grid.dy;
00242 
00243   IceModelVec2S H = *thickness; // an alias
00244   ierr = velocity.begin_access(); CHKERRQ(ierr);
00245   ierr = H.begin_access(); CHKERRQ(ierr);
00246   ierr = result_e1.begin_access(); CHKERRQ(ierr);
00247   ierr = result_e2.begin_access(); CHKERRQ(ierr);
00248 
00249   for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00250     for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00251 
00252       if ( velocity(i,j).u == 0.0 || velocity(i,j).v == 0.0) {
00253         result_e1(i,j) = 0.0;
00254         result_e2(i,j) = 0.0;
00255         continue;
00256       }
00257 
00258       //centered difference scheme; strain in units s-1
00259       PetscScalar
00260         u_x = (velocity(i+1,j).u - velocity(i-1,j).u) / (2 * dx),
00261         u_y = (velocity(i,j+1).u - velocity(i,j-1).u) / (2 * dy),
00262         v_x = (velocity(i+1,j).v - velocity(i-1,j).v) / (2 * dx),
00263         v_y = (velocity(i,j+1).v - velocity(i,j-1).v) / (2 * dy);
00264 
00265       //inward scheme at the ice-shelf front
00266       if (H(i+1,j)==0.0) {
00267         u_x = (velocity(i,j).u - velocity(i-1,j).u) / dx;
00268         v_x = (velocity(i,j).v - velocity(i-1,j).v) / dx;
00269       }
00270       if (H(i-1,j)==0.0) {
00271         u_x = (velocity(i+1,j).u - velocity(i,j).u) / dx;
00272         v_x = (velocity(i+1,j).v - velocity(i,j).v) / dx;
00273       }
00274       if (H(i-1,j)==0.0) {
00275         u_y = (velocity(i,j).u - velocity(i,j-1).u) / dy;
00276         v_y = (velocity(i,j).v - velocity(i,j-1).v) / dy;
00277       }
00278       if (H(i-1,j)==0.0) {
00279         u_y = (velocity(i,j+1).u - velocity(i,j).u) / dy;
00280         v_y = (velocity(i,j+1).v - velocity(i,j).v) / dy;
00281       }
00282 
00283       // ice nose case
00284       if (H(i,j-1)==0.0 && H(i,j+1)==0.0) {
00285         u_y = 0.0;
00286         v_y = 0.0;
00287       }
00288       if (H(i+1,j)==0.0 && H(i-1,j)==0.0) {
00289         u_x = 0.0;
00290         v_x = 0.0;
00291       }
00292 
00293       const PetscScalar A = 0.5 * (u_x + v_y),  // A = (1/2) trace(D)
00294         B   = 0.5 * (u_x - v_y),
00295         Dxy = 0.5 * (v_x + u_y),  // B^2 = A^2 - u_x v_y
00296         q   = sqrt(PetscSqr(B) + PetscSqr(Dxy));
00297       result_e1(i,j) = A + q;
00298       result_e2(i,j) = A - q; // q >= 0 so e1 >= e2
00299 
00300     } // j
00301   }   // i
00302 
00303   ierr = velocity.end_access(); CHKERRQ(ierr);
00304   ierr = H.end_access(); CHKERRQ(ierr);
00305   ierr = result_e1.end_access(); CHKERRQ(ierr);
00306   ierr = result_e2.end_access(); CHKERRQ(ierr);
00307   return 0;
00308 }
00309 
00310 
00312 
00315 PetscErrorCode SSA::compute_basal_frictional_heating(IceModelVec2S &result) {
00316   PetscErrorCode ierr;
00317 
00318   MaskQuery m(*mask);
00319 
00320   ierr = velocity.begin_access(); CHKERRQ(ierr);
00321   ierr = result.begin_access(); CHKERRQ(ierr);
00322   ierr = tauc->begin_access(); CHKERRQ(ierr);
00323   ierr = mask->begin_access(); CHKERRQ(ierr);
00324   
00325   for (PetscInt   i = grid.xs; i < grid.xs+grid.xm; ++i) {
00326     for (PetscInt j = grid.ys; j < grid.ys+grid.ym; ++j) {
00327       if (m.ocean(i,j)) {
00328         result(i,j) = 0.0;
00329       } else {
00330         const PetscScalar 
00331           C = basal.drag((*tauc)(i,j), velocity(i,j).u, velocity(i,j).v),
00332           basal_stress_x = - C * velocity(i,j).u,
00333           basal_stress_y = - C * velocity(i,j).v;
00334         result(i,j) = - basal_stress_x * velocity(i,j).u - basal_stress_y * velocity(i,j).v;
00335       }
00336     }
00337   }
00338 
00339   ierr = mask->end_access(); CHKERRQ(ierr);
00340   ierr = tauc->end_access(); CHKERRQ(ierr);
00341   ierr = result.end_access(); CHKERRQ(ierr);
00342   ierr = velocity.end_access(); CHKERRQ(ierr);
00343   return 0;
00344 }
00345 
00347 
00360 PetscErrorCode SSA::compute_driving_stress(IceModelVec2V &result) {
00361   PetscErrorCode ierr;
00362 
00363   IceModelVec2S &thk = *thickness; // to improve readability (below)
00364 
00365   const PetscScalar n       = ice.exponent(), // frequently n = 3
00366                     etapow  = (2.0 * n + 2.0)/n,  // = 8/3 if n = 3
00367                     invpow  = 1.0 / etapow,  // = 3/8
00368                     dinvpow = (- n - 2.0) / (2.0 * n + 2.0); // = -5/8
00369   const PetscScalar minThickEtaTransform = 5.0; // m
00370   const PetscScalar dx=grid.dx, dy=grid.dy;
00371 
00372   bool compute_surf_grad_inward_ssa = config.get_flag("compute_surf_grad_inward_ssa");
00373   PetscReal standard_gravity = config.get("standard_gravity");
00374   bool use_eta = (config.get_string("surface_gradient_method") == "eta");
00375 
00376   ierr =   surface->begin_access();    CHKERRQ(ierr);
00377   ierr =       bed->begin_access();  CHKERRQ(ierr);
00378   ierr =      mask->begin_access();  CHKERRQ(ierr);
00379   ierr =        thk.begin_access();  CHKERRQ(ierr);
00380 
00381   MaskQuery m(*mask);
00382 
00383   ierr = result.begin_access(); CHKERRQ(ierr);
00384 
00385   for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00386     for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00387       const PetscScalar pressure = ice.rho * standard_gravity * thk(i,j); // FIXME task #7297
00388       if (pressure <= 0.0) {
00389         result(i,j).u = 0.0;
00390         result(i,j).v = 0.0;
00391       } else {
00392         PetscScalar h_x = 0.0, h_y = 0.0;
00393         // FIXME: we need to handle grid periodicity correctly.
00394         if (m.grounded(i,j) && (use_eta == true)) {
00395                 // in grounded case, differentiate eta = H^{8/3} by chain rule
00396           if (thk(i,j) > 0.0) {
00397             const PetscScalar myH = (thk(i,j) < minThickEtaTransform ?
00398                                      minThickEtaTransform : thk(i,j));
00399             const PetscScalar eta = pow(myH, etapow), factor = invpow * pow(eta, dinvpow);
00400             h_x = factor * (pow(thk(i+1,j),etapow) - pow(thk(i-1,j),etapow)) / (2*dx);
00401             h_y = factor * (pow(thk(i,j+1),etapow) - pow(thk(i,j-1),etapow)) / (2*dy);
00402           }
00403           // now add bed slope to get actual h_x,h_y
00404           // FIXME: there is no reason to assume user's bed is periodized
00405           h_x += bed->diff_x(i,j);
00406           h_y += bed->diff_y(i,j);
00407         } else {  // floating or eta transformation is not used
00408           if (compute_surf_grad_inward_ssa) {
00409             h_x = surface->diff_x_p(i,j);
00410             h_y = surface->diff_y_p(i,j);
00411           } else {
00412             h_x = surface->diff_x(i,j);
00413             h_y = surface->diff_y(i,j);
00414           }
00415         }
00416 
00417         result(i,j).u = - pressure * h_x;
00418         result(i,j).v = - pressure * h_y;
00419       }
00420     }
00421   }
00422 
00423   ierr =        thk.end_access(); CHKERRQ(ierr);
00424   ierr =       bed->end_access(); CHKERRQ(ierr);
00425   ierr =   surface->end_access(); CHKERRQ(ierr);
00426   ierr =      mask->end_access(); CHKERRQ(ierr);
00427   ierr =     result.end_access(); CHKERRQ(ierr);
00428   return 0;
00429 }
00430 
00431 
00434 PetscErrorCode SSA::compute_maximum_velocity() {
00435   PetscErrorCode ierr;
00436   PetscReal my_max_u = 0.0,
00437     my_max_v = 0.0;
00438 
00439   ierr = velocity.begin_access(); CHKERRQ(ierr);
00440   ierr = mask->begin_access(); CHKERRQ(ierr);
00441   
00442   MaskQuery m(*mask);
00443 
00444   for (PetscInt   i = grid.xs; i < grid.xs+grid.xm; ++i) {
00445     for (PetscInt j = grid.ys; j < grid.ys+grid.ym; ++j) {
00446       if (m.icy(i, j)) {
00447         my_max_u = PetscMax(my_max_u, PetscAbs(velocity(i,j).u));
00448         my_max_v = PetscMax(my_max_v, PetscAbs(velocity(i,j).v));
00449       }
00450     }
00451   }
00452 
00453   ierr = mask->end_access(); CHKERRQ(ierr);
00454   ierr = velocity.end_access(); CHKERRQ(ierr);
00455 
00456   ierr = PetscGlobalMax(&my_max_u, &max_u, grid.com); CHKERRQ(ierr); 
00457   ierr = PetscGlobalMax(&my_max_v, &max_v, grid.com); CHKERRQ(ierr); 
00458   return 0;
00459 }
00460 
00461 PetscErrorCode SSA::stdout_report(string &result) {
00462   result = stdout_ssa;
00463   return 0;
00464 }
00465 
00466 
00468 PetscErrorCode SSA::set_initial_guess(IceModelVec2V &guess) {
00469   PetscErrorCode ierr;
00470   ierr = velocity.copy_from(guess); CHKERRQ(ierr);
00471   return 0;
00472 }
00473 
00474 
00475 void SSA::add_vars_to_output(string /*keyword*/, set<string> &result) {
00476   result.insert("velbar_ssa");
00477 }
00478 
00479 
00480 PetscErrorCode SSA::define_variables(set<string> vars, const NCTool &nc, nc_type nctype) {
00481   PetscErrorCode ierr;
00482 
00483   if (set_contains(vars, "velbar_ssa")) {
00484     ierr = velocity.define(nc, nctype); CHKERRQ(ierr);
00485   }
00486 
00487   return 0;
00488 }
00489 
00490 
00491 PetscErrorCode SSA::write_variables(set<string> vars, string filename) {
00492   PetscErrorCode ierr;
00493 
00494   if (set_contains(vars, "velbar_ssa")) {
00495     ierr = velocity.write(filename.c_str()); CHKERRQ(ierr);
00496   }
00497 
00498   return 0;
00499 }
00500 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines