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