tSSATestCase.cc - pism - [fork] customized build of PISM, the parallel ice sheet model (tillflux branch)
HTML git clone git://src.adamsgaard.dk/pism
DIR Log
DIR Files
DIR Refs
DIR LICENSE
---
tSSATestCase.cc (13367B)
---
1 // Copyright (C) 2009--2019 Ed Bueler, Constantine Khroulev, and David Maxwell
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 "SSATestCase.hh"
20 #include "SSAFD.hh"
21 #include "SSAFEM.hh"
22 #include "pism/util/Mask.hh"
23 #include "pism/util/Time.hh"
24 #include "pism/util/io/File.hh"
25 #include "pism/util/pism_options.hh"
26 #include "pism/util/io/io_helpers.hh"
27 #include "pism/util/pism_utilities.hh"
28 #include "pism/stressbalance/StressBalance.hh"
29
30 namespace pism {
31 namespace stressbalance {
32
33 SSATestCase::SSATestCase(Context::Ptr ctx, int Mx, int My,
34 double Lx, double Ly,
35 GridRegistration registration,
36 Periodicity periodicity)
37 : m_com(ctx->com()), m_ctx(ctx), m_config(ctx->config()),
38 m_grid(IceGrid::Shallow(m_ctx, Lx, Ly, 0.0, 0.0, Mx, My, registration, periodicity)),
39 m_sys(ctx->unit_system()),
40 m_geometry(m_grid),
41 m_ssa(NULL) {
42
43 const unsigned int WIDE_STENCIL = m_config->get_number("grid.max_stencil_width");
44
45 // yield stress for basal till (plastic or pseudo-plastic model)
46 m_tauc.create(m_grid, "tauc", WITH_GHOSTS, WIDE_STENCIL);
47 m_tauc.set_attrs("diagnostic",
48 "yield stress for basal till (plastic or pseudo-plastic model)",
49 "Pa", "Pa", "", 0);
50
51 // enthalpy
52 m_ice_enthalpy.create(m_grid, "enthalpy", WITH_GHOSTS, WIDE_STENCIL);
53 m_ice_enthalpy.set_attrs("model_state",
54 "ice enthalpy (includes sensible heat, latent heat, pressure)",
55 "J kg-1", "J kg-1", "", 0);
56
57 // dirichlet boundary condition (FIXME: perhaps unused!)
58 m_bc_values.create(m_grid, "_bc", WITH_GHOSTS, WIDE_STENCIL); // u_bc and v_bc
59 m_bc_values.set_attrs("intent",
60 "X-component of the SSA velocity boundary conditions",
61 "m s-1", "m year-1", "", 0);
62 m_bc_values.set_attrs("intent",
63 "Y-component of the SSA velocity boundary conditions",
64 "m s-1", "m year-1", "", 1);
65
66 Config::ConstPtr config = m_grid->ctx()->config();
67 units::System::Ptr sys = m_grid->ctx()->unit_system();
68 double fill_value = units::convert(sys, config->get_number("output.fill_value"), "m year-1", "m second-1");
69
70 auto large_number = units::convert(m_sys, 1e6, "m year-1", "m second-1");
71
72 m_bc_values.metadata(0).set_numbers("valid_range", {-large_number, large_number});
73 m_bc_values.metadata(0).set_number("_FillValue", fill_value);
74
75 m_bc_values.metadata(1).set_numbers("valid_range", {-large_number, large_number});
76 m_bc_values.metadata(1).set_number("_FillValue", fill_value);
77
78 m_bc_values.set(fill_value);
79
80 // Dirichlet B.C. mask
81 m_bc_mask.create(m_grid, "bc_mask", WITH_GHOSTS, WIDE_STENCIL);
82 m_bc_mask.set_attrs("model_state",
83 "grounded_dragging_floating integer mask",
84 "", "", "", 0);
85
86 m_bc_mask.metadata().set_numbers("flag_values", {0.0, 1.0});
87 m_bc_mask.metadata().set_string("flag_meanings",
88 "no_data ssa.dirichlet_bc_location");
89
90 m_melange_back_pressure.create(m_grid, "melange_back_pressure_fraction",
91 WITH_GHOSTS, WIDE_STENCIL);
92 m_melange_back_pressure.set_attrs("boundary_condition",
93 "melange back pressure fraction",
94 "", "", "", 0);
95 m_melange_back_pressure.set(0.0);
96 }
97
98 SSATestCase::~SSATestCase()
99 {
100 delete m_ssa;
101 }
102
103 //! Initialize the test case at the start of a run
104 void SSATestCase::init() {
105
106 m_ssa->init();
107
108 // Allow the subclass to set the coefficients.
109 initializeSSACoefficients();
110 }
111
112 //! Solve the SSA
113 void SSATestCase::run() {
114 m_ctx->log()->message(2, "* Solving the SSA stress balance ...\n");
115
116 m_geometry.ensure_consistency(m_config->get_number("stress_balance.ice_free_thickness_standard"));
117
118 Inputs inputs;
119 inputs.melange_back_pressure = &m_melange_back_pressure;
120 inputs.geometry = &m_geometry;
121 inputs.enthalpy = &m_ice_enthalpy;
122 inputs.basal_yield_stress = &m_tauc;
123 inputs.bc_mask = &m_bc_mask;
124 inputs.bc_values = &m_bc_values;
125
126 bool full_update = true;
127 m_ssa->update(inputs, full_update);
128 }
129
130 //! Report on the generated solution
131 void SSATestCase::report(const std::string &testname) {
132
133 m_ctx->log()->message(3, m_ssa->stdout_report());
134
135 double
136 maxvecerr = 0.0,
137 avvecerr = 0.0,
138 avuerr = 0.0,
139 avverr = 0.0,
140 maxuerr = 0.0,
141 maxverr = 0.0;
142 double
143 gmaxvecerr = 0.0,
144 gavvecerr = 0.0,
145 gavuerr = 0.0,
146 gavverr = 0.0,
147 gmaxuerr = 0.0,
148 gmaxverr = 0.0;
149
150 if (m_config->get_flag("basal_resistance.pseudo_plastic.enabled") &&
151 m_config->get_number("basal_resistance.pseudo_plastic.q") != 1.0) {
152 m_ctx->log()->message(1,
153 "WARNING: numerical errors not valid for pseudo-plastic till\n");
154 }
155 m_ctx->log()->message(1,
156 "NUMERICAL ERRORS in velocity relative to exact solution:\n");
157
158 const IceModelVec2V &vel_ssa = m_ssa->velocity();
159
160 IceModelVec::AccessList list{&vel_ssa};
161
162 double exactvelmax = 0, gexactvelmax = 0;
163 for (Points p(*m_grid); p; p.next()) {
164 const int i = p.i(), j = p.j();
165
166 double uexact, vexact;
167 double myx = m_grid->x(i), myy = m_grid->y(j);
168
169 exactSolution(i,j,myx,myy,&uexact,&vexact);
170
171 double exactnormsq=sqrt(uexact*uexact+vexact*vexact);
172 exactvelmax = std::max(exactnormsq,exactvelmax);
173
174 // compute maximum errors
175 const double uerr = fabs(vel_ssa(i,j).u - uexact);
176 const double verr = fabs(vel_ssa(i,j).v - vexact);
177 avuerr = avuerr + uerr;
178 avverr = avverr + verr;
179 maxuerr = std::max(maxuerr,uerr);
180 maxverr = std::max(maxverr,verr);
181 const double vecerr = sqrt(uerr * uerr + verr * verr);
182 maxvecerr = std::max(maxvecerr,vecerr);
183 avvecerr = avvecerr + vecerr;
184 }
185
186 unsigned int N = (m_grid->Mx()*m_grid->My());
187
188 gexactvelmax = GlobalMax(m_grid->com, exactvelmax);
189 gmaxuerr = GlobalMax(m_grid->com, maxuerr);
190 gmaxverr = GlobalMax(m_grid->com, maxverr);
191 gavuerr = GlobalSum(m_grid->com, avuerr);
192 gavuerr = gavuerr / N;
193 gavverr = GlobalSum(m_grid->com, avverr);
194 gavverr = gavverr / N;
195 gmaxvecerr = GlobalMax(m_grid->com, maxvecerr);
196 gavvecerr = GlobalSum(m_grid->com, avvecerr);
197 gavvecerr = gavvecerr / N;
198
199 using pism::units::convert;
200
201 m_ctx->log()->message(1,
202 "velocity : maxvector prcntavvec maxu maxv avu avv\n");
203 m_ctx->log()->message(1,
204 " %11.4f%13.5f%10.4f%10.4f%10.4f%10.4f\n",
205 convert(m_sys, gmaxvecerr, "m second-1", "m year-1"),
206 (gavvecerr/gexactvelmax)*100.0,
207 convert(m_sys, gmaxuerr, "m second-1", "m year-1"),
208 convert(m_sys, gmaxverr, "m second-1", "m year-1"),
209 convert(m_sys, gavuerr, "m second-1", "m year-1"),
210 convert(m_sys, gavverr, "m second-1", "m year-1"));
211
212 m_ctx->log()->message(1, "NUM ERRORS DONE\n");
213
214 report_netcdf(testname,
215 convert(m_sys, gmaxvecerr, "m second-1", "m year-1"),
216 (gavvecerr/gexactvelmax)*100.0,
217 convert(m_sys, gmaxuerr, "m second-1", "m year-1"),
218 convert(m_sys, gmaxverr, "m second-1", "m year-1"),
219 convert(m_sys, gavuerr, "m second-1", "m year-1"),
220 convert(m_sys, gavverr, "m second-1", "m year-1"));
221 }
222
223 void SSATestCase::report_netcdf(const std::string &testname,
224 double max_vector,
225 double rel_vector,
226 double max_u,
227 double max_v,
228 double avg_u,
229 double avg_v) {
230 TimeseriesMetadata err("N", "N", m_grid->ctx()->unit_system());
231 unsigned int start;
232 VariableMetadata global_attributes("PISM_GLOBAL", m_grid->ctx()->unit_system());
233
234 options::String filename("-report_file", "NetCDF error report file");
235
236 if (not filename.is_set()) {
237 return;
238 }
239
240 err.set_string("units", "1");
241
242 m_ctx->log()->message(2, "Also writing errors to '%s'...\n", filename->c_str());
243
244 bool append = options::Bool("-append", "Append the NetCDF error report");
245
246 IO_Mode mode = PISM_READWRITE;
247 if (not append) {
248 mode = PISM_READWRITE_MOVE;
249 }
250
251 global_attributes.set_string("source", std::string("PISM ") + pism::revision);
252
253 // Find the number of records in this file:
254 File file(m_grid->com, filename, PISM_NETCDF3, mode); // OK to use NetCDF3.
255 start = file.dimension_length("N");
256
257 io::write_attributes(file, global_attributes, PISM_DOUBLE);
258
259 // Write the dimension variable:
260 io::write_timeseries(file, err, (size_t)start, (double)(start + 1), PISM_INT);
261
262 // Always write grid parameters:
263 err.set_name("dx");
264 err.set_string("units", "meters");
265 io::write_timeseries(file, err, (size_t)start, m_grid->dx());
266 err.set_name("dy");
267 io::write_timeseries(file, err, (size_t)start, m_grid->dy());
268
269 // Always write the test name:
270 err.clear_all_strings(); err.clear_all_doubles(); err.set_string("units", "1");
271 err.set_name("test");
272 io::write_timeseries(file, err, (size_t)start, testname[0], PISM_INT);
273
274 err.clear_all_strings(); err.clear_all_doubles(); err.set_string("units", "1");
275 err.set_name("max_velocity");
276 err.set_string("units", "m year-1");
277 err.set_string("long_name", "maximum ice velocity magnitude error");
278 io::write_timeseries(file, err, (size_t)start, max_vector);
279
280 err.clear_all_strings(); err.clear_all_doubles(); err.set_string("units", "1");
281 err.set_name("relative_velocity");
282 err.set_string("units", "percent");
283 err.set_string("long_name", "relative ice velocity magnitude error");
284 io::write_timeseries(file, err, (size_t)start, rel_vector);
285
286 err.clear_all_strings(); err.clear_all_doubles(); err.set_string("units", "1");
287 err.set_name("maximum_u");
288 err.set_string("units", "m year-1");
289 err.set_string("long_name", "maximum error in the X-component of the ice velocity");
290 io::write_timeseries(file, err, (size_t)start, max_u);
291
292 err.clear_all_strings(); err.clear_all_doubles(); err.set_string("units", "1");
293 err.set_name("maximum_v");
294 err.set_string("units", "m year-1");
295 err.set_string("long_name", "maximum error in the Y-component of the ice velocity");
296 io::write_timeseries(file, err, (size_t)start, max_v);
297
298 err.clear_all_strings(); err.clear_all_doubles(); err.set_string("units", "1");
299 err.set_name("average_u");
300 err.set_string("units", "m year-1");
301 err.set_string("long_name", "average error in the X-component of the ice velocity");
302 io::write_timeseries(file, err, (size_t)start, avg_u);
303
304 err.clear_all_strings(); err.clear_all_doubles(); err.set_string("units", "1");
305 err.set_name("average_v");
306 err.set_string("units", "m year-1");
307 err.set_string("long_name", "average error in the Y-component of the ice velocity");
308 io::write_timeseries(file, err, (size_t)start, avg_v);
309
310 file.close();
311 }
312
313 void SSATestCase::exactSolution(int /*i*/, int /*j*/,
314 double /*x*/, double /*y*/,
315 double *u, double *v) {
316 *u=0; *v=0;
317 }
318
319 //! Save the computation and data to a file.
320 void SSATestCase::write(const std::string &filename) {
321
322 // Write results to an output file:
323 File file(m_grid->com, filename, PISM_NETCDF3, PISM_READWRITE_MOVE);
324 io::define_time(file, *m_grid->ctx());
325 io::append_time(file, *m_config, 0.0);
326
327 m_geometry.ice_surface_elevation.write(file);
328 m_geometry.ice_thickness.write(file);
329 m_bc_mask.write(file);
330 m_tauc.write(file);
331 m_geometry.bed_elevation.write(file);
332 m_ice_enthalpy.write(file);
333 m_bc_values.write(file);
334
335 const IceModelVec2V &vel_ssa = m_ssa->velocity();
336 vel_ssa.write(file);
337
338 IceModelVec2V exact;
339 exact.create(m_grid, "_exact", WITHOUT_GHOSTS);
340 exact.set_attrs("diagnostic",
341 "X-component of the SSA exact solution",
342 "m s-1", "m year-1", "", 0);
343 exact.set_attrs("diagnostic",
344 "Y-component of the SSA exact solution",
345 "m s-1", "m year-1", "", 1);
346
347 IceModelVec::AccessList list(exact);
348 for (Points p(*m_grid); p; p.next()) {
349 const int i = p.i(), j = p.j();
350
351 exactSolution(i, j, m_grid->x(i), m_grid->y(j),
352 &(exact(i,j).u), &(exact(i,j).v));
353 }
354 exact.write(file);
355
356 file.close();
357 }
358
359 } // end of namespace stressbalance
360 } // end of namespace pism