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