PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/coupler/PISMSurface.cc

Go to the documentation of this file.
00001 // Copyright (C) 2008-2011 Ed Bueler, Constantine Khroulev, Ricarda Winkelmann,
00002 // Gudfinna Adalgeirsdottir and Andy Aschwanden
00003 //
00004 // This file is part of PISM.
00005 //
00006 // PISM is free software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the Free Software
00008 // Foundation; either version 2 of the License, or (at your option) any later
00009 // version.
00010 //
00011 // PISM is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
00014 // details.
00015 //
00016 // You should have received a copy of the GNU General Public License
00017 // along with PISM; if not, write to the Free Software
00018 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019 
00020 #include "PISMSurface.hh"
00021 #include "PISMIO.hh"
00022 
00024 
00025 void PISMSurfaceModel::attach_atmosphere_model(PISMAtmosphereModel *input) {
00026   if (atmosphere != NULL) {
00027     delete atmosphere;
00028   }
00029   atmosphere = input;
00030 }
00031 
00032 PetscErrorCode PISMSurfaceModel::init(PISMVars &vars) {
00033   PetscErrorCode ierr;
00034 
00035   if (atmosphere == NULL)
00036     SETERRQ(1, "PISMSurfaceModel::init(PISMVars &vars): atmosphere == NULL");
00037 
00038   ierr = atmosphere->init(vars); CHKERRQ(ierr);
00039 
00040   return 0;
00041 }
00042 
00044 
00048 PetscErrorCode PISMSurfaceModel::mass_held_in_surface_layer(IceModelVec2S &result) {
00049   PetscErrorCode ierr;
00050 
00051   ierr = result.set(0.0); CHKERRQ(ierr);
00052 
00053   return 0;
00054 }
00055 
00059 
00063 PetscErrorCode PISMSurfaceModel::surface_layer_thickness(IceModelVec2S &result) {
00064   PetscErrorCode ierr;
00065 
00066   ierr = result.set(0.0); CHKERRQ(ierr);
00067 
00068   return 0;
00069 }
00070 
00072 
00075 PetscErrorCode PISMSurfaceModel::ice_surface_liquid_water_fraction(IceModelVec2S &result) {
00076   PetscErrorCode ierr;
00077 
00078   ierr = result.set(0.0); CHKERRQ(ierr);
00079 
00080   return 0;
00081 }
00082 
00083 PetscErrorCode PISMSurfaceModel::define_variables(set<string> vars, const NCTool &nc, nc_type nctype) {
00084   PetscErrorCode ierr;
00085 
00086   if (atmosphere != NULL) {
00087     ierr = atmosphere->define_variables(vars, nc, nctype); CHKERRQ(ierr);
00088   }
00089 
00090   return 0;
00091 }
00092 
00093 PetscErrorCode PISMSurfaceModel::write_variables(set<string> vars, string filename) {
00094   PetscErrorCode ierr;
00095 
00096   if (atmosphere != NULL) {
00097     ierr = atmosphere->write_variables(vars, filename); CHKERRQ(ierr);
00098   }
00099 
00100   return 0;
00101 }
00102 
00104 
00105 PetscErrorCode PSSimple::init(PISMVars &vars) {
00106   PetscErrorCode ierr;
00107 
00108   if (atmosphere == NULL)
00109     SETERRQ(1, "PISMSurfaceModel::init(PISMVars &vars): atmosphere == NULL");
00110 
00111   ierr = atmosphere->init(vars); CHKERRQ(ierr);
00112 
00113   ierr = verbPrintf(2, grid.com,
00114      "* Initializing the simplest PISM surface (snow) processes model PSSimple.\n"
00115      "  It passes atmospheric state directly to upper ice fluid surface:\n"
00116      "    surface mass balance          := precipitation,\n"
00117      "    ice upper surface temperature := 2m air temperature.\n");
00118      CHKERRQ(ierr);
00119   return 0;
00120 }
00121 
00122 PetscErrorCode PSSimple::ice_surface_mass_flux(IceModelVec2S &result) {
00123   PetscErrorCode ierr;
00124   ierr = atmosphere->mean_precip(result); CHKERRQ(ierr);
00125 
00126   string history = result.string_attr("history");
00127   history = "re-interpreted precipitation as surface mass balance (PSSimple)\n" + history;
00128   ierr = result.set_attr("history", history); CHKERRQ(ierr);
00129 
00130   return 0;
00131 }
00132 
00133 PetscErrorCode PSSimple::ice_surface_temperature(IceModelVec2S &result) {
00134   PetscErrorCode ierr;
00135   ierr = atmosphere->mean_annual_temp(result); CHKERRQ(ierr);
00136 
00137   string history = result.string_attr("history");
00138   history = "re-interpreted mean annual 2 m air temperature as instantaneous ice temperature at the ice surface (PSSimple)\n" + history;
00139   ierr = result.set_attr("history", history); CHKERRQ(ierr);
00140 
00141   return 0;
00142 }
00143 
00144 void PSSimple::add_vars_to_output(string keyword, set<string> &result) {
00145   atmosphere->add_vars_to_output(keyword, result);
00146 }
00147 
00149 
00150 PetscErrorCode PSConstant::init(PISMVars &/*vars*/) {
00151   PetscErrorCode ierr;
00152   bool regrid = false;
00153   int start = -1;
00154 
00155   ierr = verbPrintf(2, grid.com, 
00156      "* Initializing the constant-in-time surface processes model PSConstant.\n"
00157      "  It reads surface mass balance and ice upper-surface temperature\n"
00158      "  directly from the file and holds them constant.\n"
00159      "  Any choice of atmosphere coupler (option '-atmosphere') is ignored.\n"); CHKERRQ(ierr);
00160 
00161   // allocate IceModelVecs for storing temperature and surface mass balance fields
00162 
00163   // create mean annual ice equivalent snow precipitation rate (before melt, and not including rain)
00164   ierr = acab.create(grid, "acab", false); CHKERRQ(ierr);
00165   ierr = acab.set_attrs("climate_state", 
00166                         "constant-in-time ice-equivalent surface mass balance (accumulation/ablation) rate",
00167                         "m s-1", 
00168                         "land_ice_surface_specific_mass_balance"); // CF standard_name
00169                         CHKERRQ(ierr);
00170   ierr = acab.set_glaciological_units("m year-1"); CHKERRQ(ierr);
00171   acab.write_in_glaciological_units = true;
00172 
00173   ierr = artm.create(grid, "artm", false); CHKERRQ(ierr);
00174   ierr = artm.set_attrs("climate_state",
00175                         "constant-in-time ice temperature at the ice surface",
00176                         "K",
00177                         ""); CHKERRQ(ierr);
00178   
00179   // find PISM input file to read data from:
00180   ierr = find_pism_input(input_file, regrid, start); CHKERRQ(ierr);
00181 
00182   // read snow precipitation rate and temperatures from file
00183   ierr = verbPrintf(2, grid.com, 
00184     "    reading ice-equivalent surface mass balance rate 'acab'\n"
00185     "    and ice surface temperature  'artm' from %s ... \n",
00186     input_file.c_str()); CHKERRQ(ierr); 
00187   if (regrid) {
00188     ierr = acab.regrid(input_file.c_str(), true); CHKERRQ(ierr); // fails if not found!
00189     ierr = artm.regrid(input_file.c_str(), true); CHKERRQ(ierr); // fails if not found!
00190   } else {
00191     ierr = acab.read(input_file.c_str(), start); CHKERRQ(ierr); // fails if not found!
00192     ierr = artm.read(input_file.c_str(), start); CHKERRQ(ierr); // fails if not found!
00193   }
00194 
00195 
00196   return 0;
00197 }
00198 
00199 PetscErrorCode PSConstant::ice_surface_mass_flux(IceModelVec2S &result) {
00200   PetscErrorCode ierr;
00201   string history  = "read from " + input_file + "\n";
00202 
00203   ierr = acab.copy_to(result); CHKERRQ(ierr);
00204   ierr = result.set_attr("history", history); CHKERRQ(ierr);
00205 
00206   return 0;
00207 }
00208 
00209 PetscErrorCode PSConstant::ice_surface_temperature(IceModelVec2S &result) {
00210   PetscErrorCode ierr;
00211   string history  = "read from " + input_file + "\n";
00212 
00213   ierr = artm.copy_to(result); CHKERRQ(ierr);
00214   ierr = result.set_attr("history", history); CHKERRQ(ierr);
00215 
00216   return 0;
00217 }
00218 
00219 void PSConstant::add_vars_to_output(string /*keyword*/, set<string> &result) {
00220   result.insert("acab");
00221   result.insert("artm");
00222   // does not call atmosphere->add_vars_to_output().
00223 }
00224 
00225 PetscErrorCode PSConstant::define_variables(set<string> vars, const NCTool &nc, nc_type nctype) {
00226   PetscErrorCode ierr;
00227 
00228   ierr = PISMSurfaceModel::define_variables(vars, nc, nctype); CHKERRQ(ierr);
00229 
00230   if (set_contains(vars, "artm")) {
00231     ierr = artm.define(nc, nctype); CHKERRQ(ierr); 
00232   }
00233 
00234   if (set_contains(vars, "acab")) {
00235     ierr = acab.define(nc, nctype); CHKERRQ(ierr); 
00236   }
00237 
00238   return 0;
00239 }
00240 
00241 PetscErrorCode PSConstant::write_variables(set<string> vars, string filename) {
00242   PetscErrorCode ierr;
00243 
00244   if (set_contains(vars, "artm")) {
00245     ierr = artm.write(filename.c_str()); CHKERRQ(ierr);
00246   }
00247 
00248   if (set_contains(vars, "acab")) {
00249     ierr = acab.write(filename.c_str()); CHKERRQ(ierr);
00250   }
00251 
00252   return 0;
00253 }
00254 
00256 
00257 PSTemperatureIndex::PSTemperatureIndex(IceGrid &g, const NCConfigVariable &conf)
00258   : PISMSurfaceModel(g, conf) {
00259   mbscheme = NULL;
00260   faustogreve = NULL;
00261   base_ddf.snow = config.get("pdd_factor_snow");
00262   base_ddf.ice  = config.get("pdd_factor_ice");
00263   base_ddf.refreezeFrac = config.get("pdd_refreeze");
00264   base_pddStdDev = config.get("pdd_std_dev");
00265   base_pddThresholdTemp = config.get("pdd_positive_threshold_temp");
00266 
00267   pdd_annualize = false;
00268 }
00269 
00270 PSTemperatureIndex::~PSTemperatureIndex() {
00271   delete mbscheme;
00272   delete faustogreve;
00273 }
00274 
00275 PetscErrorCode PSTemperatureIndex::init(PISMVars &vars) {
00276   PetscErrorCode ierr;
00277   bool           pdd_rand, pdd_rand_repeatable, fausto_params, pSet;
00278 
00279   ierr = PISMSurfaceModel::init(vars); CHKERRQ(ierr);
00280 
00281   ierr = PetscOptionsBegin(grid.com, "", 
00282                            "Temperature-index (PDD) scheme for surface (snow) processes", "");
00283                            CHKERRQ(ierr);
00284   {
00285     ierr = PISMOptionsIsSet("-pdd_rand",
00286                             "Use a PDD implementation based on simulating a random process",
00287                             pdd_rand); CHKERRQ(ierr);
00288     ierr = PISMOptionsIsSet("-pdd_rand_repeatable",
00289                             "Use a PDD implementation based on simulating a repeatable random process",
00290                             pdd_rand_repeatable); CHKERRQ(ierr);
00291     ierr = PISMOptionsIsSet("-pdd_fausto",
00292                             "Set PDD parameters using formulas (6) and (7) in [Faustoetal2009]",
00293                             fausto_params); CHKERRQ(ierr);
00294     ierr = PISMOptionsIsSet("-pdd_annualize",
00295                             "Compute annual mass balance, removing yearly variations",
00296                             pdd_annualize); CHKERRQ(ierr);
00297 
00298     ierr = PISMOptionsReal("-pdd_factor_snow", "PDD snow factor",
00299                            base_ddf.snow, pSet); CHKERRQ(ierr);
00300     ierr = PISMOptionsReal("-pdd_factor_ice", "PDD ice factor",
00301                            base_ddf.ice, pSet); CHKERRQ(ierr);
00302     ierr = PISMOptionsReal("-pdd_refreeze", "PDD refreeze fraction",
00303                            base_ddf.refreezeFrac, pSet); CHKERRQ(ierr);
00304 
00305     ierr = PISMOptionsReal("-pdd_std_dev", "PDD standard deviation",
00306                            base_pddStdDev, pSet); CHKERRQ(ierr);
00307     ierr = PISMOptionsReal("-pdd_positive_threshold_temp", 
00308                            "PDD uses this temp in K to determine 'positive' temperatures",
00309                            base_pddThresholdTemp, pSet); CHKERRQ(ierr);
00310   }
00311   ierr = PetscOptionsEnd(); CHKERRQ(ierr);
00312 
00313 
00314   ierr = verbPrintf(2, grid.com,
00315     "* Initializing the default temperature-index, PDD-based surface processes scheme.\n"
00316     "  Precipitation and 2m air temperature provided by atmosphere are inputs.\n"
00317     "  Surface mass balance and ice upper surface temperature are outputs.\n"
00318     "  See PISM User's Manual for control of degree-day factors.\n");
00319     CHKERRQ(ierr);
00320 
00321   ierr = verbPrintf(2, grid.com,
00322     "  Computing number of positive degree-days by: "); CHKERRQ(ierr);
00323   if (pdd_rand_repeatable) {
00324     ierr = verbPrintf(2, grid.com, "simulation of a random process.\n"); CHKERRQ(ierr);
00325     mbscheme = new PDDrandMassBalance(config, true);
00326   } else if (pdd_rand) {
00327     ierr = verbPrintf(2, grid.com, "repeatable simulation of a random process.\n");
00328       CHKERRQ(ierr);
00329     mbscheme = new PDDrandMassBalance(config, false);
00330   } else {
00331     ierr = verbPrintf(2, grid.com, "an expectation integral.\n"); CHKERRQ(ierr);
00332     mbscheme = new PDDMassBalance(config);
00333   }
00334 
00335   if (config.get_flag("pdd_limit_timestep")) {
00336     ierr = verbPrintf(2, grid.com, "  NOTE: Limiting time-steps to 1 year.\n"); CHKERRQ(ierr);
00337   }
00338 
00339   ierr = acab.create(grid, "acab", false); CHKERRQ(ierr);
00340   ierr = acab.set_attrs("diagnostic",
00341                         "instantaneous ice-equivalent surface mass balance (accumulation/ablation) rate",
00342                         "m s-1",  // m *ice-equivalent* per second
00343                         "land_ice_surface_specific_mass_balance");  // CF standard_name
00344                         CHKERRQ(ierr);
00345   ierr = acab.set_glaciological_units("m year-1"); CHKERRQ(ierr);
00346   acab.write_in_glaciological_units = true;
00347   ierr = acab.set_attr("comment", "positive values correspond to ice gain"); CHKERRQ(ierr); 
00348 
00349   // diagnostic fields:
00350 
00351   ierr = accumulation_rate.create(grid, "saccum", false); CHKERRQ(ierr);
00352   ierr = accumulation_rate.set_attrs("diagnostic",
00353                                      "instantaneous ice-equivalent surface accumulation rate (precip minus rain)",
00354                                      "m s-1",
00355                                      ""); CHKERRQ(ierr);
00356   ierr = accumulation_rate.set_glaciological_units("m year-1"); CHKERRQ(ierr);
00357   accumulation_rate.write_in_glaciological_units = true;
00358 
00359   ierr = melt_rate.create(grid, "smelt", false); CHKERRQ(ierr);
00360   ierr = melt_rate.set_attrs("diagnostic",
00361                              "instantaneous ice-equivalent surface melt rate",
00362                              "m s-1",
00363                              ""); CHKERRQ(ierr);
00364   ierr = melt_rate.set_glaciological_units("m year-1"); CHKERRQ(ierr);
00365   melt_rate.write_in_glaciological_units = true;
00366 
00367   ierr = runoff_rate.create(grid, "srunoff", false); CHKERRQ(ierr);
00368   ierr = runoff_rate.set_attrs("diagnostic",
00369                                "instantaneous ice-equivalent surface meltwater runoff rate",
00370                                "m s-1",
00371                                ""); CHKERRQ(ierr);
00372   ierr = runoff_rate.set_glaciological_units("m year-1"); CHKERRQ(ierr);
00373   runoff_rate.write_in_glaciological_units = true;
00374 
00375   if ((config.get("pdd_std_dev_lapse_lat_rate") != 0.0) || fausto_params) {
00376     lat = dynamic_cast<IceModelVec2S*>(vars.get("latitude"));
00377     if (!lat)
00378       SETERRQ(10, "ERROR: 'latitude' is not available or is wrong type in dictionary");
00379   } else
00380     lat = NULL;
00381 
00382 
00383   if (fausto_params) {
00384     ierr = verbPrintf(2, grid.com, 
00385        "  Setting PDD parameters using formulas (6) and (7) in [Faustoetal2009]...\n");
00386        CHKERRQ(ierr);
00387 
00388     lon = dynamic_cast<IceModelVec2S*>(vars.get("longitude"));
00389     if (!lon)
00390       SETERRQ(11, "ERROR: 'longitude' is not available or is wrong type in dictionary");
00391     usurf = dynamic_cast<IceModelVec2S*>(vars.get("usurf"));
00392     if (!usurf)
00393       SETERRQ(12, "ERROR: 'usurf' is not available or is wrong type in dictionary");
00394    
00395     faustogreve = new FaustoGrevePDDObject(grid, config);
00396   } else {
00397     // generally, this is the case in which degree day factors do not depend
00398     //   on location; we use base_ddf
00399     lon = NULL;
00400     usurf = NULL;
00401   }
00402 
00403   // if -pdd_annualize is set, update mass balance immediately (at the
00404   // beginning of the run)
00405   next_pdd_update_year = grid.year;
00406 
00407   return 0;
00408 }
00409 
00410 PetscErrorCode PSTemperatureIndex::max_timestep(PetscReal t_years, PetscReal &dt_years) {
00411   PetscErrorCode ierr;
00412 
00413   if (pdd_annualize) {
00414     if (PetscAbs(t_years - next_pdd_update_year) < 1e-12)
00415       dt_years = 1.0;
00416     else
00417       dt_years = next_pdd_update_year - t_years;
00418   } else {
00419     dt_years = -1;
00420   }
00421 
00422   PetscReal dt_atmosphere;
00423   ierr = atmosphere->max_timestep(t_years, dt_atmosphere); CHKERRQ(ierr);
00424 
00425   if (dt_atmosphere > 0)
00426     dt_years = PetscMin(dt_years, dt_atmosphere);
00427 
00428   return 0;
00429 }
00430 
00431 PetscErrorCode PSTemperatureIndex::update(PetscReal t_years, PetscReal dt_years) {
00432   PetscErrorCode ierr;
00433 
00434   if ((fabs(t_years - t) < 1e-12) &&
00435       (fabs(dt_years - dt) < 1e-12))
00436     return 0;
00437 
00438   t  = t_years;
00439   dt = dt_years;
00440 
00441   // This flag is set in pclimate to allow testing the model. It does not
00442   // affect the normal operation of PISM.
00443   if (config.get_flag("pdd_limit_timestep")) {
00444     dt_years = PetscMin(dt_years, 1.0);
00445   }
00446 
00447   if (pdd_annualize) {
00448     if (t_years + dt_years > next_pdd_update_year) {
00449       ierr = verbPrintf(3, grid.com, 
00450                         "  Updating mass balance for one year starting at %1.1f years...\n",
00451                         t_years);
00452       ierr = update_internal(t_years, 1.0); CHKERRQ(ierr);
00453       next_pdd_update_year = t_years + 1.0;
00454     }
00455   } else {
00456     ierr = update_internal(t_years, dt_years); CHKERRQ(ierr);
00457   }
00458 
00459   return 0;
00460 }
00461 
00462 PetscErrorCode PSTemperatureIndex::update_internal(PetscReal t_years, PetscReal dt_years) {
00463   PetscErrorCode ierr;
00464 
00465   // to ensure that temperature time series are correct:
00466   ierr = atmosphere->update(t_years, dt_years); CHKERRQ(ierr);
00467 
00468   // This is a point-wise (local) computation, so we can use "acab" to store
00469   // precipitation:
00470   ierr = atmosphere->mean_precip(acab); CHKERRQ(ierr);
00471 
00472   // set up air temperature time series
00473   PetscInt Nseries;
00474   ierr = mbscheme->getNForTemperatureSeries(t_years * secpera,
00475                                             dt_years * secpera, Nseries); CHKERRQ(ierr);
00476 
00477   const PetscScalar tseries = (t_years - floor(t_years)) * secpera,
00478     dtseries = (dt_years * secpera) / ((PetscScalar) Nseries);
00479 
00480   // times for the air temperature time-series, in years:
00481   vector<PetscScalar> ts(Nseries), T(Nseries);
00482   for (PetscInt k = 0; k < Nseries; ++k)
00483     ts[k] = t_years + k * dt_years / Nseries;
00484 
00485   if (lat != NULL) {
00486     ierr = lat->begin_access(); CHKERRQ(ierr);
00487   }
00488 
00489   if (faustogreve != NULL) {
00490     if (lat == NULL) { SETERRQ(1,"faustogreve object is allocated BUT lat==NULL"); }
00491     if (lon == NULL) { SETERRQ(2,"faustogreve object is allocated BUT lon==NULL"); }
00492     if (usurf == NULL) { SETERRQ(3,"faustogreve object is allocated BUT usurf==NULL"); }
00493     ierr = lon->begin_access(); CHKERRQ(ierr);
00494     ierr = usurf->begin_access(); CHKERRQ(ierr);
00495     ierr = faustogreve->update_temp_mj(usurf, lat, lon); CHKERRQ(ierr);
00496   }
00497 
00498   const PetscScalar sigmalapserate = config.get("pdd_std_dev_lapse_lat_rate"),
00499                     sigmabaselat   = config.get("pdd_std_dev_lapse_lat_base");
00500   if (sigmalapserate != 0.0) {
00501     if (lat == NULL) { SETERRQ(4,"pdd_std_dev_lapse_lat_rate is nonzero BUT lat==NULL"); }
00502   }
00503 
00504   DegreeDayFactors  ddf = base_ddf;
00505 
00506   ierr = atmosphere->begin_pointwise_access(); CHKERRQ(ierr);
00507   ierr = acab.begin_access(); CHKERRQ(ierr);
00508 
00509   ierr = accumulation_rate.begin_access(); CHKERRQ(ierr);
00510   ierr = melt_rate.begin_access(); CHKERRQ(ierr);
00511   ierr = runoff_rate.begin_access(); CHKERRQ(ierr);
00512   
00513   for (PetscInt i = grid.xs; i<grid.xs+grid.xm; ++i) {
00514     for (PetscInt j = grid.ys; j<grid.ys+grid.ym; ++j) {
00515 
00516       // the temperature time series from the PISMAtmosphereModel and its modifiers
00517       ierr = atmosphere->temp_time_series(i, j, Nseries, &ts[0], &T[0]); CHKERRQ(ierr);
00518 
00519       if (faustogreve != NULL) {
00520         // we have been asked to set mass balance parameters according to
00521         //   formula (6) in [\ref Faustoetal2009]; they overwrite ddf set above
00522         ierr = faustogreve->setDegreeDayFactors(i,j,(*usurf)(i,j),(*lat)(i,j),(*lon)(i,j),ddf);
00523                    CHKERRQ(ierr);
00524       }
00525 
00526       // use the temperature time series, the "positive" threshhold, and the 
00527       //   standard deviation of the daily variability to get the number of
00528       //   positive degree days (PDDs)
00529       PetscScalar sigma = base_pddStdDev;
00530       if (sigmalapserate != 0.0) {
00531         sigma += sigmalapserate * ((*lat)(i,j) - sigmabaselat);
00532       }
00533       PetscScalar pddsum = mbscheme->getPDDSumFromTemperatureTimeSeries(
00534                                   sigma, base_pddThresholdTemp,
00535                                   tseries, dtseries, &T[0], Nseries);
00536 
00537       // use the temperature time series to remove the rainfall from the precipitation
00538       PetscScalar snow_amount = mbscheme->getSnowFromPrecipAndTemperatureTimeSeries(
00539                                   acab(i,j), // precipitation rate (input)
00540                                   tseries, dtseries, &T[0], Nseries);
00541 
00542       // use degree-day factors, and number of PDDs, and the snow precipitation, to
00543       //   get surface mass balance (and diagnostics: accumulation, melt, runoff)
00544       ierr = mbscheme->getMassFluxesFromPDDs(ddf,
00545                                              dt_years * secpera, pddsum, snow_amount,
00546                                              accumulation_rate(i,j), // output
00547                                              melt_rate(i,j), // output
00548                                              runoff_rate(i,j), // output
00549                                              acab(i,j)); // acab = smb (output)
00550                                              CHKERRQ(ierr); 
00551     }
00552   }
00553 
00554   ierr = accumulation_rate.end_access(); CHKERRQ(ierr);
00555   ierr = melt_rate.end_access(); CHKERRQ(ierr);
00556   ierr = runoff_rate.end_access(); CHKERRQ(ierr);
00557 
00558   ierr = acab.end_access(); CHKERRQ(ierr);
00559   ierr = atmosphere->end_pointwise_access(); CHKERRQ(ierr);
00560 
00561   if (lat != NULL) {
00562     ierr = lat->end_access(); CHKERRQ(ierr);
00563   }
00564 
00565   if (faustogreve != NULL) {
00566     ierr = lon->end_access(); CHKERRQ(ierr)
00567     ierr = usurf->end_access(); CHKERRQ(ierr)
00568   }
00569 
00570   return 0;
00571 }
00572 
00573 
00574 PetscErrorCode PSTemperatureIndex::ice_surface_mass_flux(IceModelVec2S &result) {
00575   PetscErrorCode ierr;
00576 
00577   ierr = acab.copy_to(result); CHKERRQ(ierr);
00578 
00579   return 0;
00580 }
00581 
00582 
00583 PetscErrorCode PSTemperatureIndex::ice_surface_temperature(IceModelVec2S &result) {
00584   PetscErrorCode ierr;
00585   ierr = atmosphere->mean_annual_temp(result); CHKERRQ(ierr);
00586 
00587   string history = result.string_attr("history");
00588   history = "re-interpreted mean annual near-surface air temperature as instantaneous ice temperature at the ice surface\n" + history;
00589   ierr = result.set_attr("history", history); CHKERRQ(ierr);
00590 
00591   return 0;
00592 }
00593 
00594 void PSTemperatureIndex::add_vars_to_output(string keyword, set<string> &result) {
00595   if (keyword == "big") {
00596     result.insert("saccum");
00597     result.insert("smelt");
00598     result.insert("srunoff");
00599   }
00600 
00601   atmosphere->add_vars_to_output(keyword, result);
00602 }
00603 
00604 PetscErrorCode PSTemperatureIndex::define_variables(set<string> vars, const NCTool &nc, nc_type nctype) {
00605   PetscErrorCode ierr;
00606 
00607   ierr = PISMSurfaceModel::define_variables(vars, nc, nctype); CHKERRQ(ierr);
00608 
00609   if (set_contains(vars, "acab")) {
00610     ierr = acab.define(nc, nctype); CHKERRQ(ierr); 
00611   }
00612 
00613   if (set_contains(vars, "saccum")) {
00614     ierr = accumulation_rate.define(nc, nctype); CHKERRQ(ierr); 
00615   }  
00616 
00617   if (set_contains(vars, "smelt")) {
00618     ierr = melt_rate.define(nc, nctype); CHKERRQ(ierr); 
00619   }  
00620 
00621   if (set_contains(vars, "srunoff")) {
00622     ierr = runoff_rate.define(nc, nctype); CHKERRQ(ierr); 
00623   }  
00624   
00625   return 0;
00626 }
00627 
00628 PetscErrorCode PSTemperatureIndex::write_variables(set<string> vars, string filename) {
00629   PetscErrorCode ierr;
00630 
00631   ierr = PISMSurfaceModel::write_variables(vars, filename); CHKERRQ(ierr);
00632 
00633   if (set_contains(vars, "acab")) {
00634     ierr = acab.write(filename.c_str()); CHKERRQ(ierr);
00635   }
00636 
00637   if (set_contains(vars, "saccum")) {
00638     ierr = accumulation_rate.write(filename.c_str()); CHKERRQ(ierr);
00639   }  
00640 
00641   if (set_contains(vars, "smelt")) {
00642     ierr = melt_rate.write(filename.c_str()); CHKERRQ(ierr);
00643   }  
00644 
00645   if (set_contains(vars, "srunoff")) {
00646     ierr = runoff_rate.write(filename.c_str()); CHKERRQ(ierr); 
00647   }  
00648 
00649   return 0;
00650 }
00651 
00652 
00653 
00655 
00656 void PSForceThickness::attach_atmosphere_model(PISMAtmosphereModel *input) {
00657   input_model->attach_atmosphere_model(input);
00658 }
00659 
00660 PetscErrorCode PSForceThickness::init(PISMVars &vars) {
00661   PetscErrorCode ierr;
00662   char fttfile[PETSC_MAX_PATH_LEN] = "";
00663   PetscTruth opt_set;
00664   PetscScalar fttalpha;
00665   PetscTruth  fttalphaSet;
00666 
00667   ierr = input_model->init(vars); CHKERRQ(ierr);
00668 
00669   ierr = PetscOptionsBegin(grid.com, "", "Surface model forcing", ""); CHKERRQ(ierr);
00670 
00671   ierr = PetscOptionsString("-force_to_thk",
00672                             "Specifies the target thickness file for the force-to-thickness mechanism",
00673                             "", "",
00674                             fttfile, PETSC_MAX_PATH_LEN, &opt_set); CHKERRQ(ierr);
00675 
00676   if (!opt_set) {
00677     ierr = PetscPrintf(grid.com,
00678       "ERROR: surface model forcing requires the -force_to_thk option.\n"); CHKERRQ(ierr);
00679     PISMEnd();
00680   }
00681     
00682   ierr = PetscOptionsReal("-force_to_thk_alpha",
00683                           "Specifies the force-to-thickness alpha value in per-year units",
00684                           "", alpha * secpera,
00685                           &fttalpha, &fttalphaSet); CHKERRQ(ierr);
00686 
00687   ierr = verbPrintf(2, grid.com,
00688                     "* Initializing force-to-thickness mass-balance modifier...\n"); CHKERRQ(ierr);
00689 
00690   ice_thickness = dynamic_cast<IceModelVec2S*>(vars.get("land_ice_thickness"));
00691   if (!ice_thickness) SETERRQ(1, "ERROR: land_ice_thickness is not available");
00692 
00693   ierr = target_thickness.create(grid, "thk", false); CHKERRQ(ierr); // name to read by
00694   ierr = target_thickness.set_attrs( // set attributes for the read stage; see below for reset
00695      "diagnostic", 
00696      "target thickness for force-to-thickness mechanism (hit this at end of run)",
00697      "m", 
00698      "land_ice_thickness"); CHKERRQ(ierr); // standard_name *to read by*
00699   target_thickness.write_in_glaciological_units = true;
00700 
00701   ierr = ftt_mask.create(grid, "ftt_mask", false); CHKERRQ(ierr);
00702   ierr = ftt_mask.set_attrs(
00703      "diagnostic",
00704      "mask specifying where to apply the force-to-thickness mechanism",
00705      "", ""); CHKERRQ(ierr); // no units and no standard name
00706   ierr = ftt_mask.set(1.0); CHKERRQ(ierr); // default: applied in whole domain
00707   ftt_mask.write_in_glaciological_units = true;
00708 
00709   ierr = ftt_modified_acab.create(grid, "ftt_modified_acab", false); CHKERRQ(ierr);
00710   ierr = ftt_modified_acab.set_attrs(
00711      "diagnostic",
00712      "modified ice-equivalent surface mass balance rate;"
00713        " result from force-to-thickness mechanism (which is a PSModifier)",
00714      "m s-1", 
00715      ""); CHKERRQ(ierr); // no standard name
00716   ierr = ftt_modified_acab.set_glaciological_units("m year-1"); CHKERRQ(ierr);
00717   ftt_modified_acab.write_in_glaciological_units = true;
00718   ierr = ftt_modified_acab.set_attr("comment", "positive values correspond to ice gain"); CHKERRQ(ierr); 
00719   ierr = ftt_modified_acab.set(0.0); CHKERRQ(ierr); // no useful default
00720 
00721   input_file = fttfile;
00722 
00723   // determine exponential rate alpha from user option or from factor; option
00724   // is given in a^{-1}
00725   if (fttalphaSet == PETSC_TRUE) {
00726     ierr = verbPrintf(3, grid.com, "    option -force_to_thk_alpha seen\n");
00727        CHKERRQ(ierr);
00728     alpha = fttalpha / secpera;
00729   }
00730     
00731   ierr = verbPrintf(2, grid.com,
00732                     "    alpha = %.6f a-1 for %.3f a run, for -force_to_thk mechanism\n",
00733                     alpha * secpera, grid.end_year - grid.start_year); CHKERRQ(ierr);
00734 
00735   ierr = PetscOptionsEnd(); CHKERRQ(ierr);
00736 
00737   // fttfile now contains name of -force_to_thk file; now check
00738   // it is really there; and regrid the target thickness
00739   PISMIO nc(&grid);
00740   bool mask_exists = false;
00741   ierr = nc.open_for_reading(fttfile); CHKERRQ(ierr);
00742   ierr = nc.find_variable("ftt_mask", NULL, mask_exists); CHKERRQ(ierr);
00743   ierr = nc.close(); CHKERRQ(ierr);
00744 
00745   ierr = verbPrintf(2, grid.com, 
00746                     "    reading target thickness 'thk' from %s ...\n"
00747                     "    (this field will appear in output file as 'ftt_target_thk')\n",
00748                     fttfile); CHKERRQ(ierr); 
00749   ierr = target_thickness.regrid(fttfile, true); CHKERRQ(ierr);
00750 
00751   if (mask_exists) {
00752     ierr = verbPrintf(2, grid.com, 
00753                       "    reading force-to-thickness mask 'ftt_mask' from %s ...\n", fttfile); CHKERRQ(ierr); 
00754     ierr = ftt_mask.regrid(fttfile, true); CHKERRQ(ierr);
00755   }
00756 
00757   // reset name to avoid confusion; set attributes again to overwrite "read by" choices above
00758   ierr = target_thickness.set_name("ftt_target_thk"); CHKERRQ(ierr);
00759   ierr = target_thickness.set_attrs(
00760     "diagnostic",
00761     "target thickness for force-to-thickness mechanism (wants to hit this at end of run)",
00762     "m",
00763     "");  // no CF standard_name, to put it mildly
00764     CHKERRQ(ierr);
00765   target_thickness.write_in_glaciological_units = true;
00766 
00767   return 0;
00768 }
00769 
00838 PetscErrorCode PSForceThickness::ice_surface_mass_flux(IceModelVec2S &result) {
00839   PetscErrorCode ierr;
00840 
00841   // get the surface mass balance result from the next level up
00842   ierr = input_model->ice_surface_mass_flux(result); CHKERRQ(ierr);
00843 
00844   ierr = verbPrintf(5, grid.com,
00845      "    updating surface mass balance using -force_to_thk mechanism ...");
00846      CHKERRQ(ierr);
00847     
00848   // force-to-thickness mechanism is only full-strength at end of run
00849   const PetscScalar lambda = (t - grid.start_year) / (grid.end_year - grid.start_year);
00850   ierr = verbPrintf(5, grid.com,
00851                     " (t_years = %.3f a, start_year = %.3f a, end_year = %.3f a, alpha = %.5f, lambda = %.3f)\n",
00852                     t, grid.start_year , grid.end_year, alpha, lambda); CHKERRQ(ierr);
00853   if ((lambda < 0.0) || (lambda > 1.0)) {
00854     SETERRQ(4,"computed lambda (for -force_to_thk) out of range; in updateSurfMassFluxAndProvide()");
00855   }
00856 
00857   PetscScalar **H;
00858   ierr = ice_thickness->get_array(H);   CHKERRQ(ierr);
00859   ierr = target_thickness.begin_access(); CHKERRQ(ierr);
00860   ierr = ftt_mask.begin_access(); CHKERRQ(ierr); 
00861   ierr = ftt_modified_acab.begin_access(); CHKERRQ(ierr); 
00862   ierr = result.begin_access(); CHKERRQ(ierr);
00863   for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00864     for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00865       if (ftt_mask(i,j) > 0.5) {
00866         result(i,j) += lambda * alpha * (target_thickness(i,j) - H[i][j]);
00867       }
00868       ftt_modified_acab(i,j) = result(i,j);
00869     }
00870   }
00871   ierr = ice_thickness->end_access(); CHKERRQ(ierr);
00872   ierr = target_thickness.end_access(); CHKERRQ(ierr);
00873   ierr = ftt_mask.end_access(); CHKERRQ(ierr); 
00874   ierr = ftt_modified_acab.end_access(); CHKERRQ(ierr); 
00875   ierr = result.end_access(); CHKERRQ(ierr);
00876   // no communication needed
00877 
00878   return 0;
00879 }
00880 
00882 PetscErrorCode PSForceThickness::ice_surface_temperature(IceModelVec2S &result) {
00883   PetscErrorCode ierr;
00884 
00885   ierr = input_model->ice_surface_temperature(result); CHKERRQ(ierr);
00886 
00887   return 0;
00888 }
00889 
00901 PetscErrorCode PSForceThickness::max_timestep(PetscReal t_years, PetscReal &dt_years) {
00902   PetscErrorCode ierr;
00903   PetscReal max_dt = 2.0 / (alpha * secpera);
00904   
00905   ierr = input_model->max_timestep(t_years, dt_years); CHKERRQ(ierr);
00906 
00907   if (dt_years > 0) {
00908     if (max_dt > 0)
00909       dt_years = PetscMin(max_dt, dt_years);
00910   }
00911   else dt_years = max_dt;
00912 
00913   return 0;
00914 }
00915 
00917 void PSForceThickness::add_vars_to_output(string key, set<string> &result) {
00918   if (input_model != NULL)
00919     input_model->add_vars_to_output(key, result);
00920 
00921   result.insert("ftt_modified_acab");
00922   result.insert("ftt_mask");
00923   result.insert("ftt_target_thk");
00924 }
00925 
00926 PetscErrorCode PSForceThickness::define_variables(set<string> vars, const NCTool &nc, nc_type nctype) {
00927   PetscErrorCode ierr;
00928 
00929   ierr = input_model->define_variables(vars, nc, nctype); CHKERRQ(ierr);
00930 
00931   if (set_contains(vars, "ftt_modified_acab")) {
00932     ierr = ftt_modified_acab.define(nc, nctype); CHKERRQ(ierr); 
00933   }  
00934 
00935   if (set_contains(vars, "ftt_mask")) {
00936     ierr = ftt_mask.define(nc, nctype); CHKERRQ(ierr);
00937   }  
00938 
00939   if (set_contains(vars, "ftt_target_thk")) {
00940     ierr = target_thickness.define(nc, nctype); CHKERRQ(ierr);
00941   }  
00942 
00943   return 0;
00944 }
00945 
00946 PetscErrorCode PSForceThickness::write_variables(set<string> vars, string filename) {
00947   PetscErrorCode ierr;
00948 
00949   ierr = input_model->write_variables(vars, filename); CHKERRQ(ierr);
00950 
00951   if (set_contains(vars, "ftt_modified_acab")) {
00952     ierr = ftt_modified_acab.write(filename.c_str()); CHKERRQ(ierr); 
00953   }  
00954 
00955   if (set_contains(vars, "ftt_mask")) {
00956     ierr = ftt_mask.write(filename.c_str()); CHKERRQ(ierr); 
00957   }  
00958 
00959   if (set_contains(vars, "ftt_target_thk")) {
00960     ierr = target_thickness.write(filename.c_str()); CHKERRQ(ierr);
00961   }  
00962 
00963   return 0;
00964 }
00965 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines