00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
00052 if (pism_signal == SIGTERM) {
00053 verbPrintf(1, grid.com,
00054 "\ncaught signal SIGTERM: EXITING EARLY and saving with original filename.\n");
00055 char str[TEMPORARY_STRING_LENGTH];
00056 snprintf(str, sizeof(str),
00057 "EARLY EXIT caused by signal SIGTERM. Completed timestep at year=%.3f.",
00058 grid.year);
00059 stampHistory(str);
00060 return 1;
00061 }
00062
00063 if (pism_signal == SIGUSR1) {
00064 char file_name[PETSC_MAX_PATH_LEN];
00065 snprintf(file_name, PETSC_MAX_PATH_LEN, "%s-%5.3f.nc",
00066 executable_short_name.c_str(), grid.year);
00067 verbPrintf(1, grid.com,
00068 "\ncaught signal SIGUSR1: Writing intermediate file `%s' and flushing time series.\n\n",
00069 file_name);
00070 pism_signal = 0;
00071 dumpToFile(file_name);
00072
00073
00074 vector<DiagnosticTimeseries*>::iterator i;
00075 for (i = timeseries.begin(); i < timeseries.end(); ++i) {
00076 (*i)->flush();
00077 }
00078 }
00079
00080 if (pism_signal == SIGUSR2) {
00081 verbPrintf(1, grid.com,
00082 "\ncaught signal SIGUSR2: Flushing time series.\n\n");
00083 pism_signal = 0;
00084
00085
00086 vector<DiagnosticTimeseries*>::iterator i;
00087 for (i = timeseries.begin(); i < timeseries.end(); ++i) {
00088 (*i)->flush();
00089 }
00090 }
00091
00092 return 0;
00093 }
00094
00095
00097 PetscErrorCode IceModel::stampHistoryCommand() {
00098 PetscErrorCode ierr;
00099 PetscInt argc;
00100 char **argv;
00101
00102 ierr = PetscGetArgs(&argc, &argv); CHKERRQ(ierr);
00103
00104 char startstr[TEMPORARY_STRING_LENGTH];
00105
00106 snprintf(startstr, sizeof(startstr),
00107 "PISM (%s) started on %d procs.", PISM_Revision, (int)grid.size);
00108 ierr = stampHistory(string(startstr)); CHKERRQ(ierr);
00109
00110
00111 string cmdstr;
00112 for (int j = 0; j < argc; j++)
00113 cmdstr += string(" ") + argv[j];
00114 cmdstr += "\n";
00115
00116 global_attributes.prepend_history(cmdstr);
00117
00118 return 0;
00119 }
00120
00121
00123 PetscErrorCode IceModel::stampHistoryEnd() {
00124 PetscErrorCode ierr;
00125 PetscLogDouble flops, my_flops;
00126 char str[TEMPORARY_STRING_LENGTH];
00127 MPI_Datatype mpi_type;
00128
00129 ierr = PetscGetFlops(&my_flops); CHKERRQ(ierr);
00130
00131 ierr = PetscDataTypeToMPIDataType(PETSC_DOUBLE, &mpi_type); CHKERRQ(ierr);
00132 MPI_Reduce(&my_flops, &flops, 1, mpi_type, MPI_SUM, 0, grid.com);
00133
00134 snprintf(str, sizeof(str), "PISM done. PETSc MFlops = %.2f.",
00135 flops * 1.0e-6);
00136
00137 ierr = stampHistory(str); CHKERRQ(ierr);
00138
00139 return 0;
00140 }
00141
00142
00144 PetscErrorCode IceModel::stampHistory(string str) {
00145
00146 global_attributes.prepend_history(pism_username_prefix() + (str + "\n"));
00147
00148 return 0;
00149 }
00150
00152
00155 PetscErrorCode IceModel::check_maximum_thickness() {
00156 PetscErrorCode ierr;
00157 PetscReal H_min, H_max, dz_top;
00158 double *new_zlevels, *new_zblevels;
00159 const int old_Mz = grid.Mz;
00160 int N = 0;
00161
00162 ierr = vH.range(H_min, H_max); CHKERRQ(ierr);
00163 if (grid.Lz >= H_max) return 0;
00164
00165 if (grid.initial_Mz == 0)
00166 grid.initial_Mz = grid.Mz;
00167 else if (grid.Mz > grid.initial_Mz * 2) {
00168 ierr = PetscPrintf(grid.com,
00169 "\n"
00170 "PISM ERROR: Max ice thickness (%7.4f m) is greater than the height of the computational box (%7.4f m)"
00171 " AND the grid has twice the initial number of vertical levels (%d) already. Exiting...\n",
00172 H_max, grid.Lz, grid.initial_Mz); CHKERRQ(ierr);
00173 PetscEnd();
00174 }
00175
00176
00177
00178
00179
00180 dz_top = grid.Lz - grid.zlevels[old_Mz - 2];
00181
00182
00183 while (grid.Lz + N * dz_top <= H_max) N++;
00184
00185 if (grid.Lz + N * dz_top > H_max) N += 1;
00186 else N += 2;
00187
00188 ierr = verbPrintf(2, grid.com,
00189 "\n"
00190 "PISM WARNING: max ice thickness (%7.4f m) is greater than the height of the computational box (%7.4f m)...\n"
00191 " Adding %d new grid levels %7.4f m apart...\n",
00192 H_max, grid.Lz, N, dz_top); CHKERRQ(ierr);
00193
00194
00195 new_zblevels = new double[grid.Mbz];
00196 new_zlevels = new double[old_Mz + N];
00197
00198 for (int j = 0; j < grid.Mbz; j++)
00199 new_zblevels[j] = grid.zblevels[j];
00200 for (int j = 0; j < old_Mz; j++)
00201 new_zlevels[j] = grid.zlevels[j];
00202
00203
00204 for (int j = 0; j < N; j++)
00205 new_zlevels[old_Mz + j] = grid.Lz + dz_top * (j + 1);
00206
00207 ierr = grid.set_vertical_levels(old_Mz + N, grid.Mbz,
00208 new_zlevels, new_zblevels); CHKERRQ(ierr);
00209 delete[] new_zlevels;
00210 delete[] new_zblevels;
00211
00212
00213
00214
00215
00216
00217 if (surface != PETSC_NULL) {
00218 ierr = surface->ice_surface_temperature(grid.year, 0.0, artm); CHKERRQ(ierr);
00219 } else {
00220 SETERRQ(1,"PISM ERROR: surface == PETSC_NULL");
00221 }
00222
00223
00224
00225 ierr = vWork2d[0].begin_access(); CHKERRQ(ierr);
00226 ierr = artm.begin_access(); CHKERRQ(ierr);
00227 for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00228 for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00229 ierr = EC->getEnthPermissive(
00230 artm(i,j),0.0,EC->getPressureFromDepth(0.0),vWork2d[0](i,j));
00231 CHKERRQ(ierr);
00232 }
00233 }
00234 ierr = vWork2d[0].end_access(); CHKERRQ(ierr);
00235 ierr = artm.end_access(); CHKERRQ(ierr);
00236
00237
00238 ierr = u3.extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00239 ierr = v3.extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00240 ierr = w3.extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00241 ierr = Sigma3.extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00242 ierr = Enth3.extend_vertically(old_Mz, vWork2d[0]); CHKERRQ(ierr);
00243
00244
00245 ierr = Enthnew3.extend_vertically(old_Mz, vWork2d[0]); CHKERRQ(ierr);
00246 ierr = Sigmastag3[0].extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00247 ierr = Sigmastag3[1].extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00248 ierr = Istag3[0].extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00249 ierr = Istag3[1].extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00250
00251 if (config.get_flag("do_cold_ice_methods")) {
00252 ierr = T3.extend_vertically(old_Mz, artm); CHKERRQ(ierr);
00253 ierr = Tnew3.extend_vertically(old_Mz, artm); CHKERRQ(ierr);
00254 }
00255
00256
00257 if (config.get_flag("do_age")) {
00258 ierr = tau3.extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00259 ierr = taunew3.extend_vertically(old_Mz, 0); CHKERRQ(ierr);
00260 }
00261
00262 ierr = check_maximum_thickness_hook(old_Mz); CHKERRQ(ierr);
00263
00264 if (save_snapshots && (!split_snapshots) ) {
00265 char tmp[20];
00266 snprintf(tmp, 20, "%d", grid.Mz);
00267
00268 snapshots_filename = pism_filename_add_suffix(snapshots_filename, "-Mz", tmp);
00269 snapshots_file_is_ready = false;
00270
00271 ierr = verbPrintf(2, grid.com,
00272 "NOTE: Further snapshots will be saved to '%s'...\n",
00273 snapshots_filename.c_str()); CHKERRQ(ierr);
00274 }
00275
00276 return 0;
00277 }
00278
00279
00281
00282 PetscErrorCode IceModel::check_maximum_thickness_hook(const int ) {
00283 return 0;
00284 }
00285
00286
00287 PetscErrorCode IceModel::report_grid_parameters() {
00288 PetscErrorCode ierr;
00289
00290 ierr = verbPrintf(2,grid.com, "computational domain and grid:\n"); CHKERRQ(ierr);
00291
00292 ierr = verbPrintf(2,grid.com,
00293 " spatial domain %.2f km x %.2f km",
00294 2*grid.Lx/1000.0,2*grid.Ly/1000.0); CHKERRQ(ierr);
00295 if (grid.Mbz > 1) {
00296 ierr = verbPrintf(2,grid.com," x (%.2f m + %.2f m bedrock)\n"
00297 ,grid.Lz,grid.Lbz); CHKERRQ(ierr);
00298 } else {
00299 ierr = verbPrintf(2,grid.com," x %.2f m\n",grid.Lz); CHKERRQ(ierr);
00300 }
00301
00302 ierr = verbPrintf(2, grid.com,
00303 " time interval [ %.2f a, %.2f a ]; run length = %.4f a\n",
00304 grid.start_year, grid.end_year, grid.end_year - grid.start_year);
00305
00306
00307 ierr = verbPrintf(2,grid.com,
00308 " horizontal grid cell %.2f km x %.2f km\n",
00309 grid.dx/1000.0,grid.dy/1000.0); CHKERRQ(ierr);
00310 if (grid.ice_vertical_spacing == EQUAL) {
00311 ierr = verbPrintf(2,grid.com,
00312 " vertical spacing in ice dz = %.3f m (equal spacing)\n",
00313 grid.dzMIN); CHKERRQ(ierr);
00314 } else {
00315 ierr = verbPrintf(2,grid.com,
00316 " vertical spacing in ice uneven, %d levels, %.3f m < dz < %.3f m\n",
00317 grid.Mz, grid.dzMIN, grid.dzMAX); CHKERRQ(ierr);
00318 }
00319
00320 if (grid.Mbz > 1) {
00321 if (grid.bed_vertical_spacing == EQUAL) {
00322 ierr = verbPrintf(2,grid.com,
00323 " vert spacing in bedrock dz = %.3f m (equal spacing)\n",
00324 grid.zblevels[1]-grid.zblevels[0]); CHKERRQ(ierr);
00325 } else {
00326 ierr = verbPrintf(2,grid.com,
00327 " vert spacing in bedrock uneven, %d levels, %.3f m < dz < %.3f m\n",
00328 grid.Mbz, grid.dzbMIN, grid.dzbMAX); CHKERRQ(ierr);
00329 }
00330 ierr = verbPrintf(3,grid.com,
00331 " fine spacing in conservation of energy and age:\n"
00332 " fMz = %d, fdz = %.3f m, fMbz = %d m\n",
00333 grid.Mz_fine, grid.dz_fine, grid.Mbz_fine); CHKERRQ(ierr);
00334 } else {
00335 ierr = verbPrintf(3,grid.com,
00336 " fine spacing used in energy/age fMz = %d, fdz = %.3f m\n",
00337 grid.Mz_fine, grid.dz_fine); CHKERRQ(ierr);
00338 }
00339 if (grid.Mz_fine > 1000) {
00340 ierr = verbPrintf(2,grid.com,
00341 "\n\nWARNING: Using more than 1000 ice vertical levels internally in energy/age computation!\n\n");
00342 CHKERRQ(ierr);
00343 }
00344
00345
00346 ierr = grid.printInfo(3); CHKERRQ(ierr);
00347
00348
00349 ierr = verbPrintf(5,grid.com,
00350 " REALLY verbose output on IceGrid:\n"); CHKERRQ(ierr);
00351 ierr = grid.printVertLevels(5); CHKERRQ(ierr);
00352
00353 return 0;
00354 }
00355
00356
00357 bool IceModel::issounding(const PetscInt i, const PetscInt j){
00358 return ((i == id) && (j == jd));
00359 }
00360
00361 void IceModel::attach_surface_model(PISMSurfaceModel *my_surface) {
00362 surface = my_surface;
00363 }
00364
00365 void IceModel::attach_ocean_model(PISMOceanModel *my_ocean) {
00366 ocean = my_ocean;
00367 }
00368
00370 static PetscReal triangle_area(PetscReal *A, PetscReal *B, PetscReal *C) {
00371 PetscReal V1[3], V2[3];
00372 for (int j = 0; j < 3; ++j) {
00373 V1[j] = B[j] - A[j];
00374 V2[j] = C[j] - A[j];
00375 }
00376
00377 return 0.5*sqrt(PetscSqr(V1[1]*V2[2] - V2[1]*V1[2]) +
00378 PetscSqr(V1[0]*V2[2] - V2[0]*V1[2]) +
00379 PetscSqr(V1[0]*V2[1] - V2[0]*V1[1]));
00380 }
00381
00382 static inline PetscReal sin_degrees(PetscReal deg) {
00383 return sin(deg * M_PI / 180.0);
00384 }
00385
00386 static inline PetscReal cos_degrees(PetscReal deg) {
00387 return cos(deg * M_PI / 180.0);
00388 }
00389
00392 static PetscReal geo_x(PetscReal a, PetscReal b,
00393 PetscReal lon, PetscReal lat) {
00394 const PetscReal oe = acos(b/a),
00395 N = a/sqrt( 1 - PetscSqr( sin(oe)*sin_degrees(lat) ) );
00396
00397 return N * cos_degrees(lat) * cos_degrees(lon);
00398 }
00399
00402 static PetscReal geo_y(PetscReal a, PetscReal b,
00403 PetscReal lon, PetscReal lat) {
00404 const PetscReal oe = acos(b/a),
00405 N = a/sqrt( 1 - PetscSqr( sin(oe)*sin_degrees(lat) ) );
00406
00407 return N * cos_degrees(lat) * sin_degrees(lon);
00408 }
00409
00412 static PetscReal geo_z(PetscReal a, PetscReal b,
00413 PetscReal lon, PetscReal lat) {
00414 const PetscReal oe = acos(b/a),
00415 N = a/sqrt( 1 - PetscSqr( sin(oe)*sin_degrees(lat) ) );
00416
00417 return N * sin_degrees(lat) * PetscSqr(b/a);
00418 }
00419
00434 PetscErrorCode IceModel::correct_cell_areas() {
00435 PetscErrorCode ierr;
00436
00437 if (!mapping.has("grid_mapping_name"))
00438 return 0;
00439
00440 if (!config.get_flag("correct_cell_areas"))
00441 return 0;
00442
00443 ierr = verbPrintf(2,grid.com,
00444 "* Computing corrected cell areas using WGS84 datum...\n"); CHKERRQ(ierr);
00445
00446
00447 ierr = cell_area.create(grid, "cell_area", false); CHKERRQ(ierr);
00448 ierr = cell_area.set_attrs("diagnostic", "corrected cell areas", "m2", ""); CHKERRQ(ierr);
00449 cell_area.time_independent = true;
00450 ierr = cell_area.set_glaciological_units("km2"); CHKERRQ(ierr);
00451 cell_area.write_in_glaciological_units = true;
00452 ierr = variables.add(cell_area); CHKERRQ(ierr);
00453
00454 PetscReal a = config.get("WGS84_semimajor_axis"),
00455 b = config.get("WGS84_semiminor_axis");
00456
00457
00458 ierr = cell_area.set(grid.dx * grid.dy);
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471 PetscScalar **lat, **lon;
00472 ierr = cell_area.begin_access(); CHKERRQ(ierr);
00473 ierr = vLatitude.get_array(lat); CHKERRQ(ierr);
00474 ierr = vLongitude.get_array(lon); CHKERRQ(ierr);
00475 for (PetscInt i=grid.xs; i<grid.xs+grid.xm; ++i) {
00476 if ((i == 0) || (i == grid.Mx-1))
00477 continue;
00478
00479 for (PetscInt j=grid.ys; j<grid.ys+grid.ym; ++j) {
00480 if ((j == 0) || (j == grid.My-1))
00481 continue;
00482
00483 PetscReal
00484
00485 lat_nw = 0.5 * ( lat[i][j] + lat[i-1][j+1] ),
00486 lat_sw = 0.5 * ( lat[i][j] + lat[i-1][j-1] ),
00487 lat_se = 0.5 * ( lat[i][j] + lat[i+1][j-1] ),
00488 lat_ne = 0.5 * ( lat[i][j] + lat[i+1][j+1] ),
00489
00490 lon_nw = 0.5 * ( lon[i][j] + lon[i-1][j+1] ),
00491 lon_sw = 0.5 * ( lon[i][j] + lon[i-1][j-1] ),
00492 lon_se = 0.5 * ( lon[i][j] + lon[i+1][j-1] ),
00493 lon_ne = 0.5 * ( lon[i][j] + lon[i+1][j+1] );
00494
00495
00496 PetscReal sw[3] = {geo_x(a, b, lon_sw, lat_sw),
00497 geo_y(a, b, lon_sw, lat_sw),
00498 geo_z(a, b, lon_sw, lat_sw)};
00499
00500 PetscReal se[3] = {geo_x(a, b, lon_se, lat_se),
00501 geo_y(a, b, lon_se, lat_se),
00502 geo_z(a, b, lon_se, lat_se)};
00503
00504 PetscReal ne[3] = {geo_x(a, b, lon_ne, lat_ne),
00505 geo_y(a, b, lon_ne, lat_ne),
00506 geo_z(a, b, lon_ne, lat_ne)};
00507
00508 PetscReal nw[3] = {geo_x(a, b, lon_nw, lat_nw),
00509 geo_y(a, b, lon_nw, lat_nw),
00510 geo_z(a, b, lon_nw, lat_nw)};
00511
00512 cell_area(i,j) = triangle_area(sw, se, ne) + triangle_area(ne, nw, sw);
00513 }
00514 }
00515 ierr = cell_area.end_access(); CHKERRQ(ierr);
00516 ierr = vLatitude.end_access(); CHKERRQ(ierr);
00517 ierr = vLongitude.end_access(); CHKERRQ(ierr);
00518
00519 return 0;
00520 }
00521