|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 // Copyright (C) 2009--2011 Jed Brown and Ed Bueler and Constantine Khroulev and David Maxwell 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 // Utility functions used by the SSAFEM code. 00020 00021 #include "FETools.hh" 00022 00023 const FEShapeQ1::ShapeFunctionSpec FEShapeQ1::shapeFunction[FEShapeQ1::Nk] = 00024 {FEShapeQ1::shape0, FEShapeQ1::shape1, FEShapeQ1::shape2, FEShapeQ1::shape3}; 00025 00026 00027 FEElementMap::FEElementMap(const IceGrid &g) 00028 { 00029 // Start by assuming ghost elements exist in all directions. 00030 // Elements are indexed by their lower left vertex. If there is a ghost 00031 // element on the right, its i-index will be the same as the maximum 00032 // i-index of a non-ghost vertex in the local grid. 00033 xs= g.xs-1; // Start at ghost to the left. 00034 PetscInt xf = g.xs + g.xm - 1; // End at ghost to the right. 00035 ys= g.ys-1; // Start at ghost at the bottom. 00036 PetscInt yf = g.ys + g.ym - 1; // End at ghost at the top. 00037 00038 lxs = g.xs; 00039 PetscInt lxf = lxs + g.xm - 1; 00040 lys = g.ys; 00041 PetscInt lyf = lys + g.ym - 1; 00042 00043 // Now correct if needed. The only way there will not be ghosts is if the 00044 // grid is not periodic and we are up against the grid boundary. 00045 00046 if( !(g.periodicity & X_PERIODIC) ) 00047 { 00048 // Leftmost element has x-index 0. 00049 if(xs < 0){ 00050 xs = 0; 00051 } 00052 // Rightmost vertex has index g.Mx-1, so the rightmost element has index g.Mx-2 00053 if(xf > g.Mx-2) 00054 { 00055 xf = g.Mx-2; 00056 lxf = g.Mx-2; 00057 } 00058 } 00059 00060 if( !(g.periodicity & Y_PERIODIC) ) 00061 { 00062 // Bottom element has y-index 0. 00063 if(ys < 0){ 00064 ys = 0; 00065 } 00066 // Topmost vertex has index g.My-1, so the topmost element has index g.My-2 00067 if(yf > g.My-2) 00068 { 00069 yf = g.My-2; 00070 lyf = g.My-2; 00071 } 00072 } 00073 00074 // Tally up the number of elements in each direction 00075 xm = xf-xs+1; 00076 ym = yf-ys+1; 00077 lxm = lxf-lxs+1; 00078 lym = lyf-lys+1; 00079 00080 } 00081 00082 00085 void FEDOFMap::extractLocalDOFs(PetscInt i,PetscInt j, PetscReal const*const*xg,PetscReal *x) const 00086 { 00087 x[0] = xg[i][j]; x[1] = xg[i+1][j]; x[2] = xg[i+1][j+1]; x[3] = xg[i][j+1]; 00088 } 00089 00093 void FEDOFMap::extractLocalDOFs(PetscInt i,PetscInt j, PISMVector2 const*const*xg,PISMVector2 *x) const 00094 { 00095 x[0] = xg[i][j]; x[1] = xg[i+1][j]; x[2] = xg[i+1][j+1]; x[3] = xg[i][j+1]; 00096 } 00097 00098 00100 void FEDOFMap::extractLocalDOFs(PetscReal const*const*xg,PetscReal *x) const 00101 { 00102 extractLocalDOFs(m_i,m_j,xg,x); 00103 } 00104 00106 void FEDOFMap::extractLocalDOFs(PISMVector2 const*const*xg,PISMVector2 *x) const 00107 { 00108 extractLocalDOFs(m_i,m_j,xg,x); 00109 } 00110 00112 void FEDOFMap::localToGlobal(PetscInt k, PetscInt *i, PetscInt *j) 00113 { 00114 *i = m_i + kIOffset[k]; 00115 *j = m_j + kJOffset[k]; 00116 } 00117 00120 void FEDOFMap::reset(PetscInt i, PetscInt j, const IceGrid &grid) 00121 { 00122 m_i = i; m_j = j; 00123 // The meaning of i and j for a PISM IceGrid and for a Petsc DA are swapped (the so-called 00124 // fundamental transpose. The interface between PISM and Petsc is the stencils, so all 00125 // interactions with the stencils involve a transpose. 00126 m_col[0].j = i; m_col[0].i = j; 00127 m_col[1].j = i+1; m_col[1].i = j; 00128 m_col[2].j = i+1; m_col[2].i = j+1; 00129 m_col[3].j = i; m_col[3].i = j+1; 00130 00131 memcpy(m_row,m_col,Nk*sizeof(m_col[0])); 00132 00133 // We do not ever sum into rows that are not owned by the local rank. 00134 for(PetscInt k=0; k<Nk; k++) { 00135 PetscInt pism_i = m_row[k].j, pism_j = m_row[k].i; 00136 if ( pism_i < grid.xs || grid.xs+grid.xm-1 < pism_i || 00137 pism_j < grid.ys || grid.ys+grid.ym-1 < pism_j ) { 00138 markRowInvalid(k); 00139 } 00140 } 00141 } 00142 00145 void FEDOFMap::markRowInvalid(PetscInt k) 00146 { 00147 m_row[k].i=m_row[k].j = kDofInvalid; 00148 } 00149 00152 void FEDOFMap::markColInvalid(PetscInt k) 00153 { 00154 m_col[k].i=m_col[k].j = kDofInvalid; 00155 } 00156 00160 void FEDOFMap::addLocalResidualBlock(const PISMVector2 *y, PISMVector2 **yg) 00161 { 00162 for (int k=0; k<Nk; k++) { 00163 if (m_row[k].i == kDofInvalid || m_row[k].j == kDofInvalid) continue; 00164 yg[m_row[k].j][m_row[k].i].u += y[k].u; 00165 yg[m_row[k].j][m_row[k].i].v += y[k].v; 00166 } 00167 } 00168 void FEDOFMap::addLocalResidualBlock(const PetscScalar *y, PetscScalar **yg) 00169 { 00170 for (int k=0; k<Nk; k++) { 00171 if (m_row[k].i == kDofInvalid || m_row[k].j == kDofInvalid) continue; 00172 yg[m_row[k].j][m_row[k].i] += y[k]; 00173 } 00174 } 00175 00177 00179 PetscErrorCode FEDOFMap::addLocalJacobianBlock(const PetscReal *K, Mat J) 00180 { 00181 PetscErrorCode ierr = MatSetValuesBlockedStencil(J,Nk,m_row,Nk,m_col,K,ADD_VALUES);CHKERRQ(ierr); 00182 return 0; 00183 } 00184 00186 00190 PetscErrorCode FEDOFMap::setJacobianDiag(PetscInt i, PetscInt j, const PetscReal*K, Mat J) 00191 { 00192 MatStencil row; 00193 row.i=j; row.j=i; 00194 PetscErrorCode ierr = MatSetValuesBlockedStencil(J,1,&row,1,&row,K,INSERT_VALUES);CHKERRQ(ierr); 00195 return 0; 00196 } 00197 00198 const PetscInt FEDOFMap::kIOffset[4] = {0,1,1,0}; 00199 const PetscInt FEDOFMap::kJOffset[4] = {0,0,1,1}; 00200 00201 00202 FEQuadrature::FEQuadrature() 00203 { 00204 } 00205 00207 void FEQuadrature::getWeightedJacobian(PetscReal *jxw) 00208 { 00209 for(int q=0;q<Nq;q++) 00210 { 00211 jxw[q] = m_jacobianDet * quadWeights[q]; 00212 } 00213 } 00214 00216 void FEQuadrature::init(const IceGrid &grid,PetscScalar L) 00217 { 00218 // Since we use uniform cartesian coordinates, the Jacobian is constant and diagonal on every element. 00219 // Note that the reference element is \f$ [-1,1]^2 \f$ hence the extra factor of 1/2. 00220 PetscReal jacobian_x = 0.5*grid.dx/L; 00221 PetscReal jacobian_y = 0.5*grid.dy/L; 00222 m_jacobianDet = jacobian_x*jacobian_y; 00223 00224 FEShapeQ1 shape; 00225 for(int q=0; q<Nq; q++){ 00226 for(int k=0; k<Nk; k++){ 00227 shape.eval(k,quadPoints[q][0],quadPoints[q][1],&m_germs[q][k]); 00228 m_germs[q][k].dx /= jacobian_x; 00229 m_germs[q][k].dy /= jacobian_y; 00230 } 00231 } 00232 } 00233 00235 //* The return value is an Nq by Nk array of FEFunctionGerms. */ 00236 const FEFunctionGerm (*FEQuadrature::testFunctionValues())[FEQuadrature::Nq] 00237 { 00238 return m_germs; 00239 } 00240 00242 //* The return value is an array of Nk FEFunctionGerms. */ 00243 const FEFunctionGerm *FEQuadrature::testFunctionValues(PetscInt q) 00244 { 00245 return m_germs[q]; 00246 } 00247 00249 const FEFunctionGerm *FEQuadrature::testFunctionValues(PetscInt q, PetscInt k) 00250 { 00251 return m_germs[q] + k; 00252 } 00253 00254 00258 void FEQuadrature::computeTrialFunctionValues(const PetscReal *x, PetscReal *vals) 00259 { 00260 for (int q=0; q<Nq; q++) { 00261 const FEFunctionGerm *test = m_germs[q]; 00262 vals[q] = 0; 00263 for (int k=0; k<Nk; k++) { 00264 vals[q] += test[k].val * x[k]; 00265 } 00266 } 00267 } 00268 00274 void FEQuadrature::computeTrialFunctionValues(const PetscReal *x, PetscReal *vals, PetscReal *dx, PetscReal *dy) 00275 { 00276 for (int q=0; q<Nq; q++) { 00277 const FEFunctionGerm *test = m_germs[q]; 00278 vals[q] = 0; dx[q] = 0; dy[q] = 0; 00279 for (int k=0; k<Nk; k++) { 00280 vals[q] += test[k].val * x[k]; 00281 dx[q] += test[k].dx * x[k]; 00282 dy[q] += test[k].dy * x[k]; 00283 } 00284 } 00285 } 00286 00290 void FEQuadrature::computeTrialFunctionValues( PetscInt i, PetscInt j, const FEDOFMap &dof, 00291 PetscReal const*const*xg, PetscReal *vals) 00292 { 00293 dof.extractLocalDOFs(i,j,xg,m_tmpScalar); 00294 computeTrialFunctionValues(m_tmpScalar,vals); 00295 } 00296 00300 void FEQuadrature::computeTrialFunctionValues( PetscInt i, PetscInt j, const FEDOFMap &dof, PetscReal const*const*xg, 00301 PetscReal *vals, PetscReal *dx, PetscReal *dy) 00302 { 00303 dof.extractLocalDOFs(i,j,xg,m_tmpScalar); 00304 computeTrialFunctionValues(m_tmpScalar,vals,dx,dy); 00305 } 00306 00310 void FEQuadrature::computeTrialFunctionValues( const PISMVector2 *x, PISMVector2 *vals) 00311 { 00312 for (int q=0; q<Nq; q++) { 00313 vals[q].u = 0; vals[q].v = 0; 00314 const FEFunctionGerm *test = m_germs[q]; 00315 for (int k=0; k<Nk; k++) { 00316 vals[q].u += test[k].val * x[k].u; 00317 vals[q].v += test[k].val * x[k].v; 00318 } 00319 } 00320 00321 } 00322 00329 void FEQuadrature::computeTrialFunctionValues( const PISMVector2 *x, PISMVector2 *vals, PetscReal (*Dv)[3] ) 00330 { 00331 for (int q=0; q<Nq; q++) { 00332 vals[q].u = 0; vals[q].v = 0; 00333 PetscReal *Dvq = Dv[q]; 00334 Dvq[0]=0; Dvq[1]=0; Dvq[2]=0; 00335 const FEFunctionGerm *test = m_germs[q]; 00336 for(int k=0; k<Nk; k++) { 00337 vals[q].u += test[k].val * x[k].u; 00338 vals[q].v += test[k].val * x[k].v; 00339 Dvq[0] += test[k].dx * x[k].u; 00340 Dvq[1] += test[k].dy * x[k].v; 00341 Dvq[2] += 0.5*(test[k].dy*x[k].u + test[k].dx*x[k].v); 00342 } 00343 } 00344 } 00345 00352 void FEQuadrature::computeTrialFunctionValues( const PISMVector2 *x, PISMVector2 *vals, PISMVector2 *dx, PISMVector2 *dy) 00353 { 00354 for (int q=0; q<Nq; q++) { 00355 vals[q].u = 0; vals[q].v = 0; 00356 dx[q].u = 0; dx[q].v = 0; 00357 dy[q].u = 0; dy[q].v = 0; 00358 const FEFunctionGerm *test = m_germs[q]; 00359 for(int k=0; k<Nk; k++) { 00360 vals[q].u += test[k].val * x[k].u; 00361 vals[q].v += test[k].val * x[k].v; 00362 dx[q].u += test[k].dx * x[k].u; 00363 dx[q].v += test[k].dx * x[k].v; 00364 dy[q].u += test[k].dy * x[k].u; 00365 dy[q].v += test[k].dy * x[k].v; 00366 } 00367 } 00368 } 00369 00370 00374 void FEQuadrature::computeTrialFunctionValues( PetscInt i, PetscInt j, const FEDOFMap &dof, 00375 PISMVector2 const*const*xg, PISMVector2 *vals ) 00376 { 00377 dof.extractLocalDOFs(i,j,xg,m_tmpVector); 00378 computeTrialFunctionValues(m_tmpVector,vals); 00379 } 00380 00387 void FEQuadrature::computeTrialFunctionValues( PetscInt i, PetscInt j, const FEDOFMap &dof, 00388 PISMVector2 const*const*xg, PISMVector2 *vals, PetscReal (*Dv)[3] ) 00389 { 00390 dof.extractLocalDOFs(i,j,xg,m_tmpVector); 00391 computeTrialFunctionValues(m_tmpVector,vals,Dv); 00392 } 00393 00395 const PetscReal FEQuadrature::quadPoints[FEQuadrature::Nq][2] = 00396 {{ -0.57735026918962573, -0.57735026918962573 }, 00397 { 0.57735026918962573, -0.57735026918962573 }, 00398 { 0.57735026918962573, 0.57735026918962573 }, 00399 { -0.57735026918962573, 0.57735026918962573 }}; 00400 00402 const PetscReal FEQuadrature::quadWeights[FEQuadrature::Nq] = {1,1,1,1}; 00403 00404 00405 00407 PetscTruth Floating(const IceFlowLaw &ice, PetscScalar ocean_rho, 00408 PetscReal H, PetscReal bed) 00409 { 00410 return ice.rho*H + ocean_rho*bed < 0 ? PETSC_TRUE : PETSC_FALSE; 00411 } 00412 00413 00415 int PismIntMask(PetscScalar maskvalue) { 00416 return static_cast<int>(floor(maskvalue + 0.5)); 00417 } 00418
1.7.3