PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/earth/deformation.cc

Go to the documentation of this file.
00001 // Copyright (C) 2004-2009, 2011 Ed Bueler
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 <cmath>
00020 #include <petscvec.h>
00021 #include "pism_const.hh"
00022 #include "matlablike.hh"
00023 #include "greens.hh"
00024 
00025 #if (PISM_HAVE_FFTW)
00026 #include <fftw3.h>
00027 #endif
00028 
00029 #include "deformation.hh"
00030 
00031 
00032 BedDeformLC::BedDeformLC() {
00033   settingsDone = PETSC_FALSE;
00034   allocDone = PETSC_FALSE;
00035 }
00036 
00037 
00038 BedDeformLC::~BedDeformLC() {
00039   if (allocDone == PETSC_TRUE) {
00040 #if (PISM_HAVE_FFTW)
00041     fftw_destroy_plan(bdplanfor);
00042     fftw_destroy_plan(bdplanback);
00043     fftw_free(bdin);
00044     fftw_free(bdout);
00045 #endif
00046     VecDestroy(Hdiff);
00047     VecDestroy(dbedElastic);
00048     VecDestroy(platefat);
00049     VecDestroy(plateoffset);
00050     VecDestroy(vleft);
00051     VecDestroy(vright);
00052     VecDestroy(lrmE);
00053     delete [] cx;  delete [] cy;
00054   }
00055   allocDone = PETSC_FALSE;
00056 }
00057 
00058 
00059 PetscErrorCode BedDeformLC::settings(const NCConfigVariable &config,
00060                   PetscTruth  myinclude_elastic,
00061                   PetscInt myMx, PetscInt myMy, PetscScalar mydx, PetscScalar mydy,
00062                   PetscInt myZ, PetscScalar myicerho,
00063                   Vec* myHstart, Vec* mybedstart, Vec* myuplift, 
00064                   Vec* myH, Vec* mybed) {
00065 
00066   // set parameters
00067   include_elastic = myinclude_elastic;
00068   Mx     = myMx;
00069   My     = myMy;
00070   dx     = mydx;
00071   dy     = mydy;
00072   Z      = myZ; 
00073   icerho = myicerho;
00074   rho    = config.get("lithosphere_density");
00075   eta    = config.get("mantle_viscosity");
00076   D      = config.get("lithosphere_flexural_rigidity");
00077 
00078   standard_gravity = config.get("standard_gravity");
00079 
00080   // derive more parameters
00081   Lx     = ((Mx-1)/2) * dx;
00082   Ly     = ((My-1)/2) * dy; 
00083   Nx     = Z*(Mx-1);
00084   Ny     = Z*(My-1);      
00085   fatLx  = (Nx/2) * dx;
00086   fatLy  = (Ny/2) * dy; 
00087   Nxge   = Nx + 1;
00088   Nyge   = Ny + 1;
00089   i0_plate = (Z-1)*(Mx-1)/2;
00090   j0_plate = (Z-1)*(My-1)/2;
00091   
00092   // attach to existing (must be allocated!) sequential Vecs
00093   H        = myH;
00094   bed      = mybed;
00095   Hstart   = myHstart;
00096   bedstart   = mybedstart;
00097   uplift   = myuplift;
00098 
00099   settingsDone = PETSC_TRUE;
00100   return 0;
00101 }
00102 
00103 
00104 PetscErrorCode BedDeformLC::alloc() {
00105   PetscErrorCode  ierr;
00106   if (settingsDone == PETSC_FALSE) {
00107     SETERRQ(1,"BedDeformLC must be set with settings() before alloc()\n");
00108   }
00109   if (allocDone == PETSC_TRUE) {
00110     SETERRQ(2,"BedDeformLC already allocated\n");
00111   }
00112 #if (PISM_HAVE_FFTW==0)
00113   SETERRQ(3,"BedDeformLC will not work without FFTW");
00114 #endif
00115 
00116   ierr = VecDuplicate(*H,&Hdiff); CHKERRQ(ierr);  // allocate working space
00117   ierr = VecDuplicate(*H,&dbedElastic); CHKERRQ(ierr);  // allocate working space
00118   
00119   // allocate plate displacement
00120   ierr = VecCreateSeq(PETSC_COMM_SELF, Nx * Ny, &platefat); CHKERRQ(ierr);
00121   ierr = VecDuplicate(platefat,&plateoffset); CHKERRQ(ierr);
00122   // FFT-side coefficient fields (i.e. multiplication form of operators)
00123   ierr = VecDuplicate(platefat,&vleft); CHKERRQ(ierr);
00124   ierr = VecDuplicate(platefat,&vright); CHKERRQ(ierr);
00125   ierr = VecCreateSeq(PETSC_COMM_SELF, Nxge * Nyge, &lrmE); CHKERRQ(ierr);
00126 
00127   // setup fftw stuff: FFTW builds "plans" based on observed performance
00128 #if (PISM_HAVE_FFTW)
00129   bdin = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * Nx * Ny);
00130   bdout = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * Nx * Ny);
00131          
00132   // fftw manipulates the data in setting up a plan, so fill with nonconstant junk
00133   for (PetscInt i=0; i < Nx; i++) {
00134     for (PetscInt j=0; j < Ny; j++) {
00135        bdin[j + Ny * i][0] = static_cast<double>(i-3);
00136        bdin[j + Ny * i][1] = static_cast<double>(j*j+2);
00137     }
00138   }
00139   bdplanfor  = fftw_plan_dft_2d(Nx, Ny, bdin, bdout, FFTW_FORWARD, FFTW_MEASURE);
00140   bdplanback = fftw_plan_dft_2d(Nx, Ny, bdin, bdout, FFTW_BACKWARD, FFTW_MEASURE);
00141 #endif 
00142   
00143   // coeffs for Fourier spectral method Laplacian
00144   // Matlab version:  cx=(pi/Lx)*[0:Nx/2 Nx/2-1:-1:1]
00145   cx = new PetscScalar[Nx];
00146   cy = new PetscScalar[Ny];
00147   for (PetscInt i=0; i <= Nx/2; i++) {
00148     cx[i] = (pi/fatLx) * (PetscScalar) i;
00149   }
00150   for (PetscInt i=Nx/2+1; i < Nx; i++) {
00151     cx[i] = (pi/fatLx) * (PetscScalar) (Nx - i);
00152   }
00153   for (PetscInt j=0; j <= Ny/2; j++) {
00154     cy[j] = (pi/fatLy) * (PetscScalar) j;
00155   }
00156   for (PetscInt j=Ny/2+1; j < Ny; j++) {
00157     cy[j] = (pi/fatLy) * (PetscScalar) (Ny - j);
00158   }
00159 
00160   // compare geforconv.m
00161   if (include_elastic == PETSC_TRUE) {
00162     ierr = PetscPrintf(PETSC_COMM_SELF,
00163            "     computing spherical elastic load response matrix ..."); CHKERRQ(ierr);
00164     PetscScalar **II;
00165     ierr = VecGetArray2d(lrmE, Nxge, Nyge, 0, 0, &II); CHKERRQ(ierr);
00166     ge_params ge_data;
00167     ge_data.dx = dx;
00168     ge_data.dy = dy;
00169     //const PetscInt imid_ge = Nx/2, jmid_ge = Ny/2;
00170     for (PetscInt i=0; i < Nxge; i++) {
00171       for (PetscInt j=0; j < Nyge; j++) {
00172         ge_data.p = i;
00173         ge_data.q = j;
00174         //ge_data.p = i - imid_ge;
00175         //ge_data.q = j - jmid_ge;
00176         II[i][j] = dblquad_cubature(ge_integrand, -dx/2, dx/2, -dy/2, dy/2, 
00177                                     1.0e-8, &ge_data);
00178       }
00179     }
00180     ierr = VecRestoreArray2d(lrmE, Nxge, Nyge, 0, 0, &II); CHKERRQ(ierr);
00181     // ierr = VecView(lrmE,PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
00182     ierr = PetscPrintf(PETSC_COMM_SELF," done\n"); CHKERRQ(ierr);
00183   }
00184 
00185   allocDone = PETSC_TRUE;
00186   return 0;
00187 }
00188 
00189 
00190 PetscErrorCode BedDeformLC::uplift_init() {
00191   // to initialize we solve: 
00192   //   rho_r g U + D grad^4 U = 0 - 2 eta |grad| uplift
00193   // where U=plateoffset; yes it really should have "0" on right side because
00194   // load for future times will be "-rho g (H-Hstart)", which is zero if no geometry 
00195   // change
00196   // compare equation (16) in 
00197   // Bueler, Lingle, Brown (2007) "Fast computation of a viscoelastic
00198   // deformable Earth model for ice sheet simulations", Ann. Glaciol. 46, 97--105
00199   // [NOTE PROBABLE SIGN ERROR in eqn (16)?:  load "rho g H" should be "- rho g H"]
00200     
00201 #if (PISM_HAVE_FFTW)
00202   PetscErrorCode ierr;
00203   PetscScalar **upl, **pla, **lft, **rgt;
00204 
00205   // spectral/FFT quantities are on fat computational grid but uplift is on thin
00206   ierr = VecGetArray2d(*uplift, Mx, My, 0, 0, &upl); CHKERRQ(ierr);
00207   ierr = VecGetArray2d(plateoffset, Nx, Ny, 0, 0, &pla); CHKERRQ(ierr);
00208   ierr = VecGetArray2d(vleft, Nx, Ny, 0, 0, &lft); CHKERRQ(ierr);
00209   ierr = VecGetArray2d(vright, Nx, Ny, 0, 0, &rgt); CHKERRQ(ierr);
00210 
00211   // fft2(uplift)
00212   for (PetscInt i=0; i < Nx; i++) {
00213     for (PetscInt j=0; j < Ny; j++) {
00214       bdin[j + Ny * i][0] = 0.0;
00215       bdin[j + Ny * i][1] = 0.0;
00216     }
00217   }
00218   for (PetscInt i=0; i < Mx; i++) {
00219     for (PetscInt j=0; j < My; j++) {
00220       bdin[(j + j0_plate) + Ny * (i + i0_plate)][0] = upl[i][j];
00221     }
00222   }
00223   fftw_execute(bdplanfor);
00224 
00225   // compute left and right coefficients
00226   for (PetscInt i=0; i < Nx; i++) {
00227     for (PetscInt j=0; j < Ny; j++) {
00228       const PetscScalar cclap = cx[i]*cx[i] + cy[j]*cy[j];
00229       lft[i][j] = rho * standard_gravity + D * cclap * cclap;
00230       rgt[i][j] = -2.0 * eta * sqrt(cclap);
00231     }
00232   }
00233 
00234   // Matlab version:
00235   //        frhs = right.*fft2(uplift);
00236   //        u = real(ifft2( frhs./left ));
00237   for (PetscInt i=0; i < Nx; i++) {
00238     for (PetscInt j=0; j < Ny; j++) {
00239       bdin[j + Ny * i][0] = (rgt[i][j] * bdout[j + Ny * i][0]) / lft[i][j];
00240       bdin[j + Ny * i][1] = (rgt[i][j] * bdout[j + Ny * i][1]) / lft[i][j];
00241     }
00242   }
00243   fftw_execute(bdplanback);
00244   for (PetscInt i=0; i < Nx; i++) {
00245     for (PetscInt j=0; j < Ny; j++) {
00246       pla[i][j] = bdout[j + Ny * i][0] / ((PetscScalar) (Nx * Ny));
00247     }
00248   }
00249 
00250   ierr = VecRestoreArray2d(*uplift, Mx, My, 0, 0, &upl); CHKERRQ(ierr);
00251   ierr = VecRestoreArray2d(plateoffset, Nx, Ny, 0, 0, &pla); CHKERRQ(ierr);
00252   ierr = VecRestoreArray2d(vleft, Nx, Ny, 0, 0, &lft); CHKERRQ(ierr);
00253   ierr = VecRestoreArray2d(vright, Nx, Ny, 0, 0, &rgt); CHKERRQ(ierr);
00254 
00255   ierr = VecCopy(plateoffset,platefat); CHKERRQ(ierr);
00256 #endif
00257 
00258   return 0;
00259 }
00260 
00261 
00262 PetscErrorCode BedDeformLC::step(const PetscScalar dtyear, const PetscScalar yearFromStart) {
00263   // solves: 
00264   //     (2 eta |grad| U^{n+1}) + (dt/2) * ( rho_r g U^{n+1} + D grad^4 U^{n+1} )
00265   //   = (2 eta |grad| U^n) - (dt/2) * ( rho_r g U^n + D grad^4 U^n ) - dt * rho g Hstart
00266   // where U=plate; see equation (7) in 
00267   // Bueler, Lingle, Brown (2007) "Fast computation of a viscoelastic
00268   // deformable Earth model for ice sheet simulations", Ann. Glaciol. 46, 97--105
00269   PetscErrorCode ierr;
00270   PetscScalar **b, **bs, **dbE, **pla, **plaoff;
00271 
00272   // update Hdiff from H
00273   ierr = VecWAXPY(Hdiff, -1, *Hstart, *H); CHKERRQ(ierr);
00274 
00275 #if (PISM_HAVE_FFTW)
00276   const PetscScalar dt = dtyear * secpera;
00277   PetscScalar **dH, **lft, **rgt;
00278 
00279   // note ice thicknesses and bed elevations only on physical ("thin") grid
00280   //   while spectral/FFT quantities are on fat computational grid
00281   ierr = VecGetArray2d(platefat, Nx, Ny, 0, 0, &pla); CHKERRQ(ierr);
00282   ierr = VecGetArray2d(vleft, Nx, Ny, 0, 0, &lft); CHKERRQ(ierr);
00283   ierr = VecGetArray2d(vright, Nx, Ny, 0, 0, &rgt); CHKERRQ(ierr);
00284 
00285   // Matlab: sszz=-rhoi*g*H;  (here H -> H-Hstart) 
00286   //         COMPUTE fft2(dt*sszz);
00287   for (PetscInt i=0; i < Nx; i++) {
00288     for (PetscInt j=0; j < Ny; j++) {
00289       bdin[j + Ny * i][0] = 0.0;
00290       bdin[j + Ny * i][1] = 0.0;
00291     }
00292   }
00293   ierr = VecGetArray2d(Hdiff, Mx, My, 0, 0, &dH); CHKERRQ(ierr);
00294   for (PetscInt i=0; i < Mx; i++) {
00295     for (PetscInt j=0; j < My; j++) {
00296       const PetscScalar sszz = - icerho * standard_gravity * dH[i][j];
00297       bdin[(j + j0_plate) + Ny * (i + i0_plate)][0] = dt * sszz;
00298     }
00299   }
00300   ierr = VecRestoreArray2d(Hdiff, Mx, My, 0, 0, &dH); CHKERRQ(ierr);
00301   fftw_execute(bdplanfor);
00302   fftw_complex  *loadhat;  // actually a 2D array but must be flat for fftw
00303   loadhat = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * Nx * Ny);
00304   for (PetscInt i=0; i < Nx; i++) {
00305     for (PetscInt j=0; j < Ny; j++) {
00306       loadhat[j + Ny * i][0] = bdout[j + Ny * i][0];
00307       loadhat[j + Ny * i][1] = bdout[j + Ny * i][1];
00308     }
00309   }
00310 
00311   //         COMPUTE fft2(uun);
00312   for (PetscInt i=0; i < Nx; i++) {
00313     for (PetscInt j=0; j < Ny; j++) {
00314       bdin[j + Ny * i][0] = pla[i][j];
00315       bdin[j + Ny * i][1] = 0.0;
00316     }
00317   }
00318   fftw_execute(bdplanfor);
00319 
00320   // compute left and right coefficients; note they depend on actual time step
00321   //   and thus cannot be precomputed
00322   for (PetscInt i=0; i < Nx; i++) {
00323     for (PetscInt j=0; j < Ny; j++) {
00324       const PetscScalar cclap = cx[i]*cx[i] + cy[j]*cy[j];
00325       const PetscScalar part1 = 2.0 * eta * sqrt(cclap);
00326       const PetscScalar part2 = (dt/2.0) * (rho * standard_gravity + D * cclap * cclap);
00327       lft[i][j] = part1 + part2;
00328       rgt[i][j] = part1 - part2;
00329     }
00330   }
00331 
00332   //         frhs=right.*fft2(uun) + fft2(dt*sszz);
00333   //         uun1=real(ifft2( frhs./left ));
00334   for (PetscInt i=0; i < Nx; i++) {
00335     for (PetscInt j=0; j < Ny; j++) {
00336       bdin[j + Ny * i][0] = (rgt[i][j] * bdout[j + Ny * i][0] + 
00337                                loadhat[j + Ny * i][0]) / lft[i][j];
00338       bdin[j + Ny * i][1] = (rgt[i][j] * bdout[j + Ny * i][1] + 
00339                                loadhat[j + Ny * i][1]) / lft[i][j];
00340     }
00341   }
00342   fftw_execute(bdplanback);
00343   for (PetscInt i=0; i < Nx; i++) {
00344     for (PetscInt j=0; j < Ny; j++) {
00345       pla[i][j] = bdout[j + Ny * i][0] / ((PetscScalar) (Nx * Ny));
00346     }
00347   }
00348   fftw_free(loadhat);
00349 
00350   ierr = VecRestoreArray2d(vleft, Nx, Ny, 0, 0, &lft); CHKERRQ(ierr);
00351   ierr = VecRestoreArray2d(vright, Nx, Ny, 0, 0, &rgt); CHKERRQ(ierr);
00352 #endif
00353 
00354   // now tweak
00355 #if 1
00356   // find average value along "distant" bdry of [-fatLx,fatLx]X[-fatLy,fatLy]
00357   // note domain is periodic, so think of cut locus of torus (!)
00358   // (will remove it:   uun1=uun1-( sum(uun1(1,:))+sum(uun1(:,1)) )/(2*N);)
00359   PetscScalar   av = 0.0;
00360   for (PetscInt i=0; i < Nx; i++) {
00361     av += pla[i][0];
00362   }
00363   for (PetscInt j=0; j < Ny; j++) {
00364     av += pla[0][j];
00365   }
00366   av = av / ((PetscScalar) (Nx + Ny));
00367   // tweak cont: replace far field with value for equiv disc load which has R0=Lx*(2/3)=L/3 
00368   // (instead of 1000km in Matlab code: H0 = dx*dx*sum(sum(H))/(pi*1e6^2);  % trapezoid rule)
00369   const PetscScalar Lav = (fatLx + fatLy)/2.0;
00370   const PetscScalar Requiv = Lav * (2.0/3.0);
00371   PetscScalar delvolume;
00372   ierr = VecSum(Hdiff, &delvolume); CHKERRQ(ierr);
00373   delvolume = delvolume * dx * dy;  // make into a volume
00374   const PetscScalar Hequiv = delvolume / (pi * Requiv * Requiv);
00375 
00376   const PetscScalar vd_time = yearFromStart * secpera;
00377   const PetscScalar discshift = viscDisc(vd_time,Hequiv,Requiv,Lav,rho,standard_gravity,D,eta) - av; 
00378   for (PetscInt i=0; i < Nx; i++) {
00379     for (PetscInt j=0; j < Ny; j++) {
00380       pla[i][j] += discshift;
00381     }
00382   }
00383 #endif
00384 
00385   // now compute elastic response if desired; bed = ue at end of this block
00386   if (include_elastic == PETSC_TRUE) {
00387     // Matlab:     ue=rhoi*conv2(H-Hstart,II,'same')
00388     ierr = conv2_same(Hdiff,Mx,My,lrmE,Nxge,Nyge,dbedElastic);  CHKERRQ(ierr);
00389     ierr = VecScale(dbedElastic,icerho);  CHKERRQ(ierr);
00390   } else {
00391     ierr = VecSet(dbedElastic,0.0); CHKERRQ(ierr);
00392   }
00393 
00394   // now sum contributions to get new bed elevation:
00395   //    (new bed) = ue + (bed start) + plate
00396   // (but use only central part of plate if Z>1)
00397   ierr = VecGetArray2d(plateoffset, Nx, Ny, 0, 0, &plaoff); CHKERRQ(ierr);
00398   ierr = VecGetArray2d(*bed, Mx, My, 0, 0, &b); CHKERRQ(ierr);
00399   ierr = VecGetArray2d(*bedstart, Mx, My, 0, 0, &bs); CHKERRQ(ierr);
00400   ierr = VecGetArray2d(dbedElastic, Mx, My, 0, 0, &dbE); CHKERRQ(ierr);
00401   for (PetscInt i=0; i < Mx; i++) {
00402     for (PetscInt j=0; j < My; j++) {
00403       b[i][j] = bs[i][j] + dbE[i][j] // add elastic first
00404                  + (pla[i + i0_plate][j + j0_plate] - plaoff[i + i0_plate][j + j0_plate]);
00405     }
00406   }
00407   ierr = VecRestoreArray2d(*bed, Mx, My, 0, 0, &b); CHKERRQ(ierr);
00408   ierr = VecRestoreArray2d(*bedstart, Mx, My, 0, 0, &bs); CHKERRQ(ierr);
00409   ierr = VecRestoreArray2d(dbedElastic, Mx, My, 0, 0, &dbE); CHKERRQ(ierr);    
00410   ierr = VecRestoreArray2d(plateoffset, Nx, Ny, 0, 0, &plaoff); CHKERRQ(ierr);
00411 
00412   ierr = VecRestoreArray2d(platefat, Nx, Ny, 0, 0, &pla); CHKERRQ(ierr);
00413   return 0;
00414 }
00415 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines