PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/energy/btutest.cc

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