|
PISM, A Parallel Ice Sheet Model
stable v0.5
|
00001 // Copyright (C) 2004-2011 Jed Brown, 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 "iceModel.hh" 00020 #include "Mask.hh" 00021 #include "bedrockThermalUnit.hh" 00022 #include "PISMSurface.hh" 00023 #include "PISMOcean.hh" 00024 #include "enthalpyConverter.hh" 00025 00028 00030 00043 PetscErrorCode IceModel::energyStep() { 00044 PetscErrorCode ierr; 00045 00046 PetscScalar myCFLviolcount = 0.0, // these are counts but they are type "PetscScalar" 00047 myVertSacrCount = 0.0, // because that type works with PISMGlobalSum() 00048 myBulgeCount = 0.0; 00049 PetscScalar gVertSacrCount, gBulgeCount; 00050 00051 // always count CFL violations for sanity check (but can occur only if -skip N with N>1) 00052 ierr = countCFLViolations(&myCFLviolcount); CHKERRQ(ierr); 00053 00054 // operator-splitting occurs here (ice and bedrock energy updates are split): 00055 // tell PISMBedThermalUnit* btu that we have an ice base temp; it will return 00056 // the z=0 value of geothermal flux when called inside temperatureStep() or 00057 // enthalpyAndDrainageStep() 00058 ierr = get_bed_top_temp(bedtoptemp); CHKERRQ(ierr); 00059 ierr = btu->update(t_TempAge, dt_TempAge); CHKERRQ(ierr); // has ptr to bedtoptemp 00060 00061 if (config.get_flag("do_cold_ice_methods")) { 00062 // new temperature values go in vTnew; also updates Hmelt: 00063 ierr = temperatureStep(&myVertSacrCount,&myBulgeCount); CHKERRQ(ierr); 00064 00065 ierr = T3.beginGhostCommTransfer(vWork3d); CHKERRQ(ierr); 00066 ierr = T3.endGhostCommTransfer(vWork3d); CHKERRQ(ierr); 00067 00068 // compute_enthalpy_cold() updates ghosts of Enth3 using a 00069 // begin/endGhostComm pair. Is not optimized because this 00070 // (do_cold_ice_methods) is a rare case. 00071 ierr = compute_enthalpy_cold(T3, Enth3); CHKERRQ(ierr); 00072 00073 } else { 00074 // new enthalpy values go in vWork3d; also updates (and communicates) Hmelt 00075 PetscScalar myLiquifiedVol = 0.0, gLiquifiedVol; 00076 00077 ierr = enthalpyAndDrainageStep(&myVertSacrCount,&myLiquifiedVol,&myBulgeCount); 00078 CHKERRQ(ierr); 00079 00080 ierr = Enth3.beginGhostCommTransfer(vWork3d); CHKERRQ(ierr); 00081 ierr = Enth3.endGhostCommTransfer(vWork3d); CHKERRQ(ierr); 00082 00083 ierr = PISMGlobalSum(&myLiquifiedVol, &gLiquifiedVol, grid.com); CHKERRQ(ierr); 00084 if (gLiquifiedVol > 0.0) { 00085 ierr = verbPrintf(1,grid.com, 00086 "\n PISM WARNING: fully-liquified cells detected: volume liquified = %.3f km^3\n\n", 00087 gLiquifiedVol / 1.0e9); CHKERRQ(ierr); 00088 } 00089 } 00090 00091 // Both cases above update the basal melt rate field; here we update its 00092 // ghosts, which are needed to compute tauc locally 00093 ierr = vbmr.beginGhostComm(); CHKERRQ(ierr); 00094 ierr = vbmr.endGhostComm(); CHKERRQ(ierr); 00095 00096 ierr = PISMGlobalSum(&myCFLviolcount, &CFLviolcount, grid.com); CHKERRQ(ierr); 00097 00098 ierr = PISMGlobalSum(&myVertSacrCount, &gVertSacrCount, grid.com); CHKERRQ(ierr); 00099 if (gVertSacrCount > 0.0) { // count of when BOMBPROOF switches to lower accuracy 00100 const PetscScalar bfsacrPRCNT = 100.0 * (gVertSacrCount / (grid.Mx * grid.My)); 00101 const PetscScalar BPSACR_REPORT_VERB2_PERCENT = 5.0; // only report if above 5% 00102 if ( (bfsacrPRCNT > BPSACR_REPORT_VERB2_PERCENT) 00103 && (getVerbosityLevel() > 2) ) { 00104 char tempstr[50] = ""; 00105 snprintf(tempstr,50, " [BPsacr=%.4f%%] ", bfsacrPRCNT); 00106 stdout_flags = tempstr + stdout_flags; 00107 } 00108 } 00109 00110 ierr = PISMGlobalSum(&myBulgeCount, &gBulgeCount, grid.com); CHKERRQ(ierr); 00111 if (gBulgeCount > 0.0) { // count of when advection bulges are limited; 00112 // frequently it is identically zero 00113 char tempstr[50] = ""; 00114 snprintf(tempstr,50, " BULGE=%d ", static_cast<int>(ceil(gBulgeCount)) ); 00115 stdout_flags = tempstr + stdout_flags; 00116 } 00117 00118 return 0; 00119 } 00120 00121 00124 PetscErrorCode IceModel::get_bed_top_temp(IceModelVec2S &result) { 00125 PetscErrorCode ierr; 00126 PetscReal sea_level = 0, 00127 T0 = config.get("water_melting_point_temperature"), 00128 beta_CC_grad_sea_water = (config.get("beta_CC") * config.get("sea_water_density") * 00129 config.get("standard_gravity")); // K m-1 00130 00131 // will need coupler fields in ice-free land and 00132 if (surface != PETSC_NULL) { 00133 ierr = surface->ice_surface_temperature(artm); CHKERRQ(ierr); 00134 } else { 00135 SETERRQ(grid.com, 1,"PISM ERROR: surface == PETSC_NULL"); 00136 } 00137 if (ocean != PETSC_NULL) { 00138 ierr = ocean->sea_level_elevation(sea_level); CHKERRQ(ierr); 00139 } else { 00140 SETERRQ(grid.com, 5,"PISM ERROR: ocean == PETSC_NULL"); 00141 } 00142 00143 // start by grabbing 2D basal enthalpy field at z=0; converted to temperature if needed, below 00144 ierr = Enth3.getHorSlice(result, 0.0); CHKERRQ(ierr); 00145 00146 MaskQuery mask(vMask); 00147 00148 ierr = vbed.begin_access(); CHKERRQ(ierr); 00149 ierr = result.begin_access(); CHKERRQ(ierr); 00150 ierr = vH.begin_access(); CHKERRQ(ierr); 00151 ierr = vMask.begin_access(); CHKERRQ(ierr); 00152 ierr = artm.begin_access(); CHKERRQ(ierr); 00153 for (PetscInt i = grid.xs; i < grid.xs+grid.xm; ++i) { 00154 for (PetscInt j = grid.ys; j < grid.ys+grid.ym; ++j) { 00155 if (mask.grounded(i,j)) { 00156 if (mask.ice_free(i,j)) { // no ice: sees air temp 00157 result(i,j) = artm(i,j); 00158 } else { // ice: sees temp of base of ice 00159 const PetscReal pressure = EC->getPressureFromDepth(vH(i,j)); 00160 PetscReal temp; 00161 // ignore return code when getting temperature: we are committed to 00162 // this enthalpy field; getAbsTemp() only returns temperatures at or 00163 // below pressure melting 00164 EC->getAbsTemp(result(i,j), pressure, temp); 00165 result(i,j) = temp; 00166 } 00167 } else { // floating: apply pressure melting temp as top of bedrock temp 00168 result(i,j) = T0 - (sea_level - vbed(i,j)) * beta_CC_grad_sea_water; 00169 } 00170 } 00171 } 00172 ierr = vH.end_access(); CHKERRQ(ierr); 00173 ierr = result.end_access(); CHKERRQ(ierr); 00174 ierr = vMask.end_access(); CHKERRQ(ierr); 00175 ierr = artm.end_access(); CHKERRQ(ierr); 00176 ierr = vbed.end_access(); CHKERRQ(ierr); 00177 00178 return 0; 00179 } 00180 00181 00184 bool IceModel::checkThinNeigh(PetscScalar E, PetscScalar NE, PetscScalar N, PetscScalar NW, 00185 PetscScalar W, PetscScalar SW, PetscScalar S, PetscScalar SE) { 00186 // FIXME: silly hard-wired critical level, but we want to avoid config.get() in loops. 00187 const PetscScalar THIN = 100.0; // thin = (at most 100m thick) 00188 return ( (E < THIN) || (NE < THIN) || (N < THIN) || (NW < THIN) 00189 || (W < THIN) || (SW < THIN) || (S < THIN) || (SE < THIN) ); 00190 } 00191
1.7.5.1