PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/eismint/icePSTexModel.cc

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