output_save.cc (5594B)
1 /* Copyright (C) 2017, 2018, 2019 PISM Authors 2 * 3 * This file is part of PISM. 4 * 5 * PISM is free software; you can redistribute it and/or modify it under the 6 * terms of the GNU General Public License as published by the Free Software 7 * Foundation; either version 3 of the License, or (at your option) any later 8 * version. 9 * 10 * PISM is distributed in the hope that it will be useful, but WITHOUT ANY 11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 * details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with PISM; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 #include "IceModel.hh" 21 22 #include "pism/util/pism_utilities.hh" 23 #include "pism/util/Profiling.hh" 24 25 namespace pism { 26 27 //! Computes the maximum time-step we can take and still hit all `-save_times`. 28 MaxTimestep IceModel::save_max_timestep(double my_t) { 29 30 if ((not m_save_snapshots) or 31 (not m_config->get_flag("time_stepping.hit_save_times"))) { 32 return MaxTimestep("reporting (-save_times)"); 33 } 34 35 return reporting_max_timestep(m_snapshot_times, my_t, "reporting (-save_times)"); 36 } 37 38 //! Initializes the snapshot-saving mechanism. 39 void IceModel::init_snapshots() { 40 m_current_snapshot = 0; 41 42 m_snapshots_filename = m_config->get_string("output.snapshot.file"); 43 bool filename_set = not m_snapshots_filename.empty(); 44 45 auto save_times = m_config->get_string("output.snapshot.times"); 46 bool times_set = not save_times.empty(); 47 48 bool split = m_config->get_flag("output.snapshot.split"); 49 50 m_snapshot_vars = output_variables(m_config->get_string("output.snapshot.size")); 51 52 if (filename_set ^ times_set) { 53 throw RuntimeError(PISM_ERROR_LOCATION, 54 "you need to set both output.snapshot.file and output.snapshot.times" 55 " to save snapshots."); 56 } 57 58 if (not filename_set and not times_set) { 59 m_save_snapshots = false; 60 return; 61 } 62 63 try { 64 // parse 65 std::vector<double> times = m_time->parse_times(save_times); 66 67 // discard times before the beginning and after the end of the run 68 m_snapshot_times.clear(); 69 for (const auto &t : times) { 70 if (t >= m_time->start() and t <= m_time->end()) { 71 m_snapshot_times.push_back(t); 72 } 73 } 74 } catch (RuntimeError &e) { 75 e.add_context("processing output.snapshot.times"); 76 throw; 77 } 78 79 if (m_snapshot_times.size() == 0) { 80 throw RuntimeError(PISM_ERROR_LOCATION, 81 "output.snapshot.times was set, but all requested times" 82 " are outside of the modeled time interval"); 83 } 84 85 m_save_snapshots = true; 86 m_snapshots_file_is_ready = false; 87 m_split_snapshots = false; 88 89 if (split) { 90 m_split_snapshots = true; 91 } else if (not ends_with(m_snapshots_filename, ".nc")) { 92 m_log->message(2, 93 "PISM WARNING: snapshots file name does not have the '.nc' suffix!\n"); 94 } 95 96 if (split) { 97 m_log->message(2, "saving snapshots to '%s+year.nc'; ", 98 m_snapshots_filename.c_str()); 99 } else { 100 m_log->message(2, "saving snapshots to '%s'; ", 101 m_snapshots_filename.c_str()); 102 } 103 104 m_log->message(2, "times requested: %s\n", save_times.c_str()); 105 } 106 107 //! Writes a snapshot of the model state (if necessary) 108 void IceModel::write_snapshot() { 109 double saving_after = -1.0e30; // initialize to avoid compiler warning; this 110 // value is never used, because saving_after 111 // is only used if save_now == true, and in 112 // this case saving_after is guaranteed to be 113 // initialized. See the code below. 114 char filename[PETSC_MAX_PATH_LEN]; 115 116 // determine if the user set the -save_times and -save_file options 117 if (not m_save_snapshots) { 118 return; 119 } 120 121 // do we need to save *now*? 122 if ((m_time->current() >= m_snapshot_times[m_current_snapshot]) and 123 (m_current_snapshot < m_snapshot_times.size())) { 124 saving_after = m_snapshot_times[m_current_snapshot]; 125 126 while ((m_current_snapshot < m_snapshot_times.size()) and 127 (m_snapshot_times[m_current_snapshot] <= m_time->current())) { 128 m_current_snapshot++; 129 } 130 } else { 131 // we don't need to save now, so just return 132 return; 133 } 134 135 // flush time-series buffers 136 flush_timeseries(); 137 138 if (m_split_snapshots) { 139 m_snapshots_file_is_ready = false; // each snapshot is written to a separate file 140 snprintf(filename, PETSC_MAX_PATH_LEN, "%s_%s.nc", 141 m_snapshots_filename.c_str(), m_time->date(saving_after).c_str()); 142 } else { 143 strncpy(filename, m_snapshots_filename.c_str(), PETSC_MAX_PATH_LEN); 144 } 145 146 m_log->message(2, 147 "saving snapshot to %s at %s, for time-step goal %s\n", 148 filename, m_time->date().c_str(), 149 m_time->date(saving_after).c_str()); 150 151 const Profiling &profiling = m_ctx->profiling(); 152 153 profiling.begin("io.snapshots"); 154 IO_Mode mode = m_snapshots_file_is_ready ? PISM_READWRITE : PISM_READWRITE_MOVE; 155 { 156 File file(m_grid->com, 157 filename, 158 string_to_backend(m_config->get_string("output.format")), 159 mode, 160 m_ctx->pio_iosys_id()); 161 162 if (not m_snapshots_file_is_ready) { 163 write_metadata(file, WRITE_MAPPING, PREPEND_HISTORY); 164 165 m_snapshots_file_is_ready = true; 166 } 167 168 write_run_stats(file); 169 170 save_variables(file, INCLUDE_MODEL_STATE, m_snapshot_vars, m_time->current()); 171 } 172 profiling.end("io.snapshots"); 173 } 174 175 } // end of namespace pism