PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/pclimate.cc

Go to the documentation of this file.
00001 // Copyright (C) 2009, 2010, 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   "Driver for testing PISM's boundary (surface and shelf-base) models without IceModel.\n";
00021 
00022 #include <set>
00023 #include <ctime>
00024 #include <string>
00025 #include <sstream>
00026 #include <vector>
00027 #include <petscda.h>
00028 #include "pism_const.hh"
00029 #include "grid.hh"
00030 #include "LocalInterpCtx.hh"
00031 #include "PISMIO.hh"
00032 #include "NCVariable.hh"
00033 
00034 #include "coupler/PCFactory.hh"
00035 #include "coupler/PISMAtmosphere.hh"
00036 #include "coupler/PISMSurface.hh"
00037 #include "coupler/PISMOcean.hh"
00038 #include "eismint/pgrn_atmosphere.hh"
00039 
00040 static void create_pa_eismint_greenland(IceGrid& g, const NCConfigVariable& conf,
00041                                         PISMAtmosphereModel* &result) {
00042   result = new PA_EISMINT_Greenland(g, conf);
00043 }
00044 
00045 
00046 static PetscErrorCode setupIceGridFromFile(string filename, IceGrid &grid) {
00047   PetscErrorCode ierr;
00048 
00049   PISMIO nc(&grid);
00050   ierr = nc.get_grid(filename, "land_ice_thickness"); CHKERRQ(ierr);
00051   grid.compute_nprocs();
00052   grid.compute_ownership_ranges();
00053   ierr = grid.createDA(); CHKERRQ(ierr);  
00054   return 0;
00055 }
00056 
00057 static PetscErrorCode createVecs(IceGrid &grid, PISMVars &variables) {
00058   
00059   PetscErrorCode ierr;
00060   IceModelVec2S *lat, *lon, *mask, *thk, *surfelev, *topg, *acab, *artm, *shelfbasetemp, *shelfbasemassflux;
00061 
00062   lat      = new IceModelVec2S;
00063   lon      = new IceModelVec2S;
00064   mask     = new IceModelVec2S;
00065   thk      = new IceModelVec2S;
00066   surfelev = new IceModelVec2S;
00067   topg     = new IceModelVec2S;
00068   
00069   // the following are allocated by the pclimate code, but may or may not
00070   //   actually be read by PISMAtmosphereModel *atmosphere and PISMOceanModel *ocean
00071   acab     = new IceModelVec2S;
00072   artm     = new IceModelVec2S;
00073   shelfbasetemp     = new IceModelVec2S;
00074   shelfbasemassflux = new IceModelVec2S;
00075 
00076   ierr = lat->create(grid, "lat", true); CHKERRQ(ierr);
00077   ierr = lat->set_attrs("mapping", "latitude", "degrees_north", "latitude"); CHKERRQ(ierr);
00078   ierr = variables.add(*lat); CHKERRQ(ierr);
00079 
00080   ierr = lon->create(grid, "lon", true); CHKERRQ(ierr);
00081   ierr = lon->set_attrs("mapping", "longitude", "degrees_east", "longitude"); CHKERRQ(ierr);
00082   ierr = variables.add(*lon); CHKERRQ(ierr);
00083 
00084   ierr = mask->create(grid, "mask", true); CHKERRQ(ierr);
00085   ierr = mask->set_attrs("", "grounded_dragging_floating integer mask",
00086                               "", ""); CHKERRQ(ierr);
00087   ierr = variables.add(*mask); CHKERRQ(ierr);
00088 
00089   ierr = thk->create(grid, "thk", true); CHKERRQ(ierr);
00090   ierr = thk->set_attrs("", "land ice thickness",
00091                              "m", "land_ice_thickness"); CHKERRQ(ierr);
00092   ierr = variables.add(*thk); CHKERRQ(ierr);
00093 
00094   ierr = surfelev->create(grid, "usurf", true); CHKERRQ(ierr);
00095   ierr = surfelev->set_attrs("", "ice upper surface elevation",
00096                                   "m", "surface_altitude"); CHKERRQ(ierr);
00097   ierr = variables.add(*surfelev); CHKERRQ(ierr);
00098 
00099   ierr = topg->create(grid, "topg", true); CHKERRQ(ierr);
00100   ierr = topg->set_attrs("", "bedrock surface elevation",
00101                         "m", "bedrock_altitude"); CHKERRQ(ierr);
00102   ierr = variables.add(*topg); CHKERRQ(ierr);
00103 
00104   ierr = artm->create(grid, "artm", false); CHKERRQ(ierr);
00105   ierr = artm->set_attrs("climate_state",
00106                          "annual average ice surface temperature, below firn processes",
00107                          "K",
00108                          ""); CHKERRQ(ierr);
00109   ierr = variables.add(*artm); CHKERRQ(ierr);
00110 
00111   ierr = acab->create(grid, "acab", false); CHKERRQ(ierr);
00112   ierr = acab->set_attrs("climate_state", 
00113                          "ice-equivalent surface mass balance (accumulation/ablation) rate",
00114                          "m s-1", 
00115                          ""); CHKERRQ(ierr);
00116   ierr = acab->set_glaciological_units("m year-1"); CHKERRQ(ierr);
00117   acab->write_in_glaciological_units = true;
00118   ierr = variables.add(*acab); CHKERRQ(ierr);
00119 
00120   ierr = shelfbasetemp->create(grid, "shelfbasetemp", false); CHKERRQ(ierr); // no ghosts; NO HOR. DIFF.!
00121   ierr = shelfbasetemp->set_attrs(
00122                                  "climate_state", "absolute temperature at ice shelf base",
00123                                  "K", ""); CHKERRQ(ierr);
00124   // PROPOSED standard name = ice_shelf_basal_temperature
00125   ierr = variables.add(*shelfbasetemp); CHKERRQ(ierr);
00126 
00127   // ice mass balance rate at the base of the ice shelf; sign convention for vshelfbasemass
00128   //   matches standard sign convention for basal melt rate of grounded ice
00129   ierr = shelfbasemassflux->create(grid, "shelfbasemassflux", false); CHKERRQ(ierr); // no ghosts; NO HOR. DIFF.!
00130   ierr = shelfbasemassflux->set_attrs("climate_state",
00131                                      "ice mass flux from ice shelf base (positive flux is loss from ice shelf)",
00132                                      "m s-1", ""); CHKERRQ(ierr);
00133   // PROPOSED standard name = ice_shelf_basal_specific_mass_balance
00134   shelfbasemassflux->write_in_glaciological_units = true;
00135   ierr = shelfbasemassflux->set_glaciological_units("m year-1"); CHKERRQ(ierr);
00136   ierr = variables.add(*shelfbasemassflux); CHKERRQ(ierr);
00137 
00138 
00139   return 0;
00140 }
00141 
00142 static PetscErrorCode readIceInfoFromFile(const char *filename, int start,
00143                                           PISMVars &variables) {
00144   PetscErrorCode ierr;
00145   // Get the names of all the variables allocated earlier:
00146   set<string> vars = variables.keys();
00147 
00148   // Remove artm, acab, shelfbasemassflux and shelfbasetemp: they are filled by
00149   // surface and ocean models and aren't necessarily read from files.
00150   vars.erase("artm");
00151   vars.erase("acab");
00152   vars.erase("shelfbasemassflux");
00153   vars.erase("shelfbasetemp");
00154 
00155   set<string>::iterator i = vars.begin();
00156   while (i != vars.end()) {
00157     IceModelVec *var = variables.get(*i);
00158     ierr = var->read(filename, start); CHKERRQ(ierr);
00159     i++;
00160   }
00161 
00162   return 0;
00163 }
00164 
00165 
00166 static PetscErrorCode doneWithIceInfo(PISMVars &variables) {
00167   // Get the names of all the variables allocated earlier:
00168   set<string> vars = variables.keys();
00169 
00170   set<string>::iterator i = vars.begin();
00171   while (i != vars.end()) {
00172     IceModelVec *var = variables.get(*i);
00173     delete var;
00174     i++;
00175   }
00176 
00177   return 0;
00178 }
00179 
00180 
00181 static PetscErrorCode writePCCStateAtTimes(PISMVars &variables,
00182                                            PISMSurfaceModel *surface,
00183                                            PISMOceanModel* ocean,
00184                                            const char *filename, IceGrid* grid,
00185                                            PetscReal ys, PetscReal ye, PetscReal dt_years,
00186                                            NCConfigVariable &mapping) {
00187 
00188   MPI_Comm com = grid->com;
00189   PetscErrorCode ierr;
00190   PISMIO nc(grid);
00191   NCGlobalAttributes global_attrs;
00192   IceModelVec2S *usurf, *artm, *acab, *shelfbasetemp, *shelfbasemassflux;
00193 
00194   usurf = dynamic_cast<IceModelVec2S*>(variables.get("surface_altitude"));
00195   if (usurf == NULL) { SETERRQ(1, "usurf is not available"); }
00196 
00197   artm = dynamic_cast<IceModelVec2S*>(variables.get("artm"));
00198   if (artm == NULL) { SETERRQ(1, "artm is not available"); }
00199 
00200   acab = dynamic_cast<IceModelVec2S*>(variables.get("acab"));
00201   if (acab == NULL) { SETERRQ(1, "acab is not available"); }
00202 
00203   shelfbasetemp = dynamic_cast<IceModelVec2S*>(variables.get("shelfbasetemp"));
00204   if (shelfbasetemp == NULL) { SETERRQ(1, "shelfbasetemp is not available"); }
00205 
00206   shelfbasemassflux = dynamic_cast<IceModelVec2S*>(variables.get("shelfbasemassflux"));
00207   if (shelfbasemassflux == NULL) { SETERRQ(1, "shelfbasemassflux is not available"); }
00208 
00209   global_attrs.init("global_attributes", com, grid->rank);
00210   global_attrs.set_string("Conventions", "CF-1.4");
00211   global_attrs.set_string("source", string("pclimate ") + PISM_Revision);
00212 
00213   // Create a string with space-separated command-line arguments:
00214   string history = pism_username_prefix() + pism_args_string();
00215 
00216   global_attrs.prepend_history(history);
00217 
00218   ierr = nc.open_for_writing(filename, false, true); CHKERRQ(ierr);
00219   // append == false, check_dims == true
00220   ierr = nc.close(); CHKERRQ(ierr);
00221 
00222   ierr = mapping.write(filename); CHKERRQ(ierr);
00223   ierr = global_attrs.write(filename); CHKERRQ(ierr);
00224 
00225   PetscInt NN;  // get number of times at which PISM boundary model state is written
00226   NN = (int) ceil((ye - ys) / dt_years);
00227   if (NN > 1000)
00228     SETERRQ(2,"PCLIMATE ERROR: refuse to write more than 1000 times!");
00229   if (NN > 50) {
00230     ierr = PetscPrintf(com,
00231         "\nPCLIMATE ATTENTION: writing more than 50 times to '%s'!!\n\n",
00232         filename); CHKERRQ(ierr);
00233   }
00234 
00235   DiagnosticTimeseries sea_level(grid, "sea_level", "t");
00236   sea_level.set_units("m", "m");
00237   sea_level.set_dimension_units("years", "");
00238   sea_level.output_filename = filename;
00239   sea_level.set_attr("long_name", "sea level elevation");
00240 
00241   PetscScalar use_dt_years = dt_years;
00242 
00243   set<string> vars_to_write;
00244   surface->add_vars_to_output("big", vars_to_write);
00245   ocean->add_vars_to_output("big", vars_to_write);
00246 
00247   // write the states
00248   for (PetscInt k=0; k < NN; k++) {
00249     // use original dt_years to get correct subinterval starts:
00250     const PetscReal pccyear = ys + k * dt_years; 
00251     ierr = nc.open_for_writing(filename, true, false); CHKERRQ(ierr); // append=true,check_dims=false
00252     ierr = nc.append_time(pccyear); CHKERRQ(ierr);
00253     
00254     PetscScalar dt_update_years = PetscMin(use_dt_years, ye - pccyear);
00255 
00256     char timestr[TEMPORARY_STRING_LENGTH];
00257     snprintf(timestr, sizeof(timestr), 
00258         "  boundary models updated for [%11.3f a,%11.3f a] ...", 
00259         pccyear, pccyear + dt_update_years);
00260     ierr = verbPrintf(2,com,"."); CHKERRQ(ierr);
00261     ierr = verbPrintf(3,com,"\n%s writing result to %s ..",timestr,filename); CHKERRQ(ierr);
00262     strncat(timestr,"\n",1);
00263     ierr = nc.write_history(timestr); CHKERRQ(ierr); // append the history
00264     ierr = nc.close(); CHKERRQ(ierr);
00265 
00266     ierr = usurf->write(filename, NC_FLOAT); CHKERRQ(ierr);
00267 
00268     // update surface and ocean models' outputs:
00269     ierr = surface->update(pccyear, dt_update_years); CHKERRQ(ierr);
00270     ierr = ocean->update(pccyear, dt_update_years); CHKERRQ(ierr);
00271 
00272     ierr = surface->ice_surface_mass_flux(*acab); CHKERRQ(ierr);
00273     ierr = surface->ice_surface_temperature(*artm); CHKERRQ(ierr);
00274 
00275     PetscReal current_sea_level;
00276     ierr = ocean->sea_level_elevation(current_sea_level); CHKERRQ(ierr);
00277 
00278     sea_level.append(pccyear, current_sea_level);
00279     sea_level.interp(pccyear);
00280 
00281     // ask ocean and surface models to write variables:
00282     ierr = surface->write_variables(vars_to_write, filename); CHKERRQ(ierr);
00283     ierr = ocean->write_variables(vars_to_write, filename); CHKERRQ(ierr);
00284 
00285     // This ensures that even if a surface model wrote artm and acab we
00286     // over-write them with values that were actually used by IceModel.
00287     ierr = acab->write(filename, NC_FLOAT); CHKERRQ(ierr);
00288     ierr = artm->write(filename, NC_FLOAT); CHKERRQ(ierr);
00289   }
00290   ierr = verbPrintf(2,com,"\n"); CHKERRQ(ierr);
00291 
00292   return 0;
00293 }
00294 
00295 
00296 int main(int argc, char *argv[]) {
00297   PetscErrorCode  ierr;
00298 
00299   MPI_Comm    com;
00300   PetscMPIInt rank, size;
00301 
00302   ierr = PetscInitialize(&argc, &argv, PETSC_NULL, help); CHKERRQ(ierr);
00303 
00304   com = PETSC_COMM_WORLD;
00305   ierr = MPI_Comm_rank(com, &rank); CHKERRQ(ierr);
00306   ierr = MPI_Comm_size(com, &size); CHKERRQ(ierr);
00307 
00308   /* This explicit scoping forces destructors to be called before PetscFinalize() */
00309   {
00310     NCConfigVariable config, overrides, mapping;
00311     string inname, outname;
00312 
00313     ierr = verbosityLevelFromOptions(); CHKERRQ(ierr);
00314 
00315     ierr = verbPrintf(2,com,
00316       "PCLIMATE %s (surface and shelf-base boundary-models-only mode)\n",
00317       PISM_Revision); CHKERRQ(ierr);
00318     ierr = stop_on_version_option(); CHKERRQ(ierr);
00319 
00320     // check required options
00321     vector<string> required;
00322     required.push_back("-i");
00323     required.push_back("-o");
00324     required.push_back("-ys");
00325     required.push_back("-ye");
00326     required.push_back("-dt");
00327     ierr = show_usage_check_req_opts(com, "pclimate", required,
00328       "  pclimate -i IN.nc -o OUT.nc -ys A -ye B -dt C [-atmosphere <name> -surface <name>] [OTHER PISM & PETSc OPTIONS]\n"
00329       "where:\n"
00330       "  -i             input file in NetCDF format\n"
00331       "  -o             output file in NetCDF format\n"
00332       "  -ys            start time A (= float) in years\n"
00333       "  -ye            end time B (= float), B > A, in years\n"
00334       "  -dt            time step C (= positive float) in years\n"
00335       "and set up the models:\n"
00336       "  -atmosphere    Chooses an atmosphere model; see User's Manual\n"
00337       "  -surface       Chooses a surface model; see User's Manual\n"
00338       "  -ocean         Chooses an ocean model; see User's Manual\n"
00339       ); CHKERRQ(ierr);
00340 
00341     // read the config option database:
00342     ierr = init_config(com, rank, config, overrides); CHKERRQ(ierr);
00343 
00344     bool override_used;
00345     ierr = PISMOptionsIsSet("-config_override", override_used); CHKERRQ(ierr);
00346 
00347     // set an un-documented (!) flag to limit time-steps to 1 year.
00348     config.set_flag("pdd_limit_timestep", true);
00349 
00350     IceGrid grid(com, rank, size, config);
00351     
00352     bool flag;
00353     PetscReal ys = 0.0, ye = 0.0, dt_years = 0.0;
00354     ierr = PetscOptionsBegin(grid.com, "", "PCLIMATE options", ""); CHKERRQ(ierr);
00355     {
00356       ierr = PISMOptionsString("-i", "Input file name",  inname, flag); CHKERRQ(ierr);
00357       ierr = PISMOptionsString("-o", "Output file name", outname, flag); CHKERRQ(ierr);
00358 
00359       ierr = PISMOptionsReal("-ys", "Start year", ys, flag); CHKERRQ(ierr);
00360       ierr = PISMOptionsReal("-ye", "End year",   ye, flag); CHKERRQ(ierr);
00361       ierr = PISMOptionsReal("-dt", "Time-step, in years", dt_years, flag); CHKERRQ(ierr);
00362     }
00363     ierr = PetscOptionsEnd(); CHKERRQ(ierr);
00364 
00365     // initialize the computational grid:
00366     ierr = verbPrintf(2,com, 
00367                       "  initializing grid from NetCDF file %s...\n", inname.c_str()); CHKERRQ(ierr);
00368     ierr = setupIceGridFromFile(inname,grid); CHKERRQ(ierr);
00369 
00370     mapping.init("mapping", com, rank);
00371 
00372     // These values may be used by surface, atmosphere of ocean models:
00373     grid.year = ys;             
00374     grid.start_year = ys;
00375     grid.end_year = ye;
00376 
00377     // allocate IceModelVecs needed by boundary models and put them in a dictionary:
00378     PISMVars variables;
00379     ierr = createVecs(grid, variables); CHKERRQ(ierr);
00380 
00381     // read data from a PISM input file (including the projection parameters)
00382     NCTool nc(grid.com, grid.rank);
00383     int last_record;
00384     bool mapping_exists;
00385     ierr = nc.open_for_reading(inname.c_str()); CHKERRQ(ierr);
00386     ierr = nc.find_variable("mapping", NULL, mapping_exists); CHKERRQ(ierr);
00387     ierr = nc.get_nrecords(last_record); CHKERRQ(ierr);
00388     ierr = nc.close(); CHKERRQ(ierr);
00389     if (mapping_exists) {
00390       ierr = mapping.read(inname.c_str()); CHKERRQ(ierr);
00391       ierr = mapping.print(); CHKERRQ(ierr);
00392     }
00393     last_record -= 1;
00394 
00395     ierr = verbPrintf(2,com, 
00396              "  reading fields lat,lon,mask,thk,topg,usurf from NetCDF file %s\n"
00397              "    to fill fields in PISMVars ...\n",
00398                       inname.c_str()); CHKERRQ(ierr);
00399 
00400     ierr = readIceInfoFromFile(inname.c_str(), last_record, variables); CHKERRQ(ierr);
00401 
00402     // Initialize boundary models:
00403     PAFactory pa(grid, config);
00404     PISMAtmosphereModel *atmosphere;
00405     pa.add_model("eismint_greenland", &create_pa_eismint_greenland);
00406 
00407     PSFactory ps(grid, config);
00408     PISMSurfaceModel *surface;
00409 
00410     POFactory po(grid, config);
00411     PISMOceanModel *ocean;
00412 
00413     ierr = PetscOptionsBegin(grid.com, "", "PISM Boundary Models", ""); CHKERRQ(ierr);
00414 
00415     pa.create(atmosphere);
00416     ps.create(surface);
00417     po.create(ocean);
00418 
00419     surface->attach_atmosphere_model(atmosphere);
00420     ierr = surface->init(variables); CHKERRQ(ierr);
00421     ierr = ocean->init(variables); CHKERRQ(ierr);
00422 
00423     ierr = PetscOptionsEnd(); CHKERRQ(ierr);  // done initializing boundary models.
00424 
00425     ierr = verbPrintf(2, com,
00426         "writing boundary model states to NetCDF file '%s' ...\n",
00427         outname.c_str()); CHKERRQ(ierr);
00428 
00429     ierr = writePCCStateAtTimes(variables, surface, ocean,
00430                                 outname.c_str(), &grid,
00431                                 ys, ye, dt_years,
00432                                 mapping); CHKERRQ(ierr);
00433 
00434     if (override_used) {
00435       ierr = verbPrintf(3, com,
00436         "  recording config overrides in NetCDF file '%s' ...\n",
00437         outname.c_str()); CHKERRQ(ierr);
00438       overrides.update_from(config);
00439       ierr = overrides.write(outname.c_str()); CHKERRQ(ierr);
00440     }
00441 
00442     delete surface;
00443     delete ocean;
00444     ierr = doneWithIceInfo(variables); CHKERRQ(ierr);
00445 
00446     ierr = verbPrintf(2,com, "done.\n"); CHKERRQ(ierr);
00447     
00448   }
00449 
00450   ierr = PetscFinalize(); CHKERRQ(ierr);
00451   return 0;
00452 }
00453 
00454 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines