PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/stressbalance/FETools.cc

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