PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/stressbalance/PISMBedSmoother.cc

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