|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 // Copyright (C) 2011 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 static char help[] = 00020 "Tests PISMBedThermalUnit using Test K. Sans IceModel.\n\n"; 00021 00022 #include "pism_const.hh" 00023 #include "grid.hh" 00024 #include "PISMIO.hh" 00025 #include "NCVariable.hh" 00026 #include "bedrockThermalUnit.hh" 00027 00028 #include "../../verif/tests/exactTestK.h" 00029 00030 class BTU_Test : public PISMBedThermalUnit 00031 { 00032 public: 00033 BTU_Test(IceGrid &g, const NCConfigVariable &conf) 00034 : PISMBedThermalUnit(g, conf) {} 00035 virtual ~BTU_Test() {} 00036 protected: 00037 virtual PetscErrorCode bootstrap(); 00038 }; 00039 00040 PetscErrorCode BTU_Test::bootstrap() { 00041 PetscErrorCode ierr; 00042 00043 // fill exact bedrock temperature from Test K at time ys 00044 if (Mbz > 1) { 00045 vector<double> zlevels = temp.get_levels(); 00046 00047 ierr = temp.begin_access(); CHKERRQ(ierr); 00048 PetscScalar *Tb; // columns of these values 00049 for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) { 00050 for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) { 00051 ierr = temp.getInternalColumn(i,j,&Tb); CHKERRQ(ierr); 00052 for (PetscInt k=0; k < Mbz; k++) { 00053 const PetscReal z = zlevels[k]; 00054 PetscReal FF; // Test K: use Tb[k], ignore FF 00055 ierr = exactK(grid.start_year * secpera, z, &Tb[k], &FF, 0); CHKERRQ(ierr); 00056 } 00057 } 00058 } 00059 ierr = temp.end_access(); CHKERRQ(ierr); 00060 } 00061 00062 return 0; 00063 } 00064 00065 00066 static PetscErrorCode createVecs(IceGrid &grid, PISMVars &variables) { 00067 00068 PetscErrorCode ierr; 00069 IceModelVec2S *bedtoptemp = new IceModelVec2S, 00070 *ghf = new IceModelVec2S; 00071 00072 ierr = ghf->create(grid, "bheatflx", false); CHKERRQ(ierr); 00073 ierr = ghf->set_attrs("", 00074 "upward geothermal flux at bedrock thermal layer base", 00075 "W m-2", ""); CHKERRQ(ierr); 00076 ierr = ghf->set_glaciological_units("mW m-2"); 00077 ierr = variables.add(*ghf); CHKERRQ(ierr); 00078 00079 ierr = bedtoptemp->create(grid, "bedtoptemp", false); CHKERRQ(ierr); 00080 ierr = bedtoptemp->set_attrs("", 00081 "temperature at top of bedrock thermal layer", 00082 "K", ""); CHKERRQ(ierr); 00083 ierr = variables.add(*bedtoptemp); CHKERRQ(ierr); 00084 00085 return 0; 00086 } 00087 00088 00089 static PetscErrorCode doneWithIceInfo(PISMVars &variables) { 00090 // Get the names of all the variables allocated earlier: 00091 set<string> vars = variables.keys(); 00092 set<string>::iterator i = vars.begin(); 00093 while (i != vars.end()) { 00094 IceModelVec *var = variables.get(*i); 00095 delete var; 00096 i++; 00097 } 00098 return 0; 00099 } 00100 00101 00102 int main(int argc, char *argv[]) { 00103 PetscErrorCode ierr; 00104 00105 MPI_Comm com; 00106 PetscMPIInt rank, size; 00107 ierr = PetscInitialize(&argc, &argv, PETSC_NULL, help); CHKERRQ(ierr); 00108 com = PETSC_COMM_WORLD; 00109 ierr = MPI_Comm_rank(com, &rank); CHKERRQ(ierr); 00110 ierr = MPI_Comm_size(com, &size); CHKERRQ(ierr); 00111 00112 /* This explicit scoping forces destructors to be called before PetscFinalize() */ 00113 { 00114 NCConfigVariable config, overrides; 00115 00116 ierr = verbosityLevelFromOptions(); CHKERRQ(ierr); 00117 00118 // check required options 00119 vector<string> required; 00120 required.push_back("-Mbz"); 00121 ierr = show_usage_check_req_opts(com, "btutest", required, 00122 " btutest -Mbz NN -Lbz 1000.0 [-o OUT.nc -ys A -ye B -dt C -Mz D -Lz E]\n" 00123 "where these are required because they are used in PISMBedThermalUnit:\n" 00124 " -Mbz number of bedrock thermal layer levels to use\n" 00125 " -Lbz 1000.0 depth of bedrock thermal layer (required; Lbz=1000.0 m in Test K)\n" 00126 "and these are allowed:\n" 00127 " -o output file name; NetCDF format\n" 00128 " -ys start year in using Test K\n" 00129 " -ye end year in using Test K\n" 00130 " -dt time step B (= positive float) in years\n" 00131 " -Mz number of ice levels to use\n" 00132 " -Lz height of ice/atmospher box\n" 00133 ); CHKERRQ(ierr); 00134 00135 ierr = verbPrintf(2,com, 00136 "btutest tests PISMBedThermalUnit and IceModelVec3BTU\n"); CHKERRQ(ierr); 00137 00138 // read the config option database: 00139 ierr = init_config(com, rank, config, overrides); CHKERRQ(ierr); 00140 00141 // when IceGrid constructor is called, these settings are used 00142 config.set_string("grid_ice_vertical_spacing","equal"); 00143 config.set_string("grid_bed_vertical_spacing","equal"); 00144 00145 // create grid and set defaults 00146 IceGrid grid(com, rank, size, config); 00147 config.set("grid_Mbz", 11); 00148 config.set("grid_Lbz", 1000); 00149 grid.Mz = 41; 00150 grid.Lz = 4000.0; 00151 grid.Mx = 3; 00152 grid.My = 3; 00153 grid.Lx = 1500e3; 00154 grid.Ly = grid.Lx; 00155 grid.start_year = 0.0; 00156 grid.end_year = 1.0; 00157 00158 ierr = verbPrintf(2,com, 00159 " initializing IceGrid from options ...\n"); CHKERRQ(ierr); 00160 bool flag; 00161 PetscReal dt_years = 1.0; 00162 string outname="unnamed_btutest.nc"; 00163 ierr = PetscOptionsBegin(grid.com, "", "BTU_TEST options", ""); CHKERRQ(ierr); 00164 { 00165 ierr = PISMOptionsString("-o", "Output file name", outname, flag); CHKERRQ(ierr); 00166 ierr = PISMOptionsReal("-ys", "starting time in years", grid.start_year, flag); CHKERRQ(ierr); 00167 ierr = PISMOptionsReal("-ye", "starting time in years", grid.end_year, flag); CHKERRQ(ierr); 00168 ierr = PISMOptionsReal("-dt", "Time-step, in years", dt_years, flag); CHKERRQ(ierr); 00169 ierr = PISMOptionsInt("-Mz", "number of vertical layers in ice", grid.Mz, flag); CHKERRQ(ierr); 00170 ierr = PISMOptionsReal("-Lz", "height of ice/atmosphere boxr", grid.Lz, flag); CHKERRQ(ierr); 00171 } 00172 ierr = PetscOptionsEnd(); CHKERRQ(ierr); 00173 00174 // complete grid initialization based on user options 00175 grid.compute_nprocs(); 00176 grid.compute_ownership_ranges(); 00177 ierr = grid.compute_horizontal_spacing(); CHKERRQ(ierr); 00178 ierr = grid.compute_vertical_levels(); CHKERRQ(ierr); 00179 ierr = grid.createDA(); CHKERRQ(ierr); 00180 00181 // allocate tools and IceModelVecs 00182 PISMVars variables; 00183 ierr = createVecs(grid, variables); CHKERRQ(ierr); 00184 00185 // these vars are owned by this driver, outside of PISMBedThermalUnit 00186 IceModelVec2S *bedtoptemp, *ghf; 00187 00188 // top of bedrock layer temperature; filled from Test K exact values 00189 bedtoptemp = dynamic_cast<IceModelVec2S*>(variables.get("bedtoptemp")); 00190 if (bedtoptemp == NULL) SETERRQ(1, "bedtoptemp is not available"); 00191 00192 // lithosphere (bottom of bedrock layer) heat flux; has constant value 00193 ghf = dynamic_cast<IceModelVec2S*>(variables.get("bheatflx")); 00194 if (ghf == NULL) SETERRQ(2, "bheatflx is not available"); 00195 ierr = ghf->set(0.042); CHKERRQ(ierr); // see Test K 00196 00197 // initialize BTU object: 00198 BTU_Test btu(grid, config); 00199 00200 ierr = btu.init(variables); CHKERRQ(ierr); // FIXME: this is bootstrapping, really 00201 00202 // worry about time step 00203 int N = (int)ceil((grid.end_year - grid.start_year) / dt_years); 00204 PetscReal old_dt_years = dt_years; 00205 dt_years = (grid.end_year - grid.start_year) / (double)N; 00206 ierr = verbPrintf(2,com, 00207 " user set timestep of %.4f years ...\n" 00208 " reset to %.4f years to get integer number of steps ... \n", 00209 old_dt_years,dt_years); CHKERRQ(ierr); 00210 PetscReal max_dt_years; 00211 ierr = btu.max_timestep(0.0, max_dt_years); CHKERRQ(ierr); 00212 ierr = verbPrintf(2,com, 00213 " PISMBedThermalUnit reports max timestep of %.4f years ...\n", 00214 max_dt_years); CHKERRQ(ierr); 00215 00216 00217 // actually do the time-stepping 00218 ierr = verbPrintf(2,com," running ...\n "); CHKERRQ(ierr); 00219 for (PetscInt n = 0; n < N; n++) { 00220 const PetscReal y = grid.start_year + dt_years * (double)n; // time at start of time-step 00221 00222 // compute exact ice temperature at z=0 at time y 00223 ierr = bedtoptemp->begin_access(); CHKERRQ(ierr); 00224 for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) { 00225 for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) { 00226 PetscReal TT, FF; // Test K: use TT, ignore FF 00227 ierr = exactK(y * secpera, 0.0, &TT, &FF, 0); CHKERRQ(ierr); 00228 (*bedtoptemp)(i,j) = TT; 00229 } 00230 } 00231 ierr = bedtoptemp->end_access(); CHKERRQ(ierr); 00232 // we are not communicating anything, which is fine 00233 00234 // update the temperature inside the thermal layer using bedtoptemp 00235 ierr = btu.update(y, dt_years); CHKERRQ(ierr); 00236 ierr = verbPrintf(2,com,"."); CHKERRQ(ierr); 00237 } 00238 00239 ierr = verbPrintf(2,com,"\n done ...\n"); CHKERRQ(ierr); 00240 00241 // compute final output heat flux G_0 at z=0; reuse ghf for this purpose 00242 ierr = ghf->set_name("bheatflx0"); CHKERRQ(ierr); 00243 ierr = ghf->set_attrs("", 00244 "upward geothermal flux at ice/bedrock interface", 00245 "W m-2", ""); CHKERRQ(ierr); 00246 ierr = btu.get_upward_geothermal_flux(*ghf); CHKERRQ(ierr); 00247 00248 // get, and tell stdout, the correct answer from Test K 00249 PetscReal TT, FF; // Test K: use FF, ignore TT 00250 ierr = exactK(grid.end_year * secpera, 0.0, &TT, &FF, 0); CHKERRQ(ierr); 00251 ierr = verbPrintf(2,com, 00252 " exact Test K reports upward heat flux at z=0, at end year %.2f, as G_0 = %.7f W m-2;\n", 00253 grid.end_year,FF); CHKERRQ(ierr); 00254 00255 // compute numerical error 00256 PetscReal maxghferr, avghferr; 00257 ierr = ghf->shift(-FF); CHKERRQ(ierr); 00258 ierr = ghf->norm(NORM_INFINITY,maxghferr); CHKERRQ(ierr); 00259 ierr = ghf->norm(NORM_1,avghferr); CHKERRQ(ierr); 00260 ierr = ghf->shift(+FF); CHKERRQ(ierr); // shift it back for writing 00261 avghferr /= (grid.Mx * grid.My); 00262 ierr = verbPrintf(2,grid.com, 00263 "case dt = %.5f:\n", dt_years); CHKERRQ(ierr); 00264 ierr = verbPrintf(1,grid.com, 00265 "NUMERICAL ERRORS in upward heat flux at z=0 relative to exact solution:\n"); 00266 CHKERRQ(ierr); 00267 ierr = verbPrintf(1,grid.com, 00268 "bheatflx0 : max prcntmax av\n"); CHKERRQ(ierr); 00269 ierr = verbPrintf(1,grid.com, 00270 " %11.7f %11.7f %11.7f\n", 00271 maxghferr,100.0*maxghferr/FF,avghferr); CHKERRQ(ierr); 00272 ierr = verbPrintf(1,grid.com, "NUM ERRORS DONE\n"); CHKERRQ(ierr); 00273 00274 set<string> vars; 00275 btu.add_vars_to_output("big", vars); // "write everything you can" 00276 00277 PISMIO pio(&grid); 00278 00279 ierr = pio.open_for_writing(outname, false, true); CHKERRQ(ierr); 00280 // append == true and check_dims == true 00281 ierr = pio.append_time(grid.end_year); CHKERRQ(ierr); 00282 ierr = btu.define_variables(vars, pio, NC_DOUBLE); CHKERRQ(ierr); 00283 ierr = pio.close(); CHKERRQ(ierr); 00284 00285 ierr = btu.write_variables(vars, outname); CHKERRQ(ierr); 00286 ierr = bedtoptemp->write(outname.c_str()); CHKERRQ(ierr); 00287 ierr = ghf->write(outname.c_str()); CHKERRQ(ierr); 00288 00289 ierr = doneWithIceInfo(variables); CHKERRQ(ierr); 00290 ierr = verbPrintf(2,com, "done.\n"); CHKERRQ(ierr); 00291 } 00292 00293 ierr = PetscFinalize(); CHKERRQ(ierr); 00294 return 0; 00295 } 00296
1.7.3