PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/stressbalance/SSAFD.cc

Go to the documentation of this file.
00001 // Copyright (C) 2004--2011 Constantine Khroulev, Ed Bueler and Jed Brown
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 "SSAFD.hh"
00020 #include "Mask.hh"
00021 
00022 SSA *SSAFDFactory(IceGrid &g, IceBasalResistancePlasticLaw &b,
00023                 IceFlowLaw &i, EnthalpyConverter &ec,
00024                 const NCConfigVariable &c)
00025 {
00026   return new SSAFD(g,b,i,ec,c);
00027 }
00028 
00029 
00031 
00039 PetscErrorCode SSAFD::allocate_fd() {
00040   PetscErrorCode ierr;
00041 
00042   // note SSADA and SSAX are allocated in SSA::allocate()
00043   ierr = VecDuplicate(SSAX, &SSARHS); CHKERRQ(ierr);
00044 
00045   ierr = DAGetMatrix(SSADA, MATAIJ, &SSAStiffnessMatrix); CHKERRQ(ierr);
00046 
00047   ierr = KSPCreate(grid.com, &SSAKSP); CHKERRQ(ierr);
00048   // the default PC type somehow is ILU, which now fails (?) while block jacobi
00049   //   seems to work; runtime options can override (see test J in vfnow.py)
00050   PC pc;
00051   ierr = KSPGetPC(SSAKSP,&pc); CHKERRQ(ierr);
00052   ierr = PCSetType(pc,PCBJACOBI); CHKERRQ(ierr);
00053   ierr = KSPSetFromOptions(SSAKSP); CHKERRQ(ierr);
00054 
00055   const PetscScalar power = 1.0 / ice.exponent();
00056   char unitstr[TEMPORARY_STRING_LENGTH];
00057   snprintf(unitstr, sizeof(unitstr), "Pa s%f", power);
00058   ierr = hardness.create(grid, "hardness", false); CHKERRQ(ierr);
00059   ierr = hardness.set_attrs("diagnostic",
00060                             "vertically-averaged ice hardness",
00061                             unitstr, ""); CHKERRQ(ierr);
00062 
00063   ierr = nuH.create(grid, "nuH", true); CHKERRQ(ierr);
00064   ierr = nuH.set_attrs("internal",
00065                        "ice thickness times effective viscosity",
00066                        "Pa s m", ""); CHKERRQ(ierr);
00067 
00068   ierr = nuH_old.create(grid, "nuH_old", true); CHKERRQ(ierr);
00069   ierr = nuH_old.set_attrs("internal",
00070                            "ice thickness times effective viscosity (before an update)",
00071                            "Pa s m", ""); CHKERRQ(ierr);
00072 
00073   scaling = 1.0e9;  // comparable to typical beta for an ice stream;
00074 
00075   // The nuH viewer:
00076   view_nuh = false;
00077   nuh_viewer_size = 300;
00078   nuh_viewer = PETSC_NULL;
00079   return 0;
00080 }
00081 
00083 PetscErrorCode SSAFD::deallocate_fd() {
00084   PetscErrorCode ierr;
00085 
00086   if (SSAKSP != PETSC_NULL) {
00087     ierr = KSPDestroy(SSAKSP); CHKERRQ(ierr);
00088   }
00089 
00090   if (SSAStiffnessMatrix != PETSC_NULL) {
00091     ierr = MatDestroy(SSAStiffnessMatrix); CHKERRQ(ierr);
00092   }
00093 
00094   if (SSARHS != PETSC_NULL) {
00095     ierr = VecDestroy(SSARHS); CHKERRQ(ierr);
00096   }
00097 
00098   return 0;
00099 }
00100 
00101 PetscErrorCode SSAFD::init(PISMVars &vars) {
00102   PetscErrorCode ierr;
00103   ierr = SSA::init(vars); CHKERRQ(ierr);
00104   ierr = verbPrintf(2,grid.com,
00105                     "  [using the KSP-based finite difference implementation]\n"); CHKERRQ(ierr);
00106 
00107   ierr = PetscOptionsBegin(grid.com, "", "SSAFD options", ""); CHKERRQ(ierr);
00108   {
00109     bool flag;
00110     ierr = PISMOptionsInt("-ssa_nuh_viewer_size", "nuH viewer size",
00111                           nuh_viewer_size, flag); CHKERRQ(ierr);
00112     ierr = PISMOptionsIsSet("-ssa_view_nuh", "Enable the SSAFD nuH runtime viewer",
00113                             view_nuh); CHKERRQ(ierr);
00114   }
00115   ierr = PetscOptionsEnd(); CHKERRQ(ierr);
00116 
00117   if (config.get_flag("calving_front_stress_boundary_condition")) {
00118     ierr = verbPrintf(2,grid.com,
00119       "  using PISM-PIK calving-front stress boundary condition ...\n"); CHKERRQ(ierr);
00120   }
00121 
00122   return 0;
00123 }
00124 
00127 
00141 PetscErrorCode SSAFD::assemble_rhs(Vec rhs) {
00142   PetscErrorCode ierr;
00143   PISMVector2 **rhs_uv;
00144   const double dx = grid.dx, dy = grid.dy;
00145 
00146   Mask M;
00147 
00148   const double standard_gravity = config.get("standard_gravity"),
00149     ocean_rho = config.get("sea_water_density");
00150   const bool use_cfbc = config.get_flag("calving_front_stress_boundary_condition");
00151 
00152   ierr = VecSet(rhs, 0.0); CHKERRQ(ierr);
00153 
00154   // get driving stress components
00155   ierr = compute_driving_stress(taud); CHKERRQ(ierr);
00156 
00157   ierr = taud.begin_access(); CHKERRQ(ierr);
00158   ierr = DAVecGetArray(SSADA, rhs, &rhs_uv); CHKERRQ(ierr);
00159 
00160   if (vel_bc && bc_locations) {
00161     ierr = vel_bc->begin_access(); CHKERRQ(ierr);
00162     ierr = bc_locations->begin_access(); CHKERRQ(ierr);
00163   }
00164 
00165   if (use_cfbc) {
00166     ierr = thickness->begin_access(); CHKERRQ(ierr);
00167     ierr = bed->begin_access(); CHKERRQ(ierr);
00168     ierr = mask->begin_access(); CHKERRQ(ierr);
00169   }
00170 
00171   for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) {
00172     for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) {
00173 
00174       if (vel_bc && (bc_locations->as_int(i, j) == 1)) {
00175         rhs_uv[i][j].u = scaling * (*vel_bc)(i, j).u;
00176         rhs_uv[i][j].v = scaling * (*vel_bc)(i, j).v;
00177         continue;
00178       }
00179 
00180 
00181       if (use_cfbc) {
00182         PetscScalar H_ij = (*thickness)(i,j);
00183         PetscInt M_ij = mask->as_int(i,j),
00184           M_e = mask->as_int(i + 1,j),
00185           M_w = mask->as_int(i - 1,j),
00186           M_n = mask->as_int(i,j + 1),
00187           M_s = mask->as_int(i,j - 1);
00188 
00189         // Note: this sets velocities at both ice-free ocean and ice-free
00190         // bedrock to zero. This means that we need to set boundary conditions
00191         // at both ice/ice-free-ocean and ice/ice-free-bedrock interfaces below
00192         // to be consistent.
00193         if (M.ice_free(M_ij)) {
00194           rhs_uv[i][j].u = 0.0;
00195           rhs_uv[i][j].v = 0.0;
00196           continue;
00197         }
00198 
00199         if (is_marginal(i, j)) {
00200           PetscInt aMM = 1, aPP = 1, bMM = 1, bPP = 1;
00201           // direct neighbors
00202           if (M.ice_free(M_e)) aPP = 0;
00203           if (M.ice_free(M_w)) aMM = 0;
00204           if (M.ice_free(M_n)) bPP = 0;
00205           if (M.ice_free(M_s)) bMM = 0;
00206 
00207           double ice_pressure = ice.rho * standard_gravity * H_ij,
00208             ocean_pressure;
00209 
00210           const double h_grounded = (*bed)(i,j) + H_ij,
00211             h_floating = sea_level + (1.0 - ice.rho / ocean_rho) * H_ij,
00212             H_ij2 = H_ij*H_ij;
00213 
00214           //double h_ij = 0.0, tdx = 0.0, tdy = 0.0;
00215           double h_ij = 0.0, tdx = taud(i, j).u, tdy = taud(i, j).v;
00216 
00217           if ((*bed)(i,j) < (sea_level - (ice.rho / ocean_rho) * H_ij)) {
00218             //calving front boundary condition for floating shelf
00219             ocean_pressure = 0.5 * ice.rho * standard_gravity * (1 - (ice.rho / ocean_rho))*H_ij2;
00220             // this is not really the ocean_pressure, but the difference between
00221             // ocean_pressure and isotrop.normal stresses (=pressure) from within
00222             // the ice
00223             h_ij = h_floating;
00224           } else {
00225             h_ij = h_grounded;
00226             if( (*bed)(i,j) >= sea_level) {
00227               // boundary condition for a "cliff" (grounded ice next to
00228               // ice-free ocean) or grounded margin.
00229               ocean_pressure = 0.5 * ice.rho * standard_gravity * H_ij2;
00230               // this is not 'zero' because the isotrop.normal stresses
00231               // (=pressure) from within the ice figures on RHS
00232             } else {
00233               // boundary condition for marine terminating glacier
00234               ocean_pressure = 0.5 * ice.rho * standard_gravity *
00235                 (H_ij2 - (ocean_rho / ice.rho)*(sea_level - (*bed)(i,j))*(sea_level - (*bed)(i,j)));
00236             }
00237           }
00238 
00239           //here we take the direct gradient at the boundary (not centered)
00240 
00241           if (aPP == 0 && aMM == 1) tdx = ice_pressure*h_ij / dx;
00242           else if (aMM == 0 && aPP == 1) tdx = -ice_pressure*h_ij / dx;
00243           else if (aPP == 0 && aMM == 0) tdx = 0; //in case of some kind of ice nose, or ice bridge
00244 
00245           if (bPP == 0 && bMM == 1) tdy = ice_pressure*h_ij / dy;
00246           else if (bMM == 0 && bPP == 1) tdy = -ice_pressure*h_ij / dy;
00247           else if (bPP == 0 && bMM == 0) tdy = 0;
00248 
00249           // Note that if the current cell is "marginal" but not a CFBC
00250           // location, the following two lines are equaivalent to the "usual
00251           // case" below.
00252           rhs_uv[i][j].u = tdx - (aMM - aPP)*ocean_pressure / dx;
00253           rhs_uv[i][j].v = tdy - (bMM - bPP)*ocean_pressure / dy;
00254 
00255           continue;
00256         } // end of "if (is_marginal(i, j))"
00257 
00258         // If we reached this point, then CFBC are enabled, but we are in the
00259         // interior of a sheet or shelf. See "usual case" below.
00260 
00261       }   // end of "if (use_cfbc)"
00262 
00263       // usual case: use already computed driving stress
00264       rhs_uv[i][j].u = taud(i, j).u;
00265       rhs_uv[i][j].v = taud(i, j).v;
00266     }
00267   }
00268 
00269   if (use_cfbc) {
00270     ierr = thickness->end_access(); CHKERRQ(ierr);
00271     ierr = bed->end_access(); CHKERRQ(ierr);
00272     ierr = mask->end_access(); CHKERRQ(ierr);
00273   }
00274 
00275   if (vel_bc && bc_locations) {
00276     ierr = bc_locations->end_access(); CHKERRQ(ierr);
00277     ierr = vel_bc->end_access(); CHKERRQ(ierr);
00278   }
00279 
00280   ierr = taud.end_access(); CHKERRQ(ierr);
00281   ierr = DAVecRestoreArray(SSADA, rhs, &rhs_uv); CHKERRQ(ierr);
00282 
00283   return 0;
00284 }
00285 
00288 
00360 PetscErrorCode SSAFD::assemble_matrix(bool include_basal_shear, Mat A) {
00361   PetscErrorCode  ierr;
00362 
00363   const PetscScalar   dx=grid.dx, dy=grid.dy;
00364   const PetscScalar   beta_ice_free_bedrock = config.get("beta_ice_free_bedrock");
00365   const bool use_cfbc = config.get_flag("calving_front_stress_boundary_condition");
00366 
00367   // shortcut:
00368   IceModelVec2V &vel = velocity;
00369 
00370   ierr = MatZeroEntries(A); CHKERRQ(ierr);
00371 
00372   /* matrix assembly loop */
00373   
00374   ierr = nuH.begin_access(); CHKERRQ(ierr);
00375   ierr = tauc->begin_access(); CHKERRQ(ierr);
00376   ierr = vel.begin_access(); CHKERRQ(ierr);
00377   ierr = mask->begin_access(); CHKERRQ(ierr);
00378 
00379   Mask M;
00380 
00381   if (vel_bc && bc_locations) {
00382     ierr = bc_locations->begin_access(); CHKERRQ(ierr);
00383   }
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 
00388       // Handle the easy case: provided Dirichlet boundary conditions
00389       if (vel_bc && bc_locations && bc_locations->as_int(i,j) == 1) {
00390         // set diagonal entry to one (scaled); RHS entry will be known velocity;
00391         ierr = set_diagonal_matrix_entry(A, i, j, scaling); CHKERRQ(ierr); 
00392         continue;
00393       }
00394 
00395       /* Provide shorthand for the following staggered coefficients  nu H:
00396        *      c_n
00397        *  c_w     c_e
00398        *      c_s
00399        */
00400       const PetscScalar c_w = nuH(i-1,j,0);
00401       const PetscScalar c_e = nuH(i,j,0);
00402       const PetscScalar c_s = nuH(i,j-1,1);
00403       const PetscScalar c_n = nuH(i,j,1);
00404 
00405       // We use DAGetMatrix to obtain the SSA matrix, which means that all 18
00406       // non-zeros get allocated, even though we use only 13 (or 14). The
00407       // remaining 5 (or 4) coefficients are zeros, but we set them anyway,
00408       // because this makes the code easier to understand.
00409       const PetscInt sten = 18;
00410       MatStencil row, col[sten];
00411 
00412       PetscInt aMn = 1, aPn = 1, aMM = 1, aPP = 1, aMs = 1, aPs = 1;
00413       PetscInt bPw = 1, bPP = 1, bPe = 1, bMw = 1, bMM = 1, bMe = 1;
00414 
00415       PetscInt M_ij = mask->as_int(i,j);
00416 
00417       if (use_cfbc) {
00418         int
00419           // direct neighbors
00420           M_e = mask->as_int(i + 1,j),
00421           M_w = mask->as_int(i - 1,j),
00422           M_n = mask->as_int(i,j + 1),
00423           M_s = mask->as_int(i,j - 1),
00424           // "diagonal" neighbors
00425           M_ne = mask->as_int(i + 1,j + 1),
00426           M_se = mask->as_int(i + 1,j - 1),
00427           M_nw = mask->as_int(i - 1,j + 1),
00428           M_sw = mask->as_int(i - 1,j - 1);
00429 
00430         // Note: this sets velocities at both ice-free ocean and ice-free
00431         // bedrock to zero. This means that we need to set boundary conditions
00432         // at both ice/ice-free-ocean and ice/ice-free-bedrock interfaces below
00433         // to be consistent.
00434         if (M.ice_free(M_ij)) {
00435           ierr = set_diagonal_matrix_entry(A, i, j, scaling); CHKERRQ(ierr);
00436           continue;
00437         }
00438 
00439         if (is_marginal(i, j)) {
00440           // If at least one of the following four conditions is "true", we're
00441           // at a CFBC location.
00442           if (M.ice_free(M_e)) aPP = 0;
00443           if (M.ice_free(M_w)) aMM = 0;
00444           if (M.ice_free(M_n)) bPP = 0;
00445           if (M.ice_free(M_s)) bMM = 0;
00446 
00447           // decide whether to use centered or one-sided differences
00448           if (M.ice_free(M_n) || M.ice_free(M_ne)) aPn = 0;
00449           if (M.ice_free(M_e) || M.ice_free(M_ne)) bPe = 0;
00450           if (M.ice_free(M_e) || M.ice_free(M_se)) bMe = 0;
00451           if (M.ice_free(M_s) || M.ice_free(M_se)) aPs = 0;
00452           if (M.ice_free(M_s) || M.ice_free(M_sw)) aMs = 0;
00453           if (M.ice_free(M_w) || M.ice_free(M_sw)) bMw = 0;
00454           if (M.ice_free(M_w) || M.ice_free(M_nw)) bPw = 0;
00455           if (M.ice_free(M_n) || M.ice_free(M_nw)) aMn = 0;
00456         }
00457       } // end of "if (use_cfbc)"
00458 
00459       /* begin Maxima-generated code */
00460       const PetscReal dx2 = dx*dx, dy2 = dy*dy, d4 = 4*dx*dy, d2 = 2*dx*dy;
00461 
00462       /* Coefficients of the discretization of the first equation; u first, then v. */
00463       PetscReal eq1[] = {
00464         0,  -c_n*bPP/dy2,  0, 
00465         -4*c_w*aMM/dx2,  (c_n*bPP+c_s*bMM)/dy2+(4*c_e*aPP+4*c_w*aMM)/dx2,  -4*c_e*aPP/dx2, 
00466         0,  -c_s*bMM/dy2,  0, 
00467         c_w*aMM*bPw/d2+c_n*aMn*bPP/d4,  (c_n*aPn*bPP-c_n*aMn*bPP)/d4+(c_w*aMM*bPP-c_e*aPP*bPP)/d2,  -c_e*aPP*bPe/d2-c_n*aPn*bPP/d4, 
00468         (c_w*aMM*bMw-c_w*aMM*bPw)/d2+(c_n*aMM*bPP-c_s*aMM*bMM)/d4,  (c_n*aPP*bPP-c_n*aMM*bPP-c_s*aPP*bMM+c_s*aMM*bMM)/d4+(c_e*aPP*bPP-c_w*aMM*bPP-c_e*aPP*bMM+c_w*aMM*bMM)/d2,  (c_e*aPP*bPe-c_e*aPP*bMe)/d2+(c_s*aPP*bMM-c_n*aPP*bPP)/d4, 
00469         -c_w*aMM*bMw/d2-c_s*aMs*bMM/d4,  (c_s*aMs*bMM-c_s*aPs*bMM)/d4+(c_e*aPP*bMM-c_w*aMM*bMM)/d2,  c_e*aPP*bMe/d2+c_s*aPs*bMM/d4, 
00470       };
00471 
00472       /* Coefficients of the discretization of the second equation; u first, then v. */
00473       PetscReal eq2[] = {
00474         c_w*aMM*bPw/d4+c_n*aMn*bPP/d2,  (c_n*aPn*bPP-c_n*aMn*bPP)/d2+(c_w*aMM*bPP-c_e*aPP*bPP)/d4,  -c_e*aPP*bPe/d4-c_n*aPn*bPP/d2, 
00475         (c_w*aMM*bMw-c_w*aMM*bPw)/d4+(c_n*aMM*bPP-c_s*aMM*bMM)/d2,  (c_n*aPP*bPP-c_n*aMM*bPP-c_s*aPP*bMM+c_s*aMM*bMM)/d2+(c_e*aPP*bPP-c_w*aMM*bPP-c_e*aPP*bMM+c_w*aMM*bMM)/d4,  (c_e*aPP*bPe-c_e*aPP*bMe)/d4+(c_s*aPP*bMM-c_n*aPP*bPP)/d2, 
00476         -c_w*aMM*bMw/d4-c_s*aMs*bMM/d2,  (c_s*aMs*bMM-c_s*aPs*bMM)/d2+(c_e*aPP*bMM-c_w*aMM*bMM)/d4,  c_e*aPP*bMe/d4+c_s*aPs*bMM/d2, 
00477         0,  -4*c_n*bPP/dy2,  0, 
00478         -c_w*aMM/dx2,  (4*c_n*bPP+4*c_s*bMM)/dy2+(c_e*aPP+c_w*aMM)/dx2,  -c_e*aPP/dx2, 
00479         0,  -4*c_s*bMM/dy2,  0, 
00480       };
00481 
00482       /* i indices */
00483       const PetscInt I[] = {
00484         i-1,  i,  i+1, 
00485         i-1,  i,  i+1, 
00486         i-1,  i,  i+1, 
00487         i-1,  i,  i+1, 
00488         i-1,  i,  i+1, 
00489         i-1,  i,  i+1, 
00490       };
00491 
00492       /* j indices */
00493       const PetscInt J[] = {
00494         j+1,  j+1,  j+1, 
00495         j,  j,  j, 
00496         j-1,  j-1,  j-1, 
00497         j+1,  j+1,  j+1, 
00498         j,  j,  j, 
00499         j-1,  j-1,  j-1, 
00500       };
00501 
00502       /* component indices */
00503       const PetscInt C[] = {
00504         0,  0,  0, 
00505         0,  0,  0, 
00506         0,  0,  0, 
00507         1,  1,  1, 
00508         1,  1,  1, 
00509         1,  1,  1, 
00510       };
00511       /* end Maxima-generated code */
00512 
00513       /* Dragging ice experiences friction at the bed determined by the
00514        *    IceBasalResistancePlasticLaw::drag() methods.  These may be a plastic,
00515        *    pseudo-plastic, or linear friction law.  Dragging is done implicitly
00516        *    (i.e. on left side of SSA eqns).  */
00517       PetscReal beta = 0.0;
00518       if (include_basal_shear) {
00519         if (M.grounded_ice(M_ij)) {
00520           beta = basal.drag((*tauc)(i,j), vel(i,j).u, vel(i,j).v);
00521         } else if (M.ice_free_land(M_ij)) {
00522           // apply drag even in this case, to help with margins; note ice free
00523           // areas already have a strength extension
00524           beta = beta_ice_free_bedrock;
00525         }
00526       }
00527 
00528       // add beta to diagonal entries
00529       eq1[4]  += beta;
00530       eq2[13] += beta;
00531 
00532       // build equations: NOTE TRANSPOSE
00533       row.j = i; row.i = j;
00534       for (PetscInt m = 0; m < sten; m++) {
00535         col[m].j = I[m]; col[m].i = J[m]; col[m].c = C[m];
00536       }
00537 
00538       // set coefficients of the first equation:
00539       row.c = 0;
00540       ierr = MatSetValuesStencil(A, 1, &row, sten, col, eq1, INSERT_VALUES); CHKERRQ(ierr);
00541 
00542       // set coefficients of the second equation:
00543       row.c = 1;
00544       ierr = MatSetValuesStencil(A, 1, &row, sten, col, eq2, INSERT_VALUES); CHKERRQ(ierr);
00545     }
00546   }
00547 
00548   if (vel_bc && bc_locations) {
00549     ierr = bc_locations->end_access(); CHKERRQ(ierr);
00550   }
00551 
00552   ierr = mask->end_access(); CHKERRQ(ierr);
00553   ierr = vel.end_access(); CHKERRQ(ierr);
00554   ierr = tauc->end_access(); CHKERRQ(ierr);
00555   ierr = nuH.end_access(); CHKERRQ(ierr);
00556 
00557   ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
00558   ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
00559 #ifdef PISM_DEBUG
00560   ierr = MatSetOption(A,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
00561 #endif
00562 
00563   return 0;
00564 }
00565 
00566 
00569 
00612 PetscErrorCode SSAFD::solve() {
00613   PetscErrorCode ierr;
00614   Mat A = SSAStiffnessMatrix; // solve  A SSAX = SSARHS
00615   PetscReal   norm, normChange;
00616   PetscInt    ksp_iterations, outer_iterations;
00617   KSPConvergedReason  reason;
00618 
00619   stdout_ssa = "";
00620 
00621   bool write_ssa_system_to_matlab = config.get_flag("write_ssa_system_to_matlab");
00622   PetscReal ssaRelativeTolerance = config.get("ssafd_relative_convergence"),
00623             epsilon              = config.get("epsilon_ssafd");
00624 
00625   PetscInt ssaMaxIterations = static_cast<PetscInt>(config.get("max_iterations_ssafd"));
00626 
00627   ierr = velocity.copy_to(velocity_old); CHKERRQ(ierr);
00628 
00629   // computation of RHS only needs to be done once; does not depend on
00630   // solution; but matrix changes under nonlinear iteration (loop over k below)
00631   ierr = assemble_rhs(SSARHS); CHKERRQ(ierr);
00632 
00633   ierr = compute_hardav_staggered(hardness); CHKERRQ(ierr);
00634 
00635   for (PetscInt l=0; ; ++l) { // iterate with increasing regularization parameter
00636     ierr = compute_nuH_staggered(nuH, epsilon); CHKERRQ(ierr);
00637 
00638     ierr = update_nuH_viewers(); CHKERRQ(ierr);
00639     // iterate on effective viscosity: "outer nonlinear iteration":
00640     for (PetscInt k = 0; k < ssaMaxIterations; ++k) {
00641       if (getVerbosityLevel() > 2) {
00642         char tempstr[50] = "";  snprintf(tempstr,50, "  %d,%2d:", l, k);
00643         stdout_ssa += tempstr;
00644       }
00645 
00646       // in preparation of measuring change of effective viscosity:
00647       ierr = nuH.copy_to(nuH_old); CHKERRQ(ierr);
00648 
00649       // assemble (or re-assemble) matrix, which depends on updated viscosity
00650       ierr = assemble_matrix(true, A); CHKERRQ(ierr);
00651       if (getVerbosityLevel() > 2)
00652         stdout_ssa += "A:";
00653 
00654       // call PETSc to solve linear system by iterative method; "inner linear iteration"
00655       ierr = KSPSetOperators(SSAKSP, A, A, SAME_NONZERO_PATTERN); CHKERRQ(ierr);
00656       ierr = KSPSolve(SSAKSP, SSARHS, SSAX); CHKERRQ(ierr); // SOLVE
00657 
00658       // report to standard out about iteration
00659       ierr = KSPGetConvergedReason(SSAKSP, &reason); CHKERRQ(ierr);
00660       if (reason < 0) {
00661         ierr = verbPrintf(1,grid.com,
00662             "\n\n\nPISM ERROR:  KSPSolve() reports 'diverged'; reason = %d = '%s';\n"
00663                   "  see PETSc man page for KSPGetConvergedReason();   ENDING ...\n\n",
00664             reason,KSPConvergedReasons[reason]); CHKERRQ(ierr);
00665         PISMEnd();
00666       }
00667       ierr = KSPGetIterationNumber(SSAKSP, &ksp_iterations); CHKERRQ(ierr);
00668       if (getVerbosityLevel() > 2) {
00669         char tempstr[50] = "";  snprintf(tempstr,50, "S:%d,%d: ", ksp_iterations, reason);
00670         stdout_ssa += tempstr;
00671       }
00672 
00673       // Communicate so that we have stencil width for evaluation of effective
00674       //   viscosity on next "outer" iteration (and geometry etc. if done):
00675       ierr = velocity.copy_from(SSAX); CHKERRQ(ierr);
00676 
00677       ierr = velocity.beginGhostComm(); CHKERRQ(ierr);
00678       ierr = velocity.endGhostComm(); CHKERRQ(ierr);
00679 
00680       // update viscosity and check for viscosity convergence
00681       ierr = compute_nuH_staggered(nuH, epsilon); CHKERRQ(ierr);
00682       ierr = update_nuH_viewers(); CHKERRQ(ierr);
00683       ierr = compute_nuH_norm(norm, normChange); CHKERRQ(ierr);
00684       if (getVerbosityLevel() > 2) {
00685         char tempstr[100] = "";
00686         snprintf(tempstr,100, "|nu|_2, |Delta nu|_2/|nu|_2 = %10.3e %10.3e\n",
00687                          norm, normChange/norm);
00688         stdout_ssa += tempstr;
00689       }
00690 
00691       if (getVerbosityLevel() > 2) { // assume that high verbosity shows interest
00692                                      //   in immediate feedback about SSA iterations
00693         ierr = verbPrintf(2,grid.com, stdout_ssa.c_str()); CHKERRQ(ierr);
00694         stdout_ssa = "";
00695       }
00696 
00697       outer_iterations = k + 1;
00698       if (norm == 0 || normChange / norm < ssaRelativeTolerance) goto done;
00699 
00700     } // end of the "outer loop" (index: k)
00701 
00702     if (epsilon > 0.0) {
00703        // this has no units; epsilon goes up by this ratio when previous value failed
00704        const PetscScalar DEFAULT_EPSILON_MULTIPLIER_SSA = 4.0;
00705        ierr = verbPrintf(1,grid.com,
00706                          "WARNING: Effective viscosity not converged after %d iterations\n"
00707                          "\twith epsilon=%8.2e. Retrying with epsilon * %8.2e.\n",
00708                          ssaMaxIterations, epsilon, DEFAULT_EPSILON_MULTIPLIER_SSA);
00709        CHKERRQ(ierr);
00710 
00711        ierr = velocity.copy_from(velocity_old); CHKERRQ(ierr);
00712        epsilon *= DEFAULT_EPSILON_MULTIPLIER_SSA;
00713     } else {
00714        SETERRQ1(1,
00715          "Effective viscosity not converged after %d iterations; epsilon=0.0.\n"
00716          "  Stopping.\n",
00717          ssaMaxIterations);
00718     }
00719 
00720   } // end of the "outer outer loop" (index: l)
00721 
00722   done:
00723 
00724   if (getVerbosityLevel() > 2) {
00725     char tempstr[50] = "";
00726     snprintf(tempstr,50, "... =%5d outer iterations\n", outer_iterations);
00727     stdout_ssa += tempstr;
00728   } else if (getVerbosityLevel() == 2) {
00729     // at default verbosity, just record last normchange and iterations
00730     char tempstr[50] = "";
00731     snprintf(tempstr,50, "%5d outer iterations\n", outer_iterations);
00732     stdout_ssa += tempstr;
00733   }
00734   if (getVerbosityLevel() >= 2)
00735     stdout_ssa = "  SSA: " + stdout_ssa;
00736 
00737   if (write_ssa_system_to_matlab) {
00738     ierr = writeSSAsystemMatlab(); CHKERRQ(ierr);
00739   }
00740 
00741   return 0;
00742 }
00743 
00744 
00746 PetscErrorCode SSAFD::writeSSAsystemMatlab() {
00747   PetscErrorCode ierr;
00748   PetscViewer    viewer;
00749   char           file_name[PETSC_MAX_PATH_LEN], yearappend[PETSC_MAX_PATH_LEN];
00750 
00751   IceModelVec2S component;
00752   ierr = component.create(grid, "temp_storage", false); CHKERRQ(ierr);
00753 
00754   // FIXME: the file name prefix should be an option
00755   strcpy(file_name,"pism_SSAFD");
00756   snprintf(yearappend, PETSC_MAX_PATH_LEN, "_y%.0f.m", grid.year);
00757   strcat(file_name,yearappend);
00758   ierr = verbPrintf(2, grid.com,
00759              "writing Matlab-readable file for SSAFD system A xsoln = rhs to file `%s' ...\n",
00760              file_name); CHKERRQ(ierr);
00761   ierr = PetscViewerCreate(grid.com, &viewer);CHKERRQ(ierr);
00762   ierr = PetscViewerSetType(viewer, PETSC_VIEWER_ASCII);CHKERRQ(ierr);
00763   ierr = PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_MATLAB);CHKERRQ(ierr);
00764   ierr = PetscViewerFileSetName(viewer, file_name);CHKERRQ(ierr);
00765 
00766   // get the command which started the run
00767   string cmdstr = pism_args_string();
00768 
00769   // save linear system; gives system A xsoln = rhs at last (nonlinear) iteration of SSA
00770   ierr = PetscViewerASCIIPrintf(viewer,
00771     "%% A PISM linear system report for the finite difference implementation\n"
00772     "%% of the SSA stress balance from this run:\n"
00773     "%%   '%s'\n"
00774     "%% Writes matrix A (sparse), and vectors uv and rhs, for the linear\n"
00775     "%% system which was solved at the last step of the nonlinear iteration:\n"
00776     "%%    A * uv = rhs.\n"
00777     "%% Also writes the year, the coordinates x,y, their gridded versions\n"
00778     "%% xx,yy, and the thickness (thk) and surface elevation (usurf).\n"
00779     "%% Also writes i-offsetvalues of vertically-integrated viscosity\n"
00780     "%% (nuH_0 = nu * H), and j-offset version of same thing (nuH_1 = nu * H);\n"
00781     "%% these are on the staggered grid.\n",
00782     cmdstr.c_str());  CHKERRQ(ierr);
00783 
00784   ierr = PetscViewerASCIIPrintf(viewer,"\n\necho off\n");  CHKERRQ(ierr);
00785   ierr = PetscObjectSetName((PetscObject) SSAStiffnessMatrix,"A"); CHKERRQ(ierr);
00786   ierr = MatView(SSAStiffnessMatrix, viewer);CHKERRQ(ierr);
00787   ierr = PetscViewerASCIIPrintf(viewer,"clear zzz\n\n");  CHKERRQ(ierr);
00788 
00789   ierr = PetscObjectSetName((PetscObject) SSARHS,"rhs"); CHKERRQ(ierr);
00790   ierr = VecView(SSARHS, viewer);CHKERRQ(ierr);
00791   ierr = PetscObjectSetName((PetscObject) SSAX,"uv"); CHKERRQ(ierr);
00792   ierr = VecView(SSAX, viewer);CHKERRQ(ierr);
00793 
00794   // save coordinates (for viewing, primarily)
00795   ierr = PetscViewerASCIIPrintf(viewer,"\nyear=%10.6f;\n",grid.year);  CHKERRQ(ierr);
00796   ierr = PetscViewerASCIIPrintf(viewer,
00797             "x=%12.3f + (0:%d)*%12.3f;\n"
00798             "y=%12.3f + (0:%d)*%12.3f;\n",
00799             -grid.Lx,grid.Mx-1,grid.dx,-grid.Ly,grid.My-1,grid.dy); CHKERRQ(ierr);
00800   ierr = PetscViewerASCIIPrintf(viewer,"[xx,yy]=meshgrid(x,y);\n");  CHKERRQ(ierr);
00801 
00802   // also save thickness and effective viscosity
00803   ierr = thickness->view_matlab(viewer); CHKERRQ(ierr);
00804   ierr = surface->view_matlab(viewer); CHKERRQ(ierr);
00805 
00806   ierr = nuH.get_component(0, component); CHKERRQ(ierr);
00807   ierr = component.set_name("nuH_0"); CHKERRQ(ierr);
00808   ierr = component.set_attr("long_name",
00809     "effective viscosity times thickness (i offset) at current time step"); CHKERRQ(ierr);
00810   ierr = component.view_matlab(viewer); CHKERRQ(ierr);
00811 
00812   ierr = nuH.get_component(0, component); CHKERRQ(ierr);
00813   ierr = component.set_name("nuH_1"); CHKERRQ(ierr);
00814   ierr = component.set_attr("long_name",
00815     "effective viscosity times thickness (j offset) at current time step"); CHKERRQ(ierr);
00816   ierr = component.view_matlab(viewer); CHKERRQ(ierr);
00817 
00818   ierr = PetscViewerASCIIPrintf(viewer,"echo on\n");  CHKERRQ(ierr);
00819   ierr = PetscViewerDestroy(viewer);CHKERRQ(ierr);
00820 
00821   return 0;
00822 }
00823 
00825 
00837 PetscErrorCode SSAFD::compute_nuH_norm(PetscReal &norm, PetscReal &norm_change) {
00838   PetscErrorCode ierr;
00839 
00840   PetscReal nuNorm[2], nuChange[2];
00841 
00842   const PetscScalar area = grid.dx * grid.dy;
00843 #define MY_NORM     NORM_1
00844 
00845   // Test for change in nu
00846   ierr = nuH_old.add(-1, nuH); CHKERRQ(ierr);
00847 
00848   ierr = nuH_old.norm_all(MY_NORM, nuChange[0], nuChange[1]); CHKERRQ(ierr);
00849   ierr =     nuH.norm_all(MY_NORM, nuNorm[0],   nuNorm[1]);   CHKERRQ(ierr);
00850 
00851   nuChange[0] *= area;
00852   nuChange[1] *= area;
00853   nuNorm[0] *= area;
00854   nuNorm[1] *= area;
00855 
00856   norm_change = sqrt(PetscSqr(nuChange[0]) + PetscSqr(nuChange[1]));
00857   norm = sqrt(PetscSqr(nuNorm[0]) + PetscSqr(nuNorm[1]));
00858   return 0;
00859 }
00860 
00862 PetscErrorCode SSAFD::compute_hardav_staggered(IceModelVec2Stag &result) {
00863   PetscErrorCode ierr;
00864   PetscScalar *E, *E_ij, *E_offset;
00865 
00866   E = new PetscScalar[grid.Mz];
00867 
00868   ierr = thickness->begin_access(); CHKERRQ(ierr);
00869   ierr = enthalpy->begin_access(); CHKERRQ(ierr);
00870   ierr = result.begin_access(); CHKERRQ(ierr);
00871 
00872   for (PetscInt   i = grid.xs; i < grid.xs+grid.xm; ++i) {
00873     for (PetscInt j = grid.ys; j < grid.ys+grid.ym; ++j) {
00874       ierr = enthalpy->getInternalColumn(i,j,&E_ij); CHKERRQ(ierr);
00875       for (PetscInt o=0; o<2; o++) {
00876         const PetscInt oi = 1-o, oj=o;
00877         const PetscScalar H = 0.5 * ((*thickness)(i,j) + (*thickness)(i+oi,j+oj));
00878 
00879         if (H == 0) {
00880           result(i,j,o) = -1e6; // an obviously impossible value
00881           continue;
00882         }
00883 
00884         ierr = enthalpy->getInternalColumn(i+oi,j+oj,&E_offset); CHKERRQ(ierr);
00885         // build a column of enthalpy values a the current location:
00886         for (int k = 0; k < grid.Mz; ++k) {
00887           E[k] = 0.5 * (E_ij[k] + E_offset[k]);
00888         }
00889 
00890         result(i,j,o) = ice.averagedHardness_from_enth(H, grid.kBelowHeight(H),
00891                                                        grid.zlevels.data(), E); CHKERRQ(ierr);
00892       } // o
00893     }   // j
00894   }     // i
00895 
00896   ierr = result.end_access(); CHKERRQ(ierr);
00897   ierr = enthalpy->end_access(); CHKERRQ(ierr);
00898   ierr = thickness->end_access(); CHKERRQ(ierr);
00899 
00900   delete [] E;
00901   return 0;
00902 }
00903 
00906 
00948 PetscErrorCode SSAFD::compute_nuH_staggered(IceModelVec2Stag &result, PetscReal epsilon) {
00949   PetscErrorCode ierr;
00950   PISMVector2 **uv;
00951 
00952   ierr = result.begin_access(); CHKERRQ(ierr);
00953   ierr = velocity.get_array(uv); CHKERRQ(ierr);
00954   ierr = hardness.begin_access(); CHKERRQ(ierr);
00955   ierr = thickness->begin_access(); CHKERRQ(ierr);
00956 
00957   PetscScalar ssa_enhancement_factor=1.0;
00958 
00959   if (config.get_flag("do_ssa_enhancement"))
00960     ssa_enhancement_factor=config.get("ssa_enhancement_factor");
00961 
00962   const PetscScalar dx = grid.dx, dy = grid.dy;
00963 
00964   for (PetscInt o=0; o<2; ++o) {
00965     const PetscInt oi = 1 - o, oj=o;
00966     for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00967       for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00968 
00969         const PetscScalar H = 0.5 * ((*thickness)(i,j) + (*thickness)(i+oi,j+oj));
00970 
00971         if (H < strength_extension->get_min_thickness()) {
00972           // Extends strength of SSA (i.e. nuH coeff) into the ice free region.
00973           //  Does not add or subtract ice mass.
00974           result(i,j,o) = strength_extension->get_notional_strength();
00975           continue;
00976         }
00977 
00978         PetscScalar u_x, u_y, v_x, v_y;
00979         // Check the offset to determine how to differentiate velocity
00980         if (o == 0) {
00981           u_x = (uv[i+1][j].u - uv[i][j].u) / dx;
00982           u_y = (uv[i][j+1].u + uv[i+1][j+1].u - uv[i][j-1].u - uv[i+1][j-1].u) / (4*dy);
00983           v_x = (uv[i+1][j].v - uv[i][j].v) / dx;
00984           v_y = (uv[i][j+1].v + uv[i+1][j+1].v - uv[i][j-1].v - uv[i+1][j-1].v) / (4*dy);
00985         } else {
00986           u_x = (uv[i+1][j].u + uv[i+1][j+1].u - uv[i-1][j].u - uv[i-1][j+1].u) / (4*dx);
00987           u_y = (uv[i][j+1].u - uv[i][j].u) / dy;
00988           v_x = (uv[i+1][j].v + uv[i+1][j+1].v - uv[i-1][j].v - uv[i-1][j+1].v) / (4*dx);
00989           v_y = (uv[i][j+1].v - uv[i][j].v) / dy;
00990         }
00991 
00992         result(i,j,o) = H * ice.effectiveViscosity(hardness(i,j,o), u_x, u_y, v_x, v_y);
00993 
00994         if (! finite(result(i,j,o)) || false) {
00995           ierr = PetscPrintf(grid.com, "nuH[%d][%d][%d] = %e\n", o, i, j, result(i,j,o));
00996           CHKERRQ(ierr);
00997           ierr = PetscPrintf(grid.com, "  u_x, u_y, v_x, v_y = %e, %e, %e, %e\n",
00998                              u_x, u_y, v_x, v_y);
00999           CHKERRQ(ierr);
01000         }
01001 
01002         // We ensure that nuH is bounded below by a positive constant.
01003         result(i,j,o) += epsilon;
01004 
01005         // include the SSA enhancement factor; in most cases ssa_enhancement_factor is 1
01006         result(i,j,o) /= ssa_enhancement_factor;
01007 
01008       } // j
01009     } // i
01010   } // o
01011 
01012   ierr = thickness->end_access(); CHKERRQ(ierr);
01013   ierr = hardness.end_access(); CHKERRQ(ierr);
01014   ierr = result.end_access(); CHKERRQ(ierr);
01015   ierr = velocity.end_access(); CHKERRQ(ierr);
01016 
01017   // Some communication
01018   ierr = result.beginGhostComm(); CHKERRQ(ierr);
01019   ierr = result.endGhostComm(); CHKERRQ(ierr);
01020   return 0;
01021 }
01022 
01023 
01025 PetscErrorCode SSAFD::update_nuH_viewers() {
01026   PetscErrorCode ierr;
01027   IceModelVec2S tmp;
01028 
01029   if (!view_nuh) return 0;
01030 
01031   ierr = tmp.create(grid, "nuH", false); CHKERRQ(ierr);
01032   ierr = tmp.set_attrs("temporary",
01033                        "log10 of (viscosity * thickness)",
01034                        "Pa s m", ""); CHKERRQ(ierr);
01035 
01036   ierr = nuH.begin_access(); CHKERRQ(ierr);
01037   ierr = tmp.begin_access(); CHKERRQ(ierr);
01038 
01039   for (PetscInt   i = grid.xs; i < grid.xs+grid.xm; ++i) {
01040     for (PetscInt j = grid.ys; j < grid.ys+grid.ym; ++j) {
01041       PetscReal avg_nuH = 0.5 * (nuH(i,j,0) + nuH(i,j,1));
01042         if (avg_nuH > 1.0e14) {
01043           tmp(i,j) = log10(avg_nuH);
01044         } else {
01045           tmp(i,j) = 14.0;
01046         }
01047     }
01048   }
01049 
01050   ierr = tmp.end_access(); CHKERRQ(ierr);
01051   ierr = nuH.end_access(); CHKERRQ(ierr);
01052 
01053   if (nuh_viewer == PETSC_NULL) {
01054     ierr = grid.create_viewer(nuh_viewer_size, "nuH", nuh_viewer); CHKERRQ(ierr);
01055   }
01056 
01057   ierr = tmp.view(nuh_viewer, PETSC_NULL); CHKERRQ(ierr);
01058 
01059   return 0;
01060 }
01061 
01062 PetscErrorCode SSAFD::set_diagonal_matrix_entry(Mat A, int i, int j,
01063                                                 PetscScalar value) {
01064   PetscErrorCode ierr;
01065   MatStencil row, col;
01066   row.j = i; row.i = j;
01067   col.j = i; col.i = j;
01068 
01069   row.c = 0; col.c = 0;
01070   ierr = MatSetValuesStencil(A, 1, &row, 1, &col, &value, INSERT_VALUES); CHKERRQ(ierr);
01071 
01072   row.c = 1; col.c = 1;
01073   ierr = MatSetValuesStencil(A, 1, &row, 1, &col, &value, INSERT_VALUES); CHKERRQ(ierr);
01074 
01075   return 0;
01076 }
01077 
01079 
01092 bool SSAFD::is_marginal(int i, int j) {
01093   const PetscInt M_ij = mask->as_int(i,j),
01094     // direct neighbors
01095     M_e = mask->as_int(i + 1,j),
01096     M_w = mask->as_int(i - 1,j),
01097     M_n = mask->as_int(i,j + 1),
01098     M_s = mask->as_int(i,j - 1),
01099     // "diagonal" neighbors
01100     M_ne = mask->as_int(i + 1,j + 1),
01101     M_se = mask->as_int(i + 1,j - 1),
01102     M_nw = mask->as_int(i - 1,j + 1),
01103     M_sw = mask->as_int(i - 1,j - 1);
01104 
01105   Mask M;
01106   
01107   return (!M.ice_free(M_ij)) &&
01108     (M.ice_free(M_e) || M.ice_free(M_w) || M.ice_free(M_n) || M.ice_free(M_s) ||
01109      M.ice_free(M_ne) || M.ice_free(M_se) || M.ice_free(M_nw) || M.ice_free(M_sw));
01110 }
01111 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines