|
PISM, A Parallel Ice Sheet Model stable 0.4.1779
|
00001 // Copyright (C) 2007-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 #include <cstring> 00020 #include <petsc.h> 00021 #include "icePSTexModel.hh" 00022 #include "Timeseries.hh" 00023 #include "SSA.hh" 00024 00025 const PetscScalar 00026 DEFAULT_PHI_STRONG = 15.0, // till friction angle outside of stream 00027 stream_offset = 100.0e3, // distance from grid center to start of stream 00028 stream_length = 650.0e3, // length used in computing slope 00029 stream_change = 400.0e3, // distance along stream at which change from 00030 // 'upstream' to 'downstream' till friction 00031 // angle occurs 00032 xi_slop = 0.15, // fractions by which reduced till friction 00033 eta_slop = 0.5; // angle extends outside of stream; see 00034 // setTillPhi() and inStreamNbhd() 00035 00036 const int Nexpers = 6, 00037 NAME_LENGTH = 10; 00038 00039 struct ExperDescription { 00040 char name[NAME_LENGTH]; 00041 PetscScalar bed_end_depth[4]; // drop for stream (see stream_length) 00042 PetscScalar stream_width[4]; // width in km 00043 PetscScalar upstream_phi[4]; // till friction angle in degrees 00044 PetscScalar downstream_phi[4]; 00045 }; 00046 00047 ExperDescription e[Nexpers] = { 00048 00049 { "P0A", 00050 {0.0, 0.0, 0.0, 0.0}, 00051 {70.0, 70.0, 70.0, 70.0}, // INACTIVE 00052 {5.0, 5.0, 5.0, 5.0}, // INACTIVE 00053 {5.0, 5.0, 5.0, 5.0} // INACTIVE 00054 }, 00055 00056 { "P0I", 00057 {0.0, 500.0, 1000.0, 2000.0}, 00058 {70.0, 70.0, 70.0, 70.0}, // INACTIVE 00059 {5.0, 5.0, 5.0, 5.0}, // INACTIVE 00060 {5.0, 5.0, 5.0, 5.0} // INACTIVE 00061 }, 00062 00063 { "P1", 00064 {0.0, 0.0, 0.0, 0.0}, 00065 {70.0, 30.0, 100.0, 50.0}, 00066 {5.0, 5.0, 5.0, 5.0}, 00067 {5.0, 5.0, 5.0, 5.0} 00068 }, 00069 00070 { "P2", // only three streams, variable grid orient 00071 {0.0, 0.0, 0.0, 0.0}, // last one INACTIVE 00072 {70.0, 70.0, 70.0, 70.0}, // last *three* INACTIVE; constant width 00073 {5.0, 5.0, 5.0, 5.0}, // last one INACTIVE 00074 {5.0, 5.0, 5.0, 5.0} // last one INACTIVE 00075 }, 00076 00077 { "P3", 00078 {0.0, 500.0, 1000.0, 2000.0}, 00079 {70.0, 70.0, 70.0, 70.0}, 00080 {5.0, 5.0, 5.0, 5.0}, 00081 {5.0, 5.0, 5.0, 5.0} 00082 }, 00083 00084 { "P4", 00085 {0.0, 0.0, 0.0, 0.0}, 00086 {70.0, 70.0, 70.0, 70.0}, 00087 {5.0, 5.0, 5.0, 5.0}, 00088 {2.0, 3.0, 8.0, 10.0} 00089 } 00090 00091 }; 00092 00093 PetscScalar stream_angle_P2[3] = {0.0, 100.0, 225.0}; // degrees 00094 00096 static bool inStreamNbhd(bool strictly_in_stream, 00097 const PetscScalar angle, const PetscScalar width, 00098 const PetscScalar x, const PetscScalar y, 00099 PetscScalar &x_loc, PetscScalar &y_loc) { 00100 const PetscScalar sinrot = sin(angle), 00101 cosrot = cos(angle); 00102 x_loc = cosrot * x + sinrot * y - stream_offset; 00103 y_loc = -sinrot * x + cosrot * y; 00104 if (strictly_in_stream) { 00105 //if ( (x_loc > 0.0) && (fabs(y_loc) < width / 2.0) ) 00106 if ( (x_loc > -1.0) && (fabs(y_loc) < width / 2.0) ) 00107 return true; 00108 else 00109 return false; 00110 } else { 00111 //if ( (x_loc > - xi_slop * stream_change) 00112 if ( (x_loc > - xi_slop * stream_change - 1.0) 00113 && (fabs(y_loc) < (1.0 + eta_slop) * (width / 2.0)) ) 00114 return true; 00115 else 00116 return false; 00117 } 00118 } 00119 00120 00122 static bool inStream(const PetscScalar angle, const PetscScalar width, 00123 const PetscScalar x, const PetscScalar y, 00124 PetscScalar &x_loc, PetscScalar &y_loc) { 00125 return inStreamNbhd(true, angle,width, x,y, x_loc,y_loc); 00126 } 00127 00128 IcePSTexModel::IcePSTexModel(IceGrid &g, NCConfigVariable &conf, NCConfigVariable &conf_overrides) 00129 : IceEISModel(g, conf, conf_overrides) { // do almost nothing; derived need constructors 00130 expername = 'A'; // PST expers are closest to EISMINT II exper A 00131 ivol = PETSC_NULL; // if we write series then this is not NULL 00132 } 00133 00134 00135 IcePSTexModel::~IcePSTexModel() { 00136 00137 if (ivol != PETSC_NULL) { 00138 delete dt_ser; 00139 delete ivol; 00140 delete iarea; 00141 delete maxcbar; 00142 00143 delete avup0; delete avup1; delete avup2; 00144 delete avdwn0; delete avdwn1; delete avdwn2; 00145 if (exper_chosen != 3) { 00146 delete avup3; 00147 delete avdwn3; 00148 } 00149 } 00150 } 00151 00152 00153 PetscErrorCode IcePSTexModel::prepare_series() { 00154 PetscErrorCode ierr; 00155 00156 // set up the file with name seriesname 00157 char outname[PETSC_MAX_PATH_LEN]; 00158 PetscTruth o_set; 00159 ierr = PetscOptionsGetString(PETSC_NULL, "-o", outname, PETSC_MAX_PATH_LEN, &o_set); CHKERRQ(ierr); 00160 if (!o_set) 00161 strncpy(outname, "unnamedpst.nc", PETSC_MAX_PATH_LEN); 00162 strncpy(seriesname,"ser_pst_", PETSC_MAX_PATH_LEN); 00163 strcat(seriesname,outname); 00164 00165 ierr = verbPrintf(2,grid.com, 00166 " will write time series with special PST information to %s ...\n", 00167 seriesname); CHKERRQ(ierr); 00168 NCTool nc(grid.com, grid.rank); 00169 ierr = nc.open_for_writing(seriesname); CHKERRQ(ierr); 00170 ierr = nc.close(); CHKERRQ(ierr); 00171 00172 // set-up each scalar time series 00173 dt_ser = new DiagnosticTimeseries(&grid, "dt", "t"); 00174 dt_ser->set_units("s", "years"); 00175 dt_ser->set_dimension_units("years", ""); 00176 dt_ser->output_filename = seriesname; 00177 dt_ser->set_attr("long_name", "PST result: mass continuity time-step"); 00178 dt_ser->set_attr("valid_min", 0.0); 00179 00180 ivol = new DiagnosticTimeseries(&grid, "ivol", "t"); 00181 ivol->set_units("m3", ""); 00182 ivol->set_dimension_units("years", ""); 00183 ivol->output_filename = seriesname; 00184 ivol->set_attr("long_name", "PST result: total ice volume"); 00185 00186 iarea = new DiagnosticTimeseries(&grid, "iarea", "t"); 00187 iarea->set_units("m2", ""); 00188 iarea->set_dimension_units("years", ""); 00189 iarea->output_filename = seriesname; 00190 iarea->set_attr("long_name", "PST result: total ice area"); 00191 00192 maxcbar = new DiagnosticTimeseries(&grid, "maxcbar", "t"); 00193 maxcbar->set_units("m s-1", "m a-1"); 00194 maxcbar->set_dimension_units("years", ""); 00195 maxcbar->output_filename = seriesname; 00196 maxcbar->set_attr("long_name", 00197 "PST result: maximum vertically-averaged ice speed anywhere on ice sheet"); 00198 00199 avup0 = new DiagnosticTimeseries(&grid, "avup0", "t"); 00200 avup0->set_units("m s-1", "m a-1"); 00201 avup0->set_dimension_units("years", ""); 00202 avup0->output_filename = seriesname; 00203 avup0->set_attr("long_name", 00204 "PST result: average speed in upper part of stream 0"); 00205 00206 avup1 = new DiagnosticTimeseries(&grid, "avup1", "t"); 00207 avup1->set_units("m s-1", "m a-1"); 00208 avup1->set_dimension_units("years", ""); 00209 avup1->output_filename = seriesname; 00210 avup1->set_attr("long_name", 00211 "PST result: average speed in upper part of stream 1"); 00212 00213 avup2 = new DiagnosticTimeseries(&grid, "avup2", "t"); 00214 avup2->set_units("m s-1", "m a-1"); 00215 avup2->set_dimension_units("years", ""); 00216 avup2->output_filename = seriesname; 00217 avup2->set_attr("long_name", 00218 "PST result: average speed in upper part of stream 2"); 00219 00220 avdwn0 = new DiagnosticTimeseries(&grid, "avdwn0", "t"); 00221 avdwn0->set_units("m s-1", "m a-1"); 00222 avdwn0->set_dimension_units("years", ""); 00223 avdwn0->output_filename = seriesname; 00224 avdwn0->set_attr("long_name", 00225 "PST result: average speed in downstream part of stream 0"); 00226 00227 avdwn1 = new DiagnosticTimeseries(&grid, "avdwn1", "t"); 00228 avdwn1->set_units("m s-1", "m a-1"); 00229 avdwn1->set_dimension_units("years", ""); 00230 avdwn1->output_filename = seriesname; 00231 avdwn1->set_attr("long_name", 00232 "PST result: average speed in downstream part of stream 1"); 00233 00234 avdwn2 = new DiagnosticTimeseries(&grid, "avdwn2", "t"); 00235 avdwn2->set_units("m s-1", "m a-1"); 00236 avdwn2->set_dimension_units("years", ""); 00237 avdwn2->output_filename = seriesname; 00238 avdwn2->set_attr("long_name", 00239 "PST result: average speed in downstream part of stream 2"); 00240 00241 if (exper_chosen != 3) { 00242 avup3 = new DiagnosticTimeseries(&grid, "avup3", "t"); 00243 avup3->set_units("m s-1", "m a-1"); 00244 avup3->set_dimension_units("years", ""); 00245 avup3->output_filename = seriesname; 00246 avup3->set_attr("long_name", 00247 "PST result: average speed in upper part of stream 3"); 00248 00249 avdwn3 = new DiagnosticTimeseries(&grid, "avdwn3", "t"); 00250 avdwn3->set_units("m s-1", "m a-1"); 00251 avdwn3->set_dimension_units("years", ""); 00252 avdwn3->output_filename = seriesname; 00253 avdwn3->set_attr("long_name", 00254 "PST result: average speed in downstream part of stream 3"); 00255 } 00256 00257 return 0; 00258 } 00259 00260 00261 PetscErrorCode IcePSTexModel::setFromOptions() { 00262 PetscErrorCode ierr; 00263 00264 ierr = IceEISModel::setFromOptions(); CHKERRQ(ierr); 00265 00266 exper_chosen = -1; 00267 for (int j=0; j<Nexpers; j++) { 00268 bool optionset; 00269 char optionname[20] = "-"; 00270 strcat(optionname,e[j].name); 00271 ierr = PISMOptionsIsSet(optionname, optionset); CHKERRQ(ierr); 00272 if (optionset == PETSC_TRUE) { 00273 if (exper_chosen >= 0) { 00274 ierr = PetscPrintf(grid.com, 00275 "IcePSTexModel ERROR: Only one experiment name option allowed.\n"); 00276 CHKERRQ(ierr); 00277 PISMEnd(); 00278 } else { 00279 exper_chosen = j; 00280 strcpy(exper_chosen_name,e[j].name); 00281 } 00282 } 00283 } 00284 if (exper_chosen < 0) { 00285 ierr = PetscPrintf(grid.com, 00286 "IcePSTexModel ERROR: Unrecognized experiment name.\n" 00287 " An experiment name option like '-P2' must be chosen.\n"); 00288 CHKERRQ(ierr); 00289 PISMEnd(); 00290 } 00291 00292 ierr = verbPrintf(2,grid.com, 00293 "setting up PST (Plastic till Stream w Thermocoupling) experiment %s ...\n", 00294 exper_chosen_name); CHKERRQ(ierr); 00295 00296 bool optionset; 00297 ierr = PISMOptionsIsSet("-no_ser", optionset); CHKERRQ(ierr); 00298 if (optionset == PETSC_FALSE) { 00299 ierr = prepare_series(); CHKERRQ(ierr); 00300 } 00301 00302 updateHmelt = PETSC_TRUE; 00303 config.set("default_till_phi", DEFAULT_PHI_STRONG); 00304 config.set_flag("include_bmr_in_continuity", true); 00305 config.set_flag("use_eta_transformation", true); 00306 00307 if (exper_chosen <= 1) { // P0A and P0I are nonsliding SIA 00308 config.set_flag("use_ssa_velocity", false); 00309 config.set_flag("use_ssa_when_grounded", false); 00310 } else { 00311 // these options equiv to "-ssa -super -plastic" 00312 config.set_flag("use_ssa_velocity", true); 00313 config.set_flag("use_ssa_when_grounded", true); 00314 } 00315 00316 return 0; 00317 } 00318 00319 PetscErrorCode IcePSTexModel::allocate_basal_yield_stress() { 00320 00321 if (basal_yield_stress != NULL) 00322 return 0; 00323 00324 basal_yield_stress = new PSTYieldStress(grid, config, exper_chosen, exper_chosen_name); 00325 00326 return 0; 00327 } 00328 00329 PetscErrorCode IcePSTexModel::allocate_stressbalance() { 00330 PetscErrorCode ierr; 00331 00332 ierr = IceModel::allocate_stressbalance(); CHKERRQ(ierr); 00333 00334 // typical strain rate is 100 m/yr per 100km in an ice shelf or fast ice stream 00335 const PetscScalar TYPICAL_STRAIN_RATE = (100.0 / secpera) / (100.0 * 1.0e3); 00336 const PetscScalar H_SSA_EXTENSION = 50.0; // m; thickness of ice shelf extension 00337 const PetscScalar constantHardnessForSSA = 1.9e8; // Pa s^{1/3}; see p. 49 of MacAyeal et al 1996 00338 const PetscScalar PSTconstantNuHForSSA = H_SSA_EXTENSION * constantHardnessForSSA 00339 / (2.0 * pow(TYPICAL_STRAIN_RATE,2./3.)); // Pa s m 00340 00341 // ssa == NULL means that the user chose non-sliding SIA 00342 SSA *ssa = dynamic_cast<SSA*>(stress_balance->get_stressbalance()); 00343 if (ssa != NULL) 00344 ssa->strength_extension->set_notional_strength(PSTconstantNuHForSSA); 00345 00346 return 0; 00347 } 00348 00349 PetscErrorCode IcePSTexModel::initFromFile(const char *fname) { 00350 PetscErrorCode ierr; 00351 00352 ierr = IceEISModel::initFromFile(fname); CHKERRQ(ierr); 00353 00354 ierr = verbPrintf(2,grid.com, 00355 "starting PST (Plastic till Stream w Thermocoupling) experiment %s from file %s ...\n", 00356 exper_chosen_name, fname); CHKERRQ(ierr); 00357 00358 ierr = verbPrintf(2,grid.com, 00359 " values of mask and phi = (till friction angle) in file will be ignored ...\n"); 00360 CHKERRQ(ierr); 00361 00362 ierr = verbPrintf(2,grid.com, 00363 " bed topography from file is kept ...\n"); CHKERRQ(ierr); 00364 00365 return 0; 00366 } 00367 00368 00369 PetscErrorCode IcePSTexModel::set_vars_from_options() { 00370 PetscErrorCode ierr; 00371 00372 ierr = IceEISModel::set_vars_from_options(); CHKERRQ(ierr); 00373 00374 ierr = verbPrintf(2,grid.com, 00375 "setting variables for PST experiment %s ...\n", exper_chosen_name); CHKERRQ(ierr); 00376 00377 ierr = setBedElev(); CHKERRQ(ierr); 00378 00379 ierr = verbPrintf(2,grid.com, 00380 " bed topography set for PST exper '%s' ...\n", exper_chosen_name); CHKERRQ(ierr); 00381 00382 return 0; 00383 } 00384 00385 00386 PetscErrorCode IcePSTexModel::setBedElev() { 00387 PetscErrorCode ierr; 00388 00389 const PetscScalar width = 200.0e3, // trough width = 200km; not the same 00390 // as stream width 00391 plateau = 2000.0; 00392 PetscScalar x_loc, y_loc; 00393 00394 ierr = vbed.set(plateau); CHKERRQ(ierr); 00395 00396 ierr = vbed.begin_access(); CHKERRQ(ierr); 00397 00398 for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) { 00399 for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) { 00400 const PetscScalar x = grid.x[i], y = grid.y[j]; 00401 // note we treat exper P2 like others; it is flat anyway (slope=0) 00402 for (PetscInt m=0; m<4; m++) { 00403 PetscScalar drop = e[exper_chosen].bed_end_depth[m], 00404 slope = drop / stream_length; 00405 if (inStream((pi/2.0)*m,width,x,y,x_loc,y_loc)) 00406 vbed(i,j) = plateau - slope * x_loc * cos(pi * y_loc / width); 00407 } 00408 } 00409 } 00410 00411 ierr = vbed.end_access(); CHKERRQ(ierr); 00412 00413 // communicate b because it will be horizontally differentiated 00414 ierr = vbed.beginGhostComm(); CHKERRQ(ierr); 00415 ierr = vbed.endGhostComm(); CHKERRQ(ierr); 00416 return 0; 00417 } 00418 00419 00420 PetscErrorCode IcePSTexModel::additionalAtEndTimestep() { 00421 PetscErrorCode ierr; 00422 00423 if (ivol == PETSC_NULL) return 0; 00424 00425 // all are in MKS units 00426 // variables starting with "g" are global across all processors 00427 00428 // not all of these are used ... 00429 PetscScalar gvolume, garea, gvolSIA, gvolstream, gvolshelf; 00430 ierr = volumeArea(gvolume, garea, gvolSIA, gvolstream, gvolshelf); CHKERRQ(ierr); 00431 00432 PetscScalar maxcbarALL = 0.0, 00433 areaup[4] = {0.0, 0.0, 0.0, 0.0}, 00434 avcup[4] = {0.0, 0.0, 0.0, 0.0}, 00435 areadown[4] = {0.0, 0.0, 0.0, 0.0}, 00436 avcdown[4] = {0.0, 0.0, 0.0, 0.0}; 00437 PetscScalar gmaxcbarALL, gareaup[4], gavcup[4], gareadown[4], gavcdown[4]; 00438 PetscScalar x_loc, y_loc; 00439 const PetscScalar darea = grid.dx * grid.dy; 00440 00441 IceModelVec *tmp; 00442 ierr = diagnostics["velbar"]->compute(tmp); CHKERRQ(ierr); 00443 IceModelVec2V *vel_bar = dynamic_cast<IceModelVec2V*>(tmp); 00444 if (!vel_bar) SETERRQ(1, "dynamic_cast failure"); 00445 00446 ierr = vH.begin_access(); CHKERRQ(ierr); 00447 ierr = vel_bar->begin_access(); CHKERRQ(ierr); 00448 for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) { 00449 for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) { 00450 if (vH(i,j) > 0) { 00451 const PetscScalar cbar = (*vel_bar)(i,j).magnitude(); 00452 const PetscScalar x = -grid.Ly + grid.dy * j, // note reversal (FIXME! 00453 // do we need this now?) 00454 y = -grid.Lx + grid.dx * i, 00455 r = sqrt(PetscSqr(x) + PetscSqr(y)); 00456 if (cbar > maxcbarALL) maxcbarALL = cbar; 00457 if (exper_chosen == 3) { // exper P2 00458 const PetscScalar width = e[exper_chosen].stream_width[0] * 1000.0; 00459 for (int m=0; m<3; m++) { 00460 if (inStream((pi/180.0) * stream_angle_P2[m],width,x,y,x_loc,y_loc)) { 00461 if (r > stream_change) { 00462 areadown[m] += darea; 00463 avcdown[m] += cbar * darea; 00464 } else { 00465 areaup[m] += darea; 00466 avcup[m] += cbar * darea; 00467 } 00468 } 00469 } 00470 } else { 00471 for (int m=0; m<4; m++) { 00472 const PetscScalar width = e[exper_chosen].stream_width[m] * 1000.0; 00473 if (inStream((pi/2.0)*m,width,x,y,x_loc,y_loc)) { 00474 if (x_loc > stream_change - 1.0) { 00475 areadown[m] += darea; 00476 avcdown[m] += cbar * darea; 00477 } else { 00478 areaup[m] += darea; 00479 avcup[m] += cbar * darea; 00480 } 00481 } 00482 } 00483 } 00484 } 00485 } 00486 } 00487 ierr = vH.end_access(); CHKERRQ(ierr); 00488 ierr = vel_bar->end_access(); CHKERRQ(ierr); 00489 00490 delete tmp; 00491 00492 // globalize and actually compute averages 00493 ierr = PetscGlobalMax(&maxcbarALL, &gmaxcbarALL, grid.com); CHKERRQ(ierr); 00494 for (PetscInt m=0; m<4; m++) { 00495 ierr = PetscGlobalSum(&areaup[m], &gareaup[m], grid.com); CHKERRQ(ierr); 00496 ierr = PetscGlobalSum(&avcup[m], &gavcup[m], grid.com); CHKERRQ(ierr); 00497 if (gareaup[m] > 0.0) { 00498 gavcup[m] = gavcup[m] / gareaup[m]; 00499 } else { 00500 gavcup[m] = 0.0; 00501 } 00502 ierr = PetscGlobalSum(&areadown[m], &gareadown[m], grid.com); CHKERRQ(ierr); 00503 ierr = PetscGlobalSum(&avcdown[m], &gavcdown[m], grid.com); CHKERRQ(ierr); 00504 if (gareadown[m] > 0.0) { 00505 gavcdown[m] = gavcdown[m] / gareadown[m]; 00506 } else { 00507 gavcdown[m] = 0.0; 00508 } 00509 } 00510 00511 dt_ser->append(grid.year, dt); 00512 dt_ser->interp(grid.year); 00513 00514 ivol->append(grid.year, gvolume); 00515 ivol->interp(grid.year); 00516 iarea->append(grid.year, garea); 00517 iarea->interp(grid.year); 00518 maxcbar->append(grid.year, gmaxcbarALL); 00519 maxcbar->interp(grid.year); 00520 00521 avup0->append(grid.year, gavcup[0]); 00522 avup0->interp(grid.year); 00523 avup1->append(grid.year, gavcup[1]); 00524 avup1->interp(grid.year); 00525 avup2->append(grid.year, gavcup[2]); 00526 avup2->interp(grid.year); 00527 00528 avdwn0->append(grid.year, gavcdown[0]); 00529 avdwn0->interp(grid.year); 00530 avdwn1->append(grid.year, gavcdown[1]); 00531 avdwn1->interp(grid.year); 00532 avdwn2->append(grid.year, gavcdown[2]); 00533 avdwn2->interp(grid.year); 00534 00535 if (exper_chosen != 3) { 00536 avup3->append(grid.year, gavcup[3]); 00537 avup3->interp(grid.year); 00538 avdwn3->append(grid.year, gavcdown[3]); 00539 avdwn3->interp(grid.year); 00540 } 00541 00542 return 0; 00543 } 00544 00546 PetscErrorCode PSTYieldStress::init(PISMVars &vars) { 00547 PetscErrorCode ierr; 00548 00549 ierr = PISMDefaultYieldStress::init(vars); CHKERRQ(ierr); 00550 00551 ierr = verbPrintf(2,grid.com, 00552 " setting phi = (till friction angle) for PST exper '%s' ...\n", experiment_name.c_str()); 00553 CHKERRQ(ierr); 00554 00555 ierr = init_till_phi(); CHKERRQ(ierr); 00556 00557 return 0; 00558 } 00559 00560 PetscErrorCode PSTYieldStress::init_till_phi() { 00561 PetscErrorCode ierr; 00562 00563 const PetscScalar dx = grid.dx, dy = grid.dy; 00564 PetscScalar x_loc, y_loc; 00565 00566 if (experiment <= 1) 00567 return 0; // nothing further for P0A and P0I 00568 00569 ierr = till_phi.begin_access(); CHKERRQ(ierr); 00570 00571 for (PetscInt i = grid.xs; i < grid.xs + grid.xm; ++i) { 00572 for (PetscInt j = grid.ys; j < grid.ys + grid.ym; ++j) { 00573 const PetscScalar x = -grid.Ly + dy * j, // note reversal 00574 y = -grid.Lx + dx * i; 00575 if (experiment == 3) { // experiment P2 00576 const PetscScalar width = e[experiment].stream_width[0] * 1000.0; 00577 for (PetscInt m = 0; m < 3; m++) { 00578 if (inStreamNbhd(false, (pi / 180.0) * stream_angle_P2[m], width, x, y, x_loc, y_loc)) 00579 till_phi(i, j) = phiLocal(width, x_loc, y_loc, DEFAULT_PHI_STRONG, 00580 e[experiment].upstream_phi[m], 00581 e[experiment].downstream_phi[m]); 00582 } 00583 } else { 00584 for (PetscInt m = 0; m < 4; m++) { // go through four sectors 00585 const PetscScalar width = e[experiment].stream_width[m] * 1000.0; 00586 if (inStreamNbhd(false, (pi / 2.0)*m, width, x, y, x_loc, y_loc)) { 00587 till_phi(i, j) = phiLocal(width, x_loc, y_loc, DEFAULT_PHI_STRONG, 00588 e[experiment].upstream_phi[m], 00589 e[experiment].downstream_phi[m]); 00590 } 00591 } 00592 } 00593 } 00594 } 00595 00596 ierr = till_phi.end_access(); CHKERRQ(ierr); 00597 00598 // communicate ghosts so that the tauc computation can be performed locally 00599 // (including ghosts of tauc, that is) 00600 ierr = till_phi.beginGhostComm(); CHKERRQ(ierr); 00601 ierr = till_phi.endGhostComm(); CHKERRQ(ierr); 00602 00603 return 0; 00604 } 00605 00606 int PSTYieldStress::sectorNumberP2(const PetscScalar x, const PetscScalar y) { 00607 if (x > 0.0) { 00608 if (y < x) 00609 return 0; 00610 else 00611 return 1; 00612 } else { 00613 if (y < 0.0) 00614 return 2; 00615 else 00616 return 1; 00617 } 00618 } 00619 00620 00622 PetscScalar PSTYieldStress::phiLocal(const PetscScalar width, 00623 const PetscScalar x, const PetscScalar y, 00624 const PetscScalar STRONG, 00625 const PetscScalar UP, const PetscScalar DOWN) { 00626 00627 const PetscScalar eta = y / (width/2.0), // normalized local y 00628 xi = x / stream_change; // normalized local x 00629 00630 // compute lambda(eta) which is even and in [0,1] 00631 PetscScalar lambda = 0.0; // for big eta 00632 if (PetscAbs(eta) <= 1.0 - eta_slop) 00633 lambda = 1.0; 00634 else if (PetscAbs(eta) < 1.0 + eta_slop) 00635 lambda = 0.5 - 0.5 * sin((pi/2.0) * (PetscAbs(eta) - 1.0) / eta_slop); 00636 00637 if (x > stream_change) 00638 return DOWN * lambda + STRONG * (1.0 - lambda); // downstream value 00639 else { // f(xi) is for upstream part only 00640 PetscScalar f = STRONG; 00641 if (xi >= xi_slop) 00642 f = UP; 00643 else if (xi > - xi_slop) { 00644 const PetscScalar fav = 0.5 * (STRONG + UP); 00645 f = fav - 0.5 * (STRONG - UP) * sin((pi/2.0) * (xi / xi_slop)); 00646 } 00647 return f * lambda + STRONG * (1.0 - lambda); // upstream value 00648 } 00649 }
1.7.3