PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
printout.cc
Go to the documentation of this file.
1 // Copyright (C) 2004-2019, 2021, 2023 Jed Brown, Ed Bueler and Constantine Khroulev
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 #include <cstring>
20 #include <cstdlib>
21 
22 #include <petscsys.h>
23 
24 #include "pism/icemodel/IceModel.hh"
25 
26 #include "pism/stressbalance/StressBalance.hh"
27 
28 #include "pism/util/Grid.hh"
29 #include "pism/util/ConfigInterface.hh"
30 #include "pism/util/Time.hh"
31 
32 #include "pism/util/pism_utilities.hh"
33 
34 namespace pism {
35 
36 
37 //! Because of the -skip mechanism it is still possible that we can have CFL violations: count them.
38 /*! This applies to the horizontal part of the 3D advection problem solved by AgeModel and the
39 horizontal part of the 3D convection-diffusion problems solved by EnthalpyModel and
40 TemperatureModel.
41 */
42 unsigned int count_CFL_violations(const array::Array3D &u3,
43  const array::Array3D &v3,
44  const array::Scalar &ice_thickness,
45  double dt) {
46 
47  if (dt == 0.0) {
48  return 0;
49  }
50 
51  std::shared_ptr<const Grid> grid = u3.grid();
52 
53  const double
54  CFL_x = grid->dx() / dt,
55  CFL_y = grid->dy() / dt;
56 
57  array::AccessScope list{&ice_thickness, &u3, &v3};
58 
59  unsigned int CFL_violation_count = 0;
60  ParallelSection loop(grid->com);
61  try {
62  for (auto p = grid->points(); p; p.next()) {
63  const int i = p.i(), j = p.j();
64 
65  const int ks = grid->kBelowHeight(ice_thickness(i,j));
66 
67  const double
68  *u = u3.get_column(i, j),
69  *v = v3.get_column(i, j);
70 
71  // check horizontal CFL conditions at each point
72  for (int k = 0; k <= ks; k++) {
73  if (fabs(u[k]) > CFL_x) {
74  CFL_violation_count += 1;
75  }
76  if (fabs(v[k]) > CFL_y) {
77  CFL_violation_count += 1;
78  }
79  }
80  }
81  } catch (...) {
82  loop.failed();
83  }
84  loop.check();
85 
86  return (unsigned int)GlobalMax(grid->com, CFL_violation_count);
87 }
88 
89 void IceModel::print_summary(bool tempAndAge) {
90 
91  const array::Array3D
92  &u3 = m_stress_balance->velocity_u(),
93  &v3 = m_stress_balance->velocity_v();
94 
95  unsigned int n_CFL_violations = count_CFL_violations(u3, v3, m_geometry.ice_thickness,
96  tempAndAge ? dt_TempAge : m_dt);
97 
98  // report CFL violations
99  if (n_CFL_violations > 0.0) {
100  const double CFLviolpercent = 100.0 * n_CFL_violations / (m_grid->Mx() * m_grid->My() * m_grid->Mz());
101  // at default verbosity level, only report CFL viols if above:
102  const double CFLVIOL_REPORT_VERB2_PERCENT = 0.1;
103  if (CFLviolpercent > CFLVIOL_REPORT_VERB2_PERCENT ||
104  m_log->get_threshold() > 2) {
105  auto tempstr = pism::printf(" [!CFL#=%d (=%5.2f%% of 3D grid)] ",
106  n_CFL_violations, CFLviolpercent);
107  m_stdout_flags = tempstr + m_stdout_flags;
108  }
109  }
110 
111  // get maximum diffusivity
112  double max_diffusivity = m_stress_balance->max_diffusivity();
113  // get volumes in m^3 and areas in m^2
114  double volume = ice_volume(m_geometry, 0.0);
115  double area = ice_area(m_geometry, 0.0);
116 
117  double meltfrac = 0.0;
118  if (tempAndAge or m_log->get_threshold() >= 3) {
119  meltfrac = compute_temperate_base_fraction(area);
120  }
121 
122  // main report: 'S' line
123  print_summary_line(false, tempAndAge, m_dt,
124  volume, area, meltfrac, max_diffusivity);
125 }
126 
127 
128 //! Print a line to stdout which summarizes the state of the modeled ice sheet at the end of the time step.
129 /*!
130 This method is for casual inspection of model behavior, and to provide the user
131 with some indication of the state of the run.
132 
133 Generally, two lines are printed to stdout, the first starting with a space
134 and the second starting with the character 'S' in the left-most column (column 1).
135 
136 The first line shows flags for which processes executed, and the length of the
137 time step (and/or substeps under option -skip). See IceModel::run()
138 for meaning of these flags.
139 
140 If printPrototype is TRUE then the first line does not appear and
141 the second line has alternate appearance. Specifically, different column 1
142 characters are printed:
143  - 'P' line gives names of the quantities reported in the 'S' line, the
144  "prototype", while
145  - 'U' line gives units of these quantities.
146 This column 1 convention allows automatic tools to read PISM stdout
147 and produce time-series. The 'P' and 'U' lines are intended to appear once at
148 the beginning of the run, while an 'S' line appears at every time step.
149 
150 These quantities are reported in this base class version:
151  - `time` is the current model time
152  - `ivol` is the total ice sheet volume
153  - `iarea` is the total area occupied by positive thickness ice
154  - `max_diffusivity` is the maximum diffusivity
155  - `max_sliding_vel` is max(max(abs(u)), max(abs(v)))
156 
157 Configuration parameters `output.runtime.time_unit_name`, `output.runtime.volume_scale_factor_log10`,
158 and `output.runtime.area_scale_factor_log10` control the appearance and units.
159 
160 For more description and examples, see the PISM User's Manual.
161 Derived classes of IceModel may redefine this method and print alternate
162 information.
163  */
164 void IceModel::print_summary_line(bool printPrototype, bool tempAndAge,
165  double delta_t,
166  double volume, double area,
167  double /* meltfrac */, double max_diffusivity) {
168  const bool do_energy = m_config->get_flag("energy.enabled");
169  const int log10scalevol = static_cast<int>(m_config->get_number("output.runtime.volume_scale_factor_log10")),
170  log10scalearea = static_cast<int>(m_config->get_number("output.runtime.area_scale_factor_log10"));
171  const std::string time_units = m_config->get_string("output.runtime.time_unit_name");
172  const bool use_calendar = m_config->get_flag("output.runtime.time_use_calendar");
173 
174  const double scalevol = pow(10.0, static_cast<double>(log10scalevol)),
175  scalearea = pow(10.0, static_cast<double>(log10scalearea));
176  std::string
177  volscalestr = " ",
178  areascalestr = " "; // blank when 10^0 = 1 scaling
179  if (log10scalevol != 0) {
180  volscalestr = pism::printf("10^%1d_", log10scalevol);
181  }
182  if (log10scalearea != 0) {
183  areascalestr = pism::printf("10^%1d_", log10scalearea);
184  }
185 
186  if (printPrototype) {
187  m_log->message(2,
188  "P time: ivol iarea max_diffusivity max_sliding_vel\n");
189  m_log->message(2,
190  "U %s %skm^3 %skm^2 m^2 s^-1 m/%s\n",
191  time_units.c_str(),
192  volscalestr.c_str(),
193  areascalestr.c_str(),
194  time_units.c_str());
195  return;
196  }
197 
198  // this version keeps track of what has been done so as to minimize stdout:
199  // FIXME: turn these static variables into class members.
200  static std::string stdout_flags_count0;
201  static int mass_cont_sub_counter = 0;
202  static double mass_cont_sub_dtsum = 0.0;
203  if (mass_cont_sub_counter == 0) {
204  stdout_flags_count0 = m_stdout_flags;
205  }
206  if (delta_t > 0.0) {
207  mass_cont_sub_counter++;
208  mass_cont_sub_dtsum += delta_t;
209  }
210 
211  if (tempAndAge or (not do_energy) or (m_log->get_threshold() > 2)) {
212  std::string tempstr;
213 
214  const double major_dt = m_time->convert_time_interval(mass_cont_sub_dtsum, time_units);
215  if (mass_cont_sub_counter <= 1) {
216  tempstr = pism::printf(" (dt=%.5f)", major_dt);
217  } else {
218  tempstr = pism::printf(" (dt=%.5f in %d substeps; av dt_sub_mass_cont=%.5f)",
219  major_dt, mass_cont_sub_counter, major_dt / mass_cont_sub_counter);
220  }
221  stdout_flags_count0 += tempstr;
222 
223  if (delta_t > 0.0) { // avoids printing an empty line if we have not done anything
224  stdout_flags_count0 += "\n";
225  m_log->message(2, stdout_flags_count0);
226  }
227 
228  double T = m_time->current();
229  if (use_calendar) {
230  tempstr = pism::printf("%12s", m_time->date(T).c_str());
231  } else {
232  tempstr = pism::printf("%.3f", m_time->convert_time_interval(T, time_units));
233  }
234 
235  const CFLData cfl = m_stress_balance->max_timestep_cfl_2d();
236  std::string velocity_units = "meters / (" + time_units + ")";
237  const double maxvel = units::convert(m_sys, std::max(cfl.u_max, cfl.v_max),
238  "m second-1", velocity_units);
239 
240  m_log->message(2,
241  "S %s: %8.5f %9.5f %12.5f %12.5f\n",
242  tempstr.c_str(),
243  volume/(scalevol*1.0e9), area/(scalearea*1.0e6),
244  max_diffusivity, maxvel);
245 
246  mass_cont_sub_counter = 0;
247  mass_cont_sub_dtsum = 0.0;
248  }
249 }
250 
251 
252 } // end of namespace pism
array::Scalar2 ice_thickness
Definition: Geometry.hh:51
virtual double compute_temperate_base_fraction(double ice_area)
std::shared_ptr< stressbalance::StressBalance > m_stress_balance
Definition: IceModel.hh:397
const Config::Ptr m_config
Configuration flags and parameters.
Definition: IceModel.hh:243
const Time::Ptr m_time
Time manager.
Definition: IceModel.hh:251
Geometry m_geometry
Definition: IceModel.hh:295
const Logger::Ptr m_log
Logger.
Definition: IceModel.hh:249
virtual void print_summary(bool tempAndAge)
Definition: printout.cc:89
std::string m_stdout_flags
Definition: IceModel.hh:328
const units::System::Ptr m_sys
Unit system.
Definition: IceModel.hh:247
virtual void print_summary_line(bool printPrototype, bool tempAndAge, double delta_t, double volume, double area, double meltfrac, double max_diffusivity)
Print a line to stdout which summarizes the state of the modeled ice sheet at the end of the time ste...
Definition: printout.cc:164
double dt_TempAge
enthalpy/temperature and age time-steps
Definition: IceModel.hh:322
double m_dt
mass continuity time step, s
Definition: IceModel.hh:318
const std::shared_ptr< Grid > m_grid
Computational grid.
Definition: IceModel.hh:241
void failed()
Indicates a failure of a parallel section.
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition: Array.hh:65
double * get_column(int i, int j)
Definition: Array3D.cc:120
A virtual class collecting methods common to ice and bedrock 3D fields.
Definition: Array3D.hh:33
std::shared_ptr< const Grid > grid() const
Definition: Array.cc:132
double max(const array::Scalar &input)
Finds maximum over all the values in an array::Scalar object. Ignores ghosts.
Definition: Scalar.cc:165
double convert(System::Ptr system, double input, const std::string &spec1, const std::string &spec2)
Convert a quantity from unit1 to unit2.
Definition: Units.cc:70
unsigned int count_CFL_violations(const array::Array3D &u3, const array::Array3D &v3, const array::Scalar &ice_thickness, double dt)
Because of the -skip mechanism it is still possible that we can have CFL violations: count them.
Definition: printout.cc:42
double ice_area(const Geometry &geometry, double thickness_threshold)
Computes ice area, in m^2.
Definition: Geometry.cc:324
void GlobalMax(MPI_Comm comm, double *local, double *result, int count)
std::string printf(const char *format,...)
static const double k
Definition: exactTestP.cc:42
double ice_volume(const Geometry &geometry, double thickness_threshold)
Computes the ice volume, in m^3.
Definition: Geometry.cc:253