|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
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
1.7.3