|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 // Copyright (C) 2010, 2011 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 "PISMBedSmoother.hh" 00020 #include "Mask.hh" 00021 00022 00023 PISMBedSmoother::PISMBedSmoother( 00024 IceGrid &g, const NCConfigVariable &conf, PetscInt MAX_GHOSTS) 00025 : grid(g), config(conf), maxGHOSTS(MAX_GHOSTS) { 00026 00027 if (allocate() != 0) { 00028 PetscPrintf(grid.com, "PISMBedSmoother constructor: allocate() failed\n"); 00029 PISMEnd(); 00030 } 00031 00032 if (config.get("bed_smoother_range") > 0.0) { 00033 verbPrintf(2, grid.com, 00034 "* Initializing bed smoother object with %.3f km half-width ...\n", 00035 config.get("bed_smoother_range") / 1000.0); 00036 } 00037 00038 } 00039 00040 00041 PISMBedSmoother::~PISMBedSmoother() { 00042 00043 if (deallocate() != 0) { 00044 PetscPrintf(grid.com, "PISMBedSmoother destructor: deallocate() failed\n"); 00045 PISMEnd(); 00046 } 00047 } 00048 00049 00050 /* the following is from the PETSc FAQ page: 00051 00052 How do I collect all the values from a parallel PETSc vector into a vector 00053 on the zeroth processor? 00054 00055 * Create the scatter context that will do the communication 00056 o VecScatterCreateToZero(v,&ctx,&w); 00057 * Actually do the communication; this can be done repeatedly as needed 00058 o VecScatterBegin(ctx,v,w,INSERT_VALUES,SCATTER_FORWARD); 00059 o VecScatterEnd(ctx,v,w,INSERT_VALUES,SCATTER_FORWARD); 00060 * Remember to free the scatter context when no longer needed 00061 o VecScatterDestroy(ctx); 00062 00063 Note that this simply concatenates in the parallel ordering of the vector. 00064 If you are using a vector from DACreateGlobalVector() you likely want to 00065 first call DAGlobalToNaturalBegin/End() to scatter the original vector into 00066 the natural ordering in a new global vector before calling 00067 VecScatterBegin/End() to scatter the natural vector onto process 0. 00068 */ 00069 00070 00071 PetscErrorCode PISMBedSmoother::allocate() { 00072 PetscErrorCode ierr; 00073 00074 ierr = DACreateGlobalVector(grid.da2, &g2); CHKERRQ(ierr); 00075 00076 // note we want a global Vec but reordered in the natural ordering so when it 00077 // is scattered to proc zero it is not all messed up; see above 00078 ierr = DACreateNaturalVector(grid.da2, &g2natural); CHKERRQ(ierr); 00079 // next get scatter context *and* allocate one of Vecs on proc zero 00080 ierr = VecScatterCreateToZero(g2natural, &scatter, &topgp0); CHKERRQ(ierr); 00081 00082 // allocate Vecs that live on proc 0 00083 ierr = VecDuplicate(topgp0,&topgsmoothp0); CHKERRQ(ierr); 00084 ierr = VecDuplicate(topgp0,&maxtlp0); CHKERRQ(ierr); 00085 ierr = VecDuplicate(topgp0,&C2p0); CHKERRQ(ierr); 00086 ierr = VecDuplicate(topgp0,&C3p0); CHKERRQ(ierr); 00087 ierr = VecDuplicate(topgp0,&C4p0); CHKERRQ(ierr); 00088 00089 // allocate Vecs that live on all procs; all have to be as "wide" as any of 00090 // their prospective uses 00091 ierr = topgsmooth.create(grid, "topgsmooth", true, maxGHOSTS); CHKERRQ(ierr); 00092 ierr = topgsmooth.set_attrs( 00093 "bed_smoother_tool", 00094 "smoothed bed elevation, in bed roughness parameterization", 00095 "m", ""); CHKERRQ(ierr); 00096 ierr = maxtl.create(grid, "maxtl", true, maxGHOSTS); CHKERRQ(ierr); 00097 ierr = maxtl.set_attrs( 00098 "bed_smoother_tool", 00099 "maximum elevation in local topography patch, in bed roughness parameterization", 00100 "m", ""); CHKERRQ(ierr); 00101 ierr = C2.create(grid, "C2bedsmooth", true, maxGHOSTS); CHKERRQ(ierr); 00102 ierr = C2.set_attrs( 00103 "bed_smoother_tool", 00104 "polynomial coeff of H^-2, in bed roughness parameterization", 00105 "m2", ""); CHKERRQ(ierr); 00106 ierr = C3.create(grid, "C3bedsmooth", true, maxGHOSTS); CHKERRQ(ierr); 00107 ierr = C3.set_attrs( 00108 "bed_smoother_tool", 00109 "polynomial coeff of H^-3, in bed roughness parameterization", 00110 "m3", ""); CHKERRQ(ierr); 00111 ierr = C4.create(grid, "C4bedsmooth", true, maxGHOSTS); CHKERRQ(ierr); 00112 ierr = C4.set_attrs( 00113 "bed_smoother_tool", 00114 "polynomial coeff of H^-4, in bed roughness parameterization", 00115 "m4", ""); CHKERRQ(ierr); 00116 return 0; 00117 } 00118 00119 00120 PetscErrorCode PISMBedSmoother::deallocate() { 00121 PetscErrorCode ierr; 00122 00123 ierr = VecDestroy(g2); CHKERRQ(ierr); 00124 ierr = VecDestroy(g2natural); CHKERRQ(ierr); 00125 ierr = VecScatterDestroy(scatter); CHKERRQ(ierr); 00126 00127 ierr = VecDestroy(topgp0); CHKERRQ(ierr); 00128 ierr = VecDestroy(topgsmoothp0); CHKERRQ(ierr); 00129 ierr = VecDestroy(maxtlp0); CHKERRQ(ierr); 00130 ierr = VecDestroy(C2p0); CHKERRQ(ierr); 00131 ierr = VecDestroy(C3p0); CHKERRQ(ierr); 00132 ierr = VecDestroy(C4p0); CHKERRQ(ierr); 00133 // no need to destroy topgsmooth,maxtl,C2,C3,C4; their destructors do it 00134 return 0; 00135 } 00136 00137 00143 PetscErrorCode PISMBedSmoother::preprocess_bed( 00144 IceModelVec2S topg, PetscReal n, PetscReal lambda) { 00145 PetscErrorCode ierr; 00146 00147 if (lambda <= 0.0) { 00148 // smoothing completely inactive. we transfer the original bed topg, 00149 // including ghosts, to public member topgsmooth ... 00150 ierr = topg.beginGhostComm(topgsmooth); CHKERRQ(ierr); 00151 ierr = topg.endGhostComm(topgsmooth); CHKERRQ(ierr); 00152 // and we tell get_theta() to return theta=1 00153 Nx = -1; 00154 Ny = -1; 00155 return 0; 00156 } 00157 00158 // determine Nx, Ny, which are always at least one if lambda > 0 00159 Nx = static_cast<PetscInt>(ceil(lambda / grid.dx)); 00160 Ny = static_cast<PetscInt>(ceil(lambda / grid.dy)); 00161 if (Nx < 1) Nx = 1; 00162 if (Ny < 1) Ny = 1; 00163 //PetscPrintf(grid.com,"PISMBedSmoother: Nx = %d, Ny = %d\n",Nx,Ny); 00164 00165 ierr = preprocess_bed(topg, n, Nx, Ny); CHKERRQ(ierr); 00166 return 0; 00167 } 00168 00169 00174 PetscErrorCode PISMBedSmoother::preprocess_bed( 00175 IceModelVec2S topg, PetscReal n, PetscInt Nx_in, PetscInt Ny_in) { 00176 PetscErrorCode ierr; 00177 00178 if ((Nx_in >= grid.Mx) || (Ny_in >= grid.My)) { 00179 SETERRQ(1,"PISM ERROR: input Nx, Ny in bed smoother is too large because\n" 00180 " domain of smoothing exceeds IceGrid domain\n"); 00181 } 00182 Nx = Nx_in; Ny = Ny_in; 00183 00184 if ((Nx < 0) || (Ny < 0)) { 00185 // smoothing completely inactive. we transfer the original bed topg, 00186 // including ghosts, to public member topgsmooth ... 00187 ierr = topg.beginGhostComm(topgsmooth); CHKERRQ(ierr); 00188 ierr = topg.endGhostComm(topgsmooth); CHKERRQ(ierr); 00189 return 0; 00190 } 00191 00192 ierr = topg.put_on_proc0(topgp0, scatter, g2, g2natural); CHKERRQ(ierr); 00193 ierr = smooth_the_bed_on_proc0(); CHKERRQ(ierr); 00194 // next call *does indeed* fill ghosts in topgsmooth 00195 ierr = topgsmooth.get_from_proc0(topgsmoothp0, scatter, g2, g2natural); CHKERRQ(ierr); 00196 00197 ierr = compute_coefficients_on_proc0(n); CHKERRQ(ierr); 00198 // following calls *do* fill the ghosts 00199 ierr = maxtl.get_from_proc0(maxtlp0, scatter, g2, g2natural); CHKERRQ(ierr); 00200 ierr = C2.get_from_proc0(C2p0, scatter, g2, g2natural); CHKERRQ(ierr); 00201 ierr = C3.get_from_proc0(C3p0, scatter, g2, g2natural); CHKERRQ(ierr); 00202 ierr = C4.get_from_proc0(C4p0, scatter, g2, g2natural); CHKERRQ(ierr); 00203 return 0; 00204 } 00205 00206 00210 PetscErrorCode PISMBedSmoother::get_smoothing_domain(PetscInt &Nx_out, PetscInt &Ny_out) { 00211 Nx_out = Nx; 00212 Ny_out = Ny; 00213 return 0; 00214 } 00215 00216 00218 PetscErrorCode PISMBedSmoother::smooth_the_bed_on_proc0() { 00219 00220 if (grid.rank == 0) { 00221 PetscErrorCode ierr; 00222 PetscScalar **b0, **bs; 00223 ierr = VecGetArray2d(topgp0, grid.Mx, grid.My, 0, 0, &b0); CHKERRQ(ierr); 00224 ierr = VecGetArray2d(topgsmoothp0, grid.Mx, grid.My, 0, 0, &bs); CHKERRQ(ierr); 00225 00226 for (PetscInt i=0; i < grid.Mx; i++) { 00227 for (PetscInt j=0; j < grid.My; j++) { 00228 // average only over those points which are in the grid; do not wrap 00229 // periodically 00230 PetscReal sum = 0.0; 00231 PetscInt count = 0; 00232 for (PetscInt r = -Nx; r <= Nx; r++) { 00233 for (PetscInt s = -Ny; s <= Ny; s++) { 00234 if ((i+r >= 0) && (i+r < grid.Mx) && (j+s >= 0) && (j+s < grid.My)) { 00235 sum += b0[i+r][j+s]; 00236 count++; 00237 } 00238 } 00239 } 00240 bs[i][j] = sum / static_cast<PetscReal>(count); 00241 } 00242 } 00243 00244 ierr = VecRestoreArray2d(topgsmoothp0, grid.Mx, grid.My, 0, 0, &bs); CHKERRQ(ierr); 00245 ierr = VecRestoreArray2d(topgp0, grid.Mx, grid.My, 0, 0, &b0); CHKERRQ(ierr); 00246 } 00247 00248 return 0; 00249 } 00250 00251 00252 PetscErrorCode PISMBedSmoother::compute_coefficients_on_proc0(PetscReal n) { 00253 00254 if (grid.rank == 0) { 00255 PetscErrorCode ierr; 00256 PetscScalar **b0, **bs, **c2, **c3, **c4, **mt; 00257 ierr = VecGetArray2d(topgp0, grid.Mx, grid.My, 0, 0, &b0); CHKERRQ(ierr); 00258 ierr = VecGetArray2d(topgsmoothp0, grid.Mx, grid.My, 0, 0, &bs); CHKERRQ(ierr); 00259 ierr = VecGetArray2d(maxtlp0, grid.Mx, grid.My, 0, 0, &mt); CHKERRQ(ierr); 00260 ierr = VecGetArray2d(C2p0, grid.Mx, grid.My, 0, 0, &c2); CHKERRQ(ierr); 00261 ierr = VecGetArray2d(C3p0, grid.Mx, grid.My, 0, 0, &c3); CHKERRQ(ierr); 00262 ierr = VecGetArray2d(C4p0, grid.Mx, grid.My, 0, 0, &c4); CHKERRQ(ierr); 00263 00264 for (PetscInt i=0; i < grid.Mx; i++) { 00265 for (PetscInt j=0; j < grid.My; j++) { 00266 // average only over those points which are in the grid 00267 // do not wrap periodically 00268 PetscReal topgs = bs[i][j], 00269 maxtltemp = 0.0, 00270 sum2 = 0.0, 00271 sum3 = 0.0, 00272 sum4 = 0.0; 00273 PetscInt count = 0; 00274 for (PetscInt r = -Nx; r <= Nx; r++) { 00275 for (PetscInt s = -Ny; s <= Ny; s++) { 00276 if ((i+r >= 0) && (i+r < grid.Mx) && (j+s >= 0) && (j+s < grid.My)) { 00277 // tl is elevation of local topography at a pt in patch 00278 const PetscReal tl = b0[i+r][j+s] - topgs; 00279 maxtltemp = PetscMax(maxtltemp, tl); 00280 // accumulate 2nd, 3rd, and 4th powers with only 3 mults 00281 const PetscReal tl2 = tl * tl; 00282 sum2 += tl2; 00283 sum3 += tl2 * tl; 00284 sum4 += tl2 * tl2; 00285 count++; 00286 } 00287 } 00288 } 00289 mt[i][j] = maxtltemp; 00290 // unprotected division by count but r=0,s=0 case guarantees count>=1 00291 c2[i][j] = sum2 / static_cast<PetscReal>(count); 00292 c3[i][j] = sum3 / static_cast<PetscReal>(count); 00293 c4[i][j] = sum4 / static_cast<PetscReal>(count); 00294 } 00295 } 00296 00297 ierr = VecRestoreArray2d(C4p0, grid.Mx, grid.My, 0, 0, &c4); CHKERRQ(ierr); 00298 ierr = VecRestoreArray2d(C3p0, grid.Mx, grid.My, 0, 0, &c3); CHKERRQ(ierr); 00299 ierr = VecRestoreArray2d(C2p0, grid.Mx, grid.My, 0, 0, &c2); CHKERRQ(ierr); 00300 ierr = VecRestoreArray2d(maxtlp0, grid.Mx, grid.My, 0, 0, &mt); CHKERRQ(ierr); 00301 ierr = VecRestoreArray2d(topgsmoothp0, grid.Mx, grid.My, 0, 0, &bs); CHKERRQ(ierr); 00302 ierr = VecRestoreArray2d(topgp0, grid.Mx, grid.My, 0, 0, &b0); CHKERRQ(ierr); 00303 00304 // scale the coeffs in Taylor series 00305 const PetscReal 00306 k = (n + 2) / n, 00307 s2 = k * (2 * n + 2) / (2 * n), 00308 s3 = s2 * (3 * n + 2) / (3 * n), 00309 s4 = s3 * (4 * n + 2) / (4 * n); 00310 ierr = VecScale(C2p0,s2); CHKERRQ(ierr); 00311 ierr = VecScale(C3p0,s3); CHKERRQ(ierr); 00312 ierr = VecScale(C4p0,s4); CHKERRQ(ierr); 00313 } 00314 00315 return 0; 00316 } 00317 00318 00320 00333 PetscErrorCode PISMBedSmoother::get_smoothed_thk(IceModelVec2S usurf, 00334 IceModelVec2S thk, 00335 IceModelVec2Int mask, 00336 PetscInt GHOSTS, 00337 IceModelVec2S *thksmooth) { 00338 PetscErrorCode ierr; 00339 00340 MaskQuery M(mask); 00341 00342 if (GHOSTS > maxGHOSTS) { 00343 SETERRQ2(1,"PISM ERROR: PISMBedSmoother fields do not have stencil\n" 00344 " width sufficient to fill thksmooth with GHOSTS=%d;\n" 00345 " construct PISMBedSmoother with MAX_GHOSTS>=%d\n", 00346 GHOSTS,GHOSTS); 00347 } 00348 00349 PetscScalar **thks; 00350 ierr = mask.begin_access(); CHKERRQ(ierr); 00351 ierr = topgsmooth.begin_access(); CHKERRQ(ierr); 00352 ierr = maxtl.begin_access(); CHKERRQ(ierr); 00353 ierr = usurf.begin_access(); CHKERRQ(ierr); 00354 ierr = thk.begin_access(); CHKERRQ(ierr); 00355 ierr = thksmooth->get_array(thks); CHKERRQ(ierr); 00356 for (PetscInt i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) { 00357 for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) { 00358 if (thk(i,j) < 0.0) { 00359 SETERRQ2(2, 00360 "PISM ERROR: PISMBedSmoother detects negative original thickness\n" 00361 " at location (i,j) = (%d,%d) ... ending\n",i,j); 00362 } else if (thk(i,j) == 0.0) { 00363 thks[i][j] = 0.0; 00364 } else if (maxtl(i,j) >= thk(i,j)) { 00365 thks[i][j] = thk(i,j); 00366 } else { 00367 if (M.grounded(i,j)) { 00368 // if grounded, compute smoothed thickness as the difference of ice 00369 // surface elevation and smoothed bed elevation 00370 const PetscScalar thks_try = usurf(i,j) - topgsmooth(i,j); 00371 thks[i][j] = (thks_try > 0.0) ? thks_try : 0.0; 00372 } else { 00373 // if floating, use original thickness (note: surface elevation was 00374 // computed using this thickness and the sea level elevation) 00375 thks[i][j] = thk(i,j); 00376 } 00377 } 00378 } 00379 } 00380 ierr = topgsmooth.end_access(); CHKERRQ(ierr); 00381 ierr = maxtl.end_access(); CHKERRQ(ierr); 00382 ierr = usurf.end_access(); CHKERRQ(ierr); 00383 ierr = thk.end_access(); CHKERRQ(ierr); 00384 ierr = thksmooth->end_access(); CHKERRQ(ierr); 00385 ierr = mask.end_access(); CHKERRQ(ierr); 00386 00387 return 0; 00388 } 00389 00390 00412 PetscErrorCode PISMBedSmoother::get_theta( 00413 IceModelVec2S usurf, PetscReal n, 00414 PetscInt GHOSTS, IceModelVec2S *theta) { 00415 PetscErrorCode ierr; 00416 00417 if (GHOSTS > maxGHOSTS) { 00418 SETERRQ2(1, 00419 "PISM ERROR: PISMBedSmoother::topgsmooth,maxtl,C2,C3,C4 do not have stencil\n" 00420 " width sufficient to fill theta with GHOSTS=%d; construct PISMBedSmoother\n" 00421 " with MAX_GHOSTS>=%d\n", GHOSTS,GHOSTS); 00422 } 00423 00424 if ((Nx < 0) || (Ny < 0)) { 00425 ierr = theta->set(1.0); CHKERRQ(ierr); 00426 return 0; 00427 } 00428 00429 PetscScalar **mytheta; 00430 ierr = theta->get_array(mytheta); CHKERRQ(ierr); 00431 ierr = usurf.begin_access(); CHKERRQ(ierr); 00432 ierr = topgsmooth.begin_access(); CHKERRQ(ierr); 00433 ierr = maxtl.begin_access(); CHKERRQ(ierr); 00434 ierr = C2.begin_access(); CHKERRQ(ierr); 00435 ierr = C3.begin_access(); CHKERRQ(ierr); 00436 ierr = C4.begin_access(); CHKERRQ(ierr); 00437 for (PetscInt i = grid.xs - GHOSTS; i < grid.xs+grid.xm + GHOSTS; ++i) { 00438 for (PetscInt j = grid.ys - GHOSTS; j < grid.ys+grid.ym + GHOSTS; ++j) { 00439 const PetscScalar H = usurf(i,j) - topgsmooth(i,j); 00440 if (H > maxtl(i,j)) { 00441 // thickness exceeds maximum variation in patch of local topography, 00442 // so ice buries local topography; note maxtl >= 0 always 00443 const PetscReal Hinv = 1.0 / H; 00444 PetscReal omega; 00445 omega = 1.0 + Hinv*Hinv * ( C2(i,j) + Hinv * ( C3(i,j) + Hinv*C4(i,j) ) ); 00446 if (omega <= 0) { // this check *should not* be necessary: p4(s) > 0 00447 SETERRQ2(1,"PISM ERROR: omega is negative for i=%d,j=%d\n" 00448 " in PISMBedSmoother.get_theta() ... ending\n",i,j); 00449 } 00450 if (omega < 0.001) omega = 0.001; 00451 mytheta[i][j] = pow(omega,-n); 00452 // now guarantee in [0,1]; this check *should not* be necessary, by convexity of p4 00453 if (mytheta[i][j] > 1.0) mytheta[i][j] = 1.0; 00454 if (mytheta[i][j] < 0.0) mytheta[i][j] = 0.0; 00455 } else { 00456 mytheta[i][j] = 0.00; // FIXME = min_theta; make configurable 00457 } 00458 } 00459 } 00460 ierr = C4.end_access(); CHKERRQ(ierr); 00461 ierr = C3.end_access(); CHKERRQ(ierr); 00462 ierr = C2.end_access(); CHKERRQ(ierr); 00463 ierr = maxtl.end_access(); CHKERRQ(ierr); 00464 ierr = topgsmooth.end_access(); CHKERRQ(ierr); 00465 ierr = usurf.end_access(); CHKERRQ(ierr); 00466 ierr = theta->end_access(); CHKERRQ(ierr); 00467 00468 return 0; 00469 } 00470
1.7.3