PISM, A Parallel Ice Sheet Model stable 0.4.1779

src/base/iMutil.cc

Go to the documentation of this file.
00001 // Copyright (C) 2004-2011 Jed Brown, 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 <sstream>
00020 #include <cstring>
00021 #include "iceModel.hh"
00022 #include "pism_signal.h"
00023 #include <petscvec.h>
00024 
00026 PetscErrorCode IceModel::additionalAtStartTimestep() {
00027   return 0;
00028 }
00029 
00030 
00032 PetscErrorCode IceModel::additionalAtEndTimestep() {
00033   return 0;
00034 }
00035 
00037 
00050 int IceModel::endOfTimeStepHook() {
00051   PetscErrorCode ierr;
00052   
00053   if (pism_signal == SIGTERM) {
00054     verbPrintf(1, grid.com, 
00055        "\ncaught signal SIGTERM:  EXITING EARLY and saving with original filename.\n");
00056     char str[TEMPORARY_STRING_LENGTH];
00057     snprintf(str, sizeof(str), 
00058        "EARLY EXIT caused by signal SIGTERM.  Completed timestep at year=%.3f.",
00059        grid.year);
00060     stampHistory(str);
00061     return 1;
00062   }
00063   
00064   if (pism_signal == SIGUSR1) {
00065     char file_name[PETSC_MAX_PATH_LEN];
00066     snprintf(file_name, PETSC_MAX_PATH_LEN, "%s-%5.3f.nc",
00067              executable_short_name.c_str(), grid.year);
00068     verbPrintf(1, grid.com, 
00069        "\ncaught signal SIGUSR1:  Writing intermediate file `%s' and flushing time series.\n\n",
00070        file_name);
00071     pism_signal = 0;
00072     dumpToFile(file_name);
00073 
00074     // flush all the time-series buffers:
00075     ierr = flush_timeseries(); CHKERRQ(ierr); 
00076   }
00077 
00078   if (pism_signal == SIGUSR2) {
00079     verbPrintf(1, grid.com, 
00080        "\ncaught signal SIGUSR2:  Flushing time series.\n\n");
00081     pism_signal = 0;
00082 
00083     // flush all the time-series buffers:
00084     ierr = flush_timeseries(); CHKERRQ(ierr);
00085   }
00086 
00087   return 0;
00088 }
00089 
00090 
00092 PetscErrorCode  IceModel::stampHistoryCommand() {
00093   PetscErrorCode ierr;
00094   
00095   char startstr[TEMPORARY_STRING_LENGTH];
00096 
00097   snprintf(startstr, sizeof(startstr), 
00098            "PISM (%s) started on %d procs.", PISM_Revision, (int)grid.size);
00099   ierr = stampHistory(string(startstr)); CHKERRQ(ierr);
00100 
00101   // Create a string with space-separated command-line arguments:
00102   string cmdstr = pism_args_string();
00103 
00104   global_attributes.prepend_history(cmdstr);
00105 
00106   return 0;
00107 }
00108 
00109 
00112 PetscErrorCode  IceModel::stampHistoryEnd() {
00113   PetscErrorCode ierr;
00114 
00115   // timing stats
00116   PetscLogDouble current_time;
00117   PetscReal wall_clock_hours, proc_hours, mypph;
00118   ierr = PetscGetTime(&current_time); CHKERRQ(ierr);
00119   wall_clock_hours = (current_time - start_time) / 3600.0;
00120   proc_hours = grid.size * wall_clock_hours;
00121   mypph = (grid.year - grid.start_year) / proc_hours;
00122 
00123   // get PETSc's reported number of floating point ops (*not* per time) on this
00124   //   process, then sum over all processes
00125   PetscLogDouble flops, my_flops;
00126   MPI_Datatype mpi_type;
00127   ierr = PetscGetFlops(&my_flops); CHKERRQ(ierr);
00128   ierr = PetscDataTypeToMPIDataType(PETSC_DOUBLE, &mpi_type); CHKERRQ(ierr);
00129   MPI_Reduce(&my_flops, &flops, 1, mpi_type, MPI_SUM, 0, grid.com);
00130 
00131   // build and put string into global attribute "history"
00132   char str[TEMPORARY_STRING_LENGTH];
00133   snprintf(str, sizeof(str), 
00134     "PISM done.  Performance stats: %.4f wall clock hours, %.4f proc.-hours, %.4f model years per proc.-hour, PETSc MFlops = %.2f.",
00135     wall_clock_hours, proc_hours, mypph, flops * 1.0e-6);
00136   ierr = stampHistory(str); CHKERRQ(ierr);
00137   
00138   return 0;
00139 }
00140 
00141 
00143 PetscErrorCode  IceModel::stampHistory(string str) {
00144 
00145   global_attributes.prepend_history(pism_username_prefix() + (str + "\n"));
00146   
00147   return 0;
00148 }
00149 
00151 
00154 PetscErrorCode IceModel::check_maximum_thickness() {
00155   PetscErrorCode  ierr;
00156   PetscReal H_min, H_max, dz_top;
00157   vector<double> new_zlevels;
00158   const int old_Mz = grid.Mz;
00159   int N = 0;                    // the number of new levels
00160 
00161   ierr = vH.range(H_min, H_max); CHKERRQ(ierr);
00162   if (grid.Lz >= H_max) return 0;
00163 
00164   if (grid.initial_Mz == 0)
00165     grid.initial_Mz = grid.Mz;
00166   else if (grid.Mz > grid.initial_Mz * 2) {
00167     ierr = PetscPrintf(grid.com,
00168                        "\n"
00169                        "PISM ERROR: Max ice thickness (%7.4f m) is greater than the height of the computational box (%7.4f m)"
00170                        " AND the grid has twice the initial number of vertical levels (%d) already. Exiting...\n",
00171                        H_max, grid.Lz, grid.initial_Mz); CHKERRQ(ierr);
00172     PISMEnd();
00173   }
00174 
00175   // So, we need to extend the grid. We find dz at the top of the grid,
00176   // create new zlevels and zblevels, then extend all the IceModelVec3s.
00177 
00178   // Find the vertical grid spacing at the top of the grid:
00179   dz_top = grid.Lz - grid.zlevels[old_Mz - 2];
00180 
00181   // Find the number of new levels:
00182   while (grid.Lz + N * dz_top <= H_max) N++;
00183   // This makes sure that we always have *exactly* two levels strictly above the ice:
00184   if (grid.Lz + N * dz_top > H_max) N += 1;
00185   else N += 2;
00186 
00187   if (H_max - grid.Lz > 1000) {
00188     PetscPrintf(grid.com,
00189                 "\n"
00190                 "PISM ERROR: Max ice thickness (%7.4f m) is greater than the computational box height (%7.4f m)\n"
00191                 "     Extending PISM's vertical grid would require adding %d new levels totaling %7.4f m.\n"
00192                 "     Exiting...\n",
00193                 H_max, grid.Lz, N, N * dz_top);
00194     PISMEnd();
00195   }
00196 
00197   ierr = verbPrintf(2, grid.com,
00198                     "\n"
00199                     "PISM WARNING: max ice thickness (%7.4f m) is greater than the computational box height (%7.4f m)...\n"
00200                     "              Adding %d new grid levels %7.4f m apart...\n",
00201                     H_max, grid.Lz, N, dz_top); CHKERRQ(ierr);
00202 
00203   // Create new zlevels and zblevels:
00204   new_zlevels = grid.zlevels;
00205 
00206   // Fill the new levels:
00207   for (int j = 0; j < N; j++)
00208     new_zlevels.push_back(grid.Lz + dz_top * (j + 1));
00209 
00210   ierr = grid.set_vertical_levels(new_zlevels); CHKERRQ(ierr);
00211 
00212   // Done with the grid. Now we need to extend IceModelVec3s.
00213 
00214   // We use surface temperatures to extend T3. We get them from the
00215   // PISMSurfaceModel.
00216 
00217   if (surface != PETSC_NULL) {
00218     ierr = surface->ice_surface_temperature(artm); CHKERRQ(ierr);
00219     ierr = surface->ice_surface_liquid_water_fraction(liqfrac_surface); CHKERRQ(ierr);
00220   } else {
00221     SETERRQ(1,"PISM ERROR: surface == PETSC_NULL");
00222   }
00223 
00224   // for extending the variables Enth3 and vWork3d vertically, put into
00225   //   vWork2d[0] the enthalpy of the air
00226   PetscReal p_air = EC->getPressureFromDepth(0.0);
00227   ierr = liqfrac_surface.begin_access(); CHKERRQ(ierr);
00228   ierr = vWork2d[0].begin_access(); CHKERRQ(ierr);
00229   ierr = artm.begin_access(); CHKERRQ(ierr);
00230   for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00231     for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00232       ierr = EC->getEnthPermissive(artm(i,j), liqfrac_surface(i,j), p_air,
00233                                    vWork2d[0](i,j));
00234          CHKERRQ(ierr);
00235     }
00236   }
00237   ierr = vWork2d[0].end_access(); CHKERRQ(ierr);
00238   ierr = artm.end_access(); CHKERRQ(ierr);
00239   ierr = liqfrac_surface.end_access(); CHKERRQ(ierr);
00240 
00241   // Model state 3D vectors:
00242   ierr =  Enth3.extend_vertically(old_Mz, vWork2d[0]); CHKERRQ(ierr);
00243 
00244   // Work 3D vectors:
00245   ierr = vWork3d.extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00246 
00247   if (config.get_flag("do_cold_ice_methods")) {
00248     ierr =    T3.extend_vertically(old_Mz, artm); CHKERRQ(ierr);
00249   }
00250 
00251   // deal with 3D age conditionally
00252   if (config.get_flag("do_age")) {
00253     ierr = tau3.extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00254   }
00255 
00256   // Ask the stress balance module to extend its 3D fields:
00257   ierr = stress_balance->extend_the_grid(old_Mz); CHKERRQ(ierr); 
00258   
00259   ierr = check_maximum_thickness_hook(old_Mz); CHKERRQ(ierr);
00260 
00261   if (save_snapshots && (!split_snapshots) ) {
00262     char tmp[20];
00263     snprintf(tmp, 20, "%d", grid.Mz);
00264     
00265     snapshots_filename = pism_filename_add_suffix(snapshots_filename, "-Mz", tmp);
00266     snapshots_file_is_ready = false;
00267 
00268     ierr = verbPrintf(2, grid.com,
00269                       "NOTE: Further snapshots will be saved to '%s'...\n",
00270                       snapshots_filename.c_str()); CHKERRQ(ierr);
00271   }
00272 
00273   return 0;
00274 }
00275 
00276 
00278 
00279 PetscErrorCode IceModel::check_maximum_thickness_hook(const int /*old_Mz*/) {
00280   return 0;
00281 }
00282 
00283 bool IceModel::issounding(const PetscInt i, const PetscInt j){ 
00284   return ((i == id) && (j == jd));
00285 }
00286 
00287 void IceModel::attach_surface_model(PISMSurfaceModel *my_surface) {
00288   surface = my_surface;
00289 }
00290 
00291 void IceModel::attach_ocean_model(PISMOceanModel *my_ocean) {
00292   ocean = my_ocean;
00293 }
00294 
00296 static PetscReal triangle_area(PetscReal *A, PetscReal *B, PetscReal *C) {
00297   PetscReal V1[3], V2[3];
00298   for (int j = 0; j < 3; ++j) {
00299     V1[j] = B[j] - A[j];
00300     V2[j] = C[j] - A[j];
00301   }
00302 
00303   return 0.5*sqrt(PetscSqr(V1[1]*V2[2] - V2[1]*V1[2]) +
00304                   PetscSqr(V1[0]*V2[2] - V2[0]*V1[2]) +
00305                   PetscSqr(V1[0]*V2[1] - V2[0]*V1[1]));
00306 }
00307 
00308 static inline PetscReal sin_degrees(PetscReal deg) {
00309   return sin(deg * M_PI / 180.0);
00310 }
00311 
00312 static inline PetscReal cos_degrees(PetscReal deg) {
00313   return cos(deg * M_PI / 180.0);
00314 }
00315 
00318 static PetscReal geo_x(PetscReal a, PetscReal b,
00319                        PetscReal lon, PetscReal lat) {
00320   const PetscReal oe = acos(b/a),
00321     N = a/sqrt( 1 - PetscSqr( sin(oe)*sin_degrees(lat) ) );
00322 
00323   return N * cos_degrees(lat) * cos_degrees(lon);
00324 }
00325 
00328 static PetscReal geo_y(PetscReal a, PetscReal b,
00329                        PetscReal lon, PetscReal lat) {
00330   const PetscReal oe = acos(b/a),
00331     N = a/sqrt( 1 - PetscSqr( sin(oe)*sin_degrees(lat) ) );
00332 
00333   return N * cos_degrees(lat) * sin_degrees(lon);
00334 }
00335 
00338 static PetscReal geo_z(PetscReal a, PetscReal b,
00339                        PetscReal /*lon*/, PetscReal lat) {
00340   const PetscReal oe = acos(b/a),
00341     N = a/sqrt( 1 - PetscSqr( sin(oe)*sin_degrees(lat) ) );
00342 
00343   return N * sin_degrees(lat) * PetscSqr(b/a);
00344 }
00345 
00360 PetscErrorCode IceModel::compute_cell_areas() {
00361   PetscErrorCode ierr;
00362 
00363   // this value will be used near the grid boundary even when we compute
00364   // corrected areas inside the domain
00365   ierr = cell_area.set(grid.dx * grid.dy);
00366 
00367   if (!mapping.has("grid_mapping_name"))
00368     return 0;
00369 
00370   if (!config.get_flag("correct_cell_areas"))
00371     return 0;
00372 
00373   ierr = verbPrintf(2,grid.com,
00374                     "* Computing corrected cell areas using WGS84 datum...\n"); CHKERRQ(ierr);
00375 
00376   PetscReal a = config.get("WGS84_semimajor_axis"),
00377     b = config.get("WGS84_semiminor_axis");
00378 
00379 // Cell layout:
00380 // (nw)        (ne)
00381 // +-----------+
00382 // |           |
00383 // |           |
00384 // |     o     |
00385 // |           |
00386 // |           |
00387 // +-----------+
00388 // (sw)        (se)
00389 
00390   PetscScalar **lat, **lon;
00391   ierr =  cell_area.begin_access(); CHKERRQ(ierr);
00392   ierr =  vLatitude.get_array(lat); CHKERRQ(ierr);
00393   ierr = vLongitude.get_array(lon); CHKERRQ(ierr);
00394   for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00395     if ((i == 0) || (i == grid.Mx-1))
00396       continue;
00397 
00398     for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00399       if ((j == 0) || (j == grid.My-1))
00400         continue;
00401 
00402       PetscReal 
00403         // latitudes
00404         lat_nw = 0.5 * ( lat[i][j] + lat[i-1][j+1] ),
00405         lat_sw = 0.5 * ( lat[i][j] + lat[i-1][j-1] ),
00406         lat_se = 0.5 * ( lat[i][j] + lat[i+1][j-1] ),
00407         lat_ne = 0.5 * ( lat[i][j] + lat[i+1][j+1] ),
00408         // longitudes
00409         lon_nw = 0.5 * ( lon[i][j] + lon[i-1][j+1] ),
00410         lon_sw = 0.5 * ( lon[i][j] + lon[i-1][j-1] ),
00411         lon_se = 0.5 * ( lon[i][j] + lon[i+1][j-1] ),
00412         lon_ne = 0.5 * ( lon[i][j] + lon[i+1][j+1] );
00413 
00414       // geocentric coordinates:
00415       PetscReal sw[3] = {geo_x(a, b, lon_sw, lat_sw),
00416                          geo_y(a, b, lon_sw, lat_sw),
00417                          geo_z(a, b, lon_sw, lat_sw)};
00418 
00419       PetscReal se[3] = {geo_x(a, b, lon_se, lat_se),
00420                          geo_y(a, b, lon_se, lat_se),
00421                          geo_z(a, b, lon_se, lat_se)};
00422 
00423       PetscReal ne[3] = {geo_x(a, b, lon_ne, lat_ne),
00424                          geo_y(a, b, lon_ne, lat_ne),
00425                          geo_z(a, b, lon_ne, lat_ne)};
00426 
00427       PetscReal nw[3] = {geo_x(a, b, lon_nw, lat_nw),
00428                          geo_y(a, b, lon_nw, lat_nw),
00429                          geo_z(a, b, lon_nw, lat_nw)};
00430 
00431       cell_area(i,j) = triangle_area(sw, se, ne) + triangle_area(ne, nw, sw);
00432     }
00433   }
00434   ierr =  cell_area.end_access(); CHKERRQ(ierr);
00435   ierr =  vLatitude.end_access(); CHKERRQ(ierr);
00436   ierr = vLongitude.end_access(); CHKERRQ(ierr);
00437 
00438   return 0;
00439 }
00440 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines