|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
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
1.7.3