PISM, A Parallel Ice Sheet Model 2.2.1-cd005eec8 committed by Constantine Khrulev on 2025-03-07
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
iceCompModel.cc
Go to the documentation of this file.
1// Copyright (C) 2004-2024 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 <cmath>
20#include <cstring>
21
22#include <algorithm> // required by sort(...) in test L
23#include <memory>
24#include <vector> // STL vector container; sortable; used in test L
25
26#include "pism/verification/tests/exactTestH.h"
27#include "pism/verification/tests/exactTestL.hh"
28#include "pism/verification/tests/exactTestsABCD.h"
29#include "pism/verification/tests/exactTestsFG.hh"
30
31#include "pism/verification/BTU_Verification.hh"
32#include "pism/verification/PSVerification.hh"
33#include "pism/verification/TemperatureModel_Verification.hh"
34#include "pism/verification/iceCompModel.hh"
35#include "pism/coupler/SeaLevel.hh"
36#include "pism/coupler/ocean/Constant.hh"
37#include "pism/earth/BedDef.hh"
38#include "pism/energy/BTU_Minimal.hh"
39#include "pism/rheology/PatersonBuddCold.hh"
40#include "pism/stressbalance/ShallowStressBalance.hh"
41#include "pism/stressbalance/StressBalance.hh"
42#include "pism/stressbalance/sia/SIAFD.hh"
43#include "pism/util/ConfigInterface.hh"
44#include "pism/util/Context.hh"
45#include "pism/util/EnthalpyConverter.hh"
46#include "pism/util/Grid.hh"
47#include "pism/util/Logger.hh"
48#include "pism/util/Mask.hh"
49#include "pism/util/Time.hh"
50#include "pism/util/error_handling.hh"
51#include "pism/util/io/File.hh"
52#include "pism/util/io/io_helpers.hh"
53#include "pism/util/pism_options.hh"
54#include "pism/util/pism_utilities.hh"
55
56namespace pism {
57
58using units::convert;
59
60IceCompModel::IceCompModel(std::shared_ptr<Grid> grid, std::shared_ptr<Context> context, int test)
61 : IceModel(grid, context),
62 m_testname(test),
63 m_HexactL(m_grid, "HexactL"),
64 m_strain_heating3_comp(m_grid, "strain_heating_comp", array::WITHOUT_GHOSTS, m_grid->z()),
65 m_bedrock_is_ice_forK(false) {
66
67 m_log->message(2, "starting Test %c ...\n", m_testname);
68
69 // Override some defaults from parent class
70 m_config->set_number("stress_balance.sia.enhancement_factor", 1.0);
71 // none use bed smoothing & bed roughness parameterization
72 m_config->set_number("stress_balance.sia.bed_smoother.range", 0.0);
73
74 // set values of flags in run()
75 m_config->set_flag("geometry.update.enabled", true);
76 m_config->set_flag("geometry.update.use_basal_melt_rate", false);
77
78 // flow law settings
79 switch (m_testname) {
80 case 'A':
81 case 'B':
82 case 'C':
83 case 'D':
84 case 'H':
85 case 'L': {
86 m_config->set_string("stress_balance.sia.flow_law", "isothermal_glen");
87 const double year = convert(m_sys, 1.0, "year", "seconds");
88 m_config->set_number("flow_law.isothermal_Glen.ice_softness", 1.0e-16 / year);
89 break;
90 }
91 case 'V': {
92 m_config->set_string("stress_balance.ssa.flow_law", "isothermal_glen");
93 const double hardness = 1.9e8,
94 softness =
95 pow(hardness, -m_config->get_number("stress_balance.ssa.Glen_exponent"));
96 m_config->set_number("flow_law.isothermal_Glen.ice_softness", softness);
97 break;
98 }
99 case 'F':
100 case 'G':
101 case 'K':
102 case 'O':
103 default: {
104 m_config->set_string("stress_balance.sia.flow_law", "arr");
105 break;
106 }
107 }
108
109 if (m_testname == 'H') {
110 m_config->set_string("bed_deformation.model", "iso");
111 } else {
112 m_config->set_string("bed_deformation.model", "none");
113 }
114
115 if ((m_testname == 'F') || (m_testname == 'G') || (m_testname == 'K') || (m_testname == 'O')) {
116 m_config->set_string("energy.model", "cold");
117 // essentially turn off run-time reporting of extremely low computed
118 // temperatures; *they will be reported as errors* anyway
119 m_config->set_number("energy.minimum_allowed_temperature", 0.0);
120 m_config->set_number("energy.max_low_temperature_count", 1000000);
121 } else {
122 m_config->set_string("energy.model", "none");
123 }
124
125 // set sea level to -1e4 to ensure that all ice is grounded
126 m_config->set_number("sea_level.constant.value", -1e4);
127
128 // special considerations for K and O wrt thermal bedrock and pressure-melting
129 if ((m_testname == 'K') || (m_testname == 'O')) {
130 m_config->set_flag("energy.allow_temperature_above_melting", false);
131 } else {
132 // note temps are generally allowed to go above pressure melting in verify
133 m_config->set_flag("energy.allow_temperature_above_melting", true);
134 }
135
136 if (m_testname == 'V') {
137 // no sub-shelf melting
138 m_config->set_flag("geometry.update.use_basal_melt_rate", false);
139
140 // this test is isothermal
141 m_config->set_string("energy.model", "none");
142
143 // use the SSA solver
144 m_config->set_string("stress_balance_model", "ssa");
145
146 // set sea level to 0.0
147 m_config->set_number("sea_level.constant.value", 0.0);
148
149 m_config->set_flag("stress_balance.ssa.dirichlet_bc", true);
150 }
151}
152
154
156
158 .long_name("rate of compensatory strain heating in ice")
159 .units("W m^-3");
160}
161
163
164 if (m_btu != NULL) {
165 return;
166 }
167
168 // this switch changes Test K to make material properties for bedrock the same as for ice
169 bool biiSet = options::Bool("-bedrock_is_ice", "set bedrock properties to those of ice");
170 if (biiSet) {
171 if (m_testname == 'K') {
172 m_log->message(1, "setting material properties of bedrock to those of ice in Test K\n");
173 m_config->set_number("energy.bedrock_thermal.density",
174 m_config->get_number("constants.ice.density"));
175 m_config->set_number("energy.bedrock_thermal.conductivity",
176 m_config->get_number("constants.ice.thermal_conductivity"));
177 m_config->set_number("energy.bedrock_thermal.specific_heat_capacity",
178 m_config->get_number("constants.ice.specific_heat_capacity"));
180 } else {
181 m_log->message(
182 1, "IceCompModel WARNING: option -bedrock_is_ice ignored; only applies to Test K\n");
183 }
184 }
185
186 if (m_testname != 'K') {
187 // now make bedrock have same material properties as ice
188 // (note Mbz=1 also, by default, but want ice/rock interface to see
189 // pure ice from the point of view of applying geothermal boundary
190 // condition, especially in tests F and G)
191 m_config->set_number("energy.bedrock_thermal.density",
192 m_config->get_number("constants.ice.density"));
193 m_config->set_number("energy.bedrock_thermal.conductivity",
194 m_config->get_number("constants.ice.thermal_conductivity"));
195 m_config->set_number("energy.bedrock_thermal.specific_heat_capacity",
196 m_config->get_number("constants.ice.specific_heat_capacity"));
197 }
198
199 auto bed_vertical_grid = energy::BTUGrid::FromOptions(m_grid->ctx());
200
201 if (bed_vertical_grid.Mbz > 1) {
202 m_btu = std::make_shared<energy::BTU_Verification>(m_grid, bed_vertical_grid,
204 } else {
205 m_btu = std::make_shared<energy::BTU_Minimal>(m_grid);
206 }
207
208 m_submodels["bedrock thermal layer"] = m_btu.get();
209}
210
212
213 if (m_energy_model != nullptr) {
214 return;
215 }
216
217 m_log->message(2, "# Allocating an energy balance model...\n");
218
219 // this switch changes Test K to make material properties for bedrock the same as for ice
220 bool bedrock_is_ice = options::Bool("-bedrock_is_ice", "set bedrock properties to those of ice");
221
222 m_energy_model = std::make_shared<energy::TemperatureModel_Verification>(
223 m_grid, m_stress_balance, m_testname, bedrock_is_ice);
224
225 m_submodels["energy balance model"] = m_energy_model.get();
226}
227
228
230
232
233 // for simple isostasy
234 m_f = m_config->get_number("constants.ice.density") / m_config->get_number("bed_deformation.mantle_density");
235
236 std::string bed_def_model = m_config->get_string("bed_deformation.model");
237
238 if ((m_testname == 'H') && bed_def_model != "iso") {
239 m_log->message(1,
240 "IceCompModel WARNING: Test H should be run with option\n"
241 " '-bed_def iso' for the reported errors to be correct.\n");
242 }
243}
244
246 EnthalpyConverter::Ptr EC = m_ctx->enthalpy_converter();
247
248 // Climate will always come from verification test formulas.
250 m_submodels["surface process model"] = m_surface.get();
251
252 m_ocean.reset(new ocean::Constant(m_grid));
253 m_submodels["ocean model"] = m_ocean.get();
254
256 m_submodels["sea level forcing"] = m_sea_level.get();
257}
258
259void IceCompModel::bootstrap_2d(const File &/*input_file*/) {
261 "PISM does not support bootstrapping in verification mode.");
262}
263
265 m_log->message(3, "initializing Test %c from formulas ...\n",m_testname);
266
269
270 array::Scalar uplift(m_grid, "uplift");
271 uplift.set(0.0);
272
274 uplift,
277
278 // Test-specific initialization:
279 switch (m_testname) {
280 case 'A':
281 case 'B':
282 case 'C':
283 case 'D':
284 case 'H':
286 break;
287 case 'F':
288 case 'G':
289 initTestFG(); // see iCMthermo.cc
290 break;
291 case 'K':
292 case 'O':
293 initTestsKO(); // see iCMthermo.cc
294 break;
295 case 'L':
296 initTestL();
297 break;
298 case 'V':
299 test_V_init();
300 break;
301 default:
302 throw RuntimeError(PISM_ERROR_LOCATION, "Desired test not implemented by IceCompModel.");
303 }
304}
305
307
308 const double time = m_time->current();
309
311
313
314 ParallelSection loop(m_grid->com);
315 try {
316 for (auto p = m_grid->points(); p; p.next()) {
317 const int i = p.i(), j = p.j();
318
319 const double r = grid::radius(*m_grid, i, j);
320 switch (m_testname) {
321 case 'A':
322 m_geometry.ice_thickness(i, j) = exactA(r).H;
323 break;
324 case 'B':
325 m_geometry.ice_thickness(i, j) = exactB(time, r).H;
326 break;
327 case 'C':
328 m_geometry.ice_thickness(i, j) = exactC(time, r).H;
329 break;
330 case 'D':
331 m_geometry.ice_thickness(i, j) = exactD(time, r).H;
332 break;
333 case 'H':
334 m_geometry.ice_thickness(i, j) = exactH(m_f, time, r).H;
335 break;
336 default:
337 throw RuntimeError(PISM_ERROR_LOCATION, "test must be A, B, C, D, or H");
338 }
339 }
340 } catch (...) {
341 loop.failed();
342 }
343 loop.check();
344
346
347 {
348 array::Scalar bed_uplift(m_grid, "uplift");
349 bed_uplift.set(0.0);
350
351 if (m_testname == 'H') {
354 } else { // flat bed case otherwise
356 }
360 }
361}
362
363//! Class used initTestL() in generating sorted list for ODE solver.
364class rgrid {
365public:
366 double r;
367 int i,j;
368};
369
370//! Comparison used initTestL() in generating sorted list for ODE solver.
372 bool operator()(rgrid a, rgrid b) {
373 return (a.r > b.r);
374 }
375};
376
378
379 m_log->message(2, "* Initializing ice thickness and bed topography for test L...\n");
380
381 // setup to evaluate test L; requires solving an ODE numerically
382 // using sorted list of radii, sorted in decreasing radius order
383 const int MM = m_grid->xm() * m_grid->ym();
384
385 std::vector<rgrid> rrv(MM);
386 int k = 0;
387 for (auto p = m_grid->points(); p; p.next()) {
388 const int i = p.i(), j = p.j();
389
390 rrv[k].i = i;
391 rrv[k].j = j;
392 rrv[k].r = grid::radius(*m_grid, i,j);
393
394 k += 1;
395 }
396
397 std::sort(rrv.begin(), rrv.end(), rgridReverseSort()); // so rrv[k].r > rrv[k+1].r
398
399 // get soln to test L at these radii; solves ODE only once (on each processor)
400 std::vector<double> rr(MM), HH(MM), bb(MM), aa(MM);
401
402 for (k = 0; k < MM; k++) {
403 rr[k] = rrv[k].r;
404 }
405
407
408 {
409 array::Scalar bed_uplift(m_grid, "uplift");
410
412
413 for (k = 0; k < MM; k++) {
414 m_geometry.ice_thickness(rrv[k].i, rrv[k].j) = L.H[k];
415 m_geometry.bed_elevation(rrv[k].i, rrv[k].j) = L.b[k];
416 }
417
419
420 bed_uplift.set(0.0);
421
424 }
425
426 // store copy of ice_thickness for evaluating geometry errors
428}
429
430//! \brief Tests A and E have a thickness B.C. (ice_thickness == 0 outside a circle of radius 750km).
432 const double LforAE = 750e3; // m
433
435
436 for (auto p = m_grid->points(); p; p.next()) {
437 const int i = p.i(), j = p.j();
438
439 if (grid::radius(*m_grid, i, j) > LforAE) {
440 m_geometry.ice_thickness(i, j) = 0;
441 }
442 }
443
445}
446
447void IceCompModel::computeGeometryErrors(double &gvolexact, double &gareaexact,
448 double &gdomeHexact, double &volerr,
449 double &areaerr, double &gmaxHerr,
450 double &gavHerr, double &gmaxetaerr,
451 double &centerHerr) {
452 // compute errors in thickness, eta=thickness^{(2n+2)/n}, volume, area
453
454 const double time = m_time->current();
455 double
456 Hexact = 0.0,
457 vol = 0.0,
458 area = 0.0,
459 domeH = 0.0,
460 volexact = 0.0,
461 areaexact = 0.0,
462 domeHexact = 0.0;
463 double
464 Herr = 0.0,
465 avHerr = 0.0,
466 etaerr = 0.0;
467
469 if (m_testname == 'L') {
470 list.add(m_HexactL);
471 }
472
473 double
474 seawater_density = m_config->get_number("constants.sea_water.density"),
475 ice_density = m_config->get_number("constants.ice.density"),
476 Glen_n = m_config->get_number("stress_balance.sia.Glen_exponent"),
477 standard_gravity = m_config->get_number("constants.standard_gravity");
478
479 // area of grid square in square km:
480 const double a = m_grid->dx() * m_grid->dy() * 1e-3 * 1e-3;
481 const double m = (2.0 * Glen_n + 2.0) / Glen_n;
482
483 ParallelSection loop(m_grid->com);
484 try {
485 for (auto p = m_grid->points(); p; p.next()) {
486 const int i = p.i(), j = p.j();
487
488 if (m_geometry.ice_thickness(i,j) > 0) {
489 area += a;
490 vol += a * m_geometry.ice_thickness(i,j) * 1e-3;
491 }
492 double xx = m_grid->x(i), r = grid::radius(*m_grid, i,j);
493 switch (m_testname) {
494 case 'A':
495 Hexact = exactA(r).H;
496 break;
497 case 'B':
498 Hexact = exactB(time, r).H;
499 break;
500 case 'C':
501 Hexact = exactC(time, r).H;
502 break;
503 case 'D':
504 Hexact = exactD(time, r).H;
505 break;
506 case 'F':
507 if (r > m_LforFG - 1.0) { // outside of sheet
508 Hexact=0.0;
509 } else {
510 r=std::max(r,1.0);
511 std::vector<double> z(1, 0.0);
512 Hexact = exactFG(0.0, r, z, 0.0).H;
513 }
514 break;
515 case 'G':
516 if (r > m_LforFG -1.0) { // outside of sheet
517 Hexact=0.0;
518 } else {
519 r=std::max(r,1.0);
520 std::vector<double> z(1, 0.0);
521 Hexact = exactFG(time, r, z, m_ApforG).H;
522 }
523 break;
524 case 'H':
525 Hexact = exactH(m_f, time, r).H;
526 break;
527 case 'K':
528 case 'O':
529 Hexact = 3000.0;
530 break;
531 case 'L':
532 Hexact = m_HexactL(i,j);
533 break;
534 case 'V':
535 {
536 double
537 H0 = 600.0,
538 v0 = convert(m_sys, 300.0, "m year-1", "m second-1"),
539 Q0 = H0 * v0,
540 B0 = m_stress_balance->shallow()->flow_law()->hardness(0, 0),
541 C = pow(ice_density * standard_gravity * (1.0 - ice_density/seawater_density) / (4 * B0), 3);
542
543 Hexact = pow(4 * C / Q0 * xx + 1/pow(H0, 4), -0.25);
544 }
545 break;
546 default:
547 throw RuntimeError(PISM_ERROR_LOCATION, "test must be A, B, C, D, F, G, H, K, L, or O");
548 }
549
550 if (Hexact > 0) {
551 areaexact += a;
552 volexact += a * Hexact * 1e-3;
553 }
554 if (i == ((int)m_grid->Mx() - 1)/2 and
555 j == ((int)m_grid->My() - 1)/2) {
556 domeH = m_geometry.ice_thickness(i,j);
557 domeHexact = Hexact;
558 }
559 // compute maximum errors
560 Herr = std::max(Herr,fabs(m_geometry.ice_thickness(i,j) - Hexact));
561 etaerr = std::max(etaerr,fabs(pow(m_geometry.ice_thickness(i,j),m) - pow(Hexact,m)));
562 // add to sums for average errors
563 avHerr += fabs(m_geometry.ice_thickness(i,j) - Hexact);
564 }
565 } catch (...) {
566 loop.failed();
567 }
568 loop.check();
569
570 // globalize (find errors over all processors)
571 double gvol, garea, gdomeH;
572 gvolexact = GlobalSum(m_grid->com, volexact);
573 gdomeHexact = GlobalMax(m_grid->com, domeHexact);
574 gareaexact = GlobalSum(m_grid->com, areaexact);
575
576 gvol = GlobalSum(m_grid->com, vol);
577 garea = GlobalSum(m_grid->com, area);
578 volerr = fabs(gvol - gvolexact);
579 areaerr = fabs(garea - gareaexact);
580
581 gmaxHerr = GlobalMax(m_grid->com, Herr);
582 gavHerr = GlobalSum(m_grid->com, avHerr);
583 gavHerr = gavHerr/(m_grid->Mx()*m_grid->My());
584 gmaxetaerr = GlobalMax(m_grid->com, etaerr);
585
586 gdomeH = GlobalMax(m_grid->com, domeH);
587 centerHerr = fabs(gdomeH - gdomeHexact);
588}
589
591 if (m_testname == 'A') {
593 }
594}
595
596
597void IceCompModel::print_summary(bool /* tempAndAge */) {
598 // we always show a summary at every step
600}
601
602static void write(units::System::Ptr sys, const File &file, size_t start, const char *name,
603 const char *units, const char *long_name, double value,
604 io::Type type = io::PISM_DOUBLE) {
605 VariableMetadata v(name, sys);
606 v["units"] = units;
607 v["long_name"] = long_name;
608
609 io::define_timeseries(v, "N", file, type);
610 io::write_timeseries(file, v, start, { value });
611}
612
614 // geometry errors to report (for all tests except K and O):
615 // -- max thickness error
616 // -- average (at each grid point on whole grid) thickness error
617 // -- max (thickness)^(2n+2)/n error
618 // -- volume error
619 // -- area error
620 // and temperature errors (for tests F & G & K & O):
621 // -- max T error over 3D domain of ice
622 // -- av T error over 3D domain of ice
623 // and basal temperature errors (for tests F & G):
624 // -- max basal temp error
625 // -- average (at each grid point on whole grid) basal temp error
626 // and bedrock temperature errors (for tests K & O):
627 // -- max Tb error over 3D domain of bedrock
628 // -- av Tb error over 3D domain of bedrock
629 // and strain-heating (Sigma) errors (for tests F & G):
630 // -- max Sigma error over 3D domain of ice (in 10^-3 K a^-1)
631 // -- av Sigma error over 3D domain of ice (in 10^-3 K a^-1)
632 // and basal melt rate error (for test O):
633 // -- max bmelt error over base of ice
634 // and surface velocity errors (for tests F & G):
635 // -- max |<us,vs> - <usex,vsex>| error
636 // -- av |<us,vs> - <usex,vsex>| error
637 // -- max ws error
638 // -- av ws error
639 // and basal sliding errors (for test E):
640 // -- max ub error
641 // -- max vb error
642 // -- max |<ub,vb> - <ubexact,vbexact>| error
643 // -- av |<ub,vb> - <ubexact,vbexact>| error
644
645 bool no_report = options::Bool("-no_report", "Don't report numerical errors");
646
647 if (no_report) {
648 return;
649 }
650
651 double maxbmelterr, minbmelterr, volexact, areaexact, domeHexact,
652 volerr, areaerr, maxHerr, avHerr, maxetaerr, centerHerr;
653 double maxTerr, avTerr, basemaxTerr, baseavTerr, basecenterTerr, maxTberr, avTberr;
654 double max_strain_heating_error, av_strain_heating_error;
655 double maxUerr, avUerr, maxWerr, avWerr;
656
657 const rheology::FlowLaw &flow_law = *m_stress_balance->modifier()->flow_law();
658 const double m = (2.0 * flow_law.exponent() + 2.0) / flow_law.exponent();
659
660 EnthalpyConverter::Ptr EC = m_ctx->enthalpy_converter();
661
662 if ((m_testname == 'F' or m_testname == 'G') and m_testname != 'V' and
663 not FlowLawIsPatersonBuddCold(flow_law, *m_config, EC)) {
664 m_log->message(1,
665 "WARNING: flow law must be cold part of Paterson-Budd ('-siafd_flow_law arr')\n"
666 " for reported errors in test %c to be meaningful!\n",
667 m_testname);
668 }
669
670 m_log->message(1,
671 "NUMERICAL ERRORS evaluated at final time (relative to exact solution):\n");
672
673
674 // geometry (thickness, vol) errors if appropriate; reported in m except for relmaxETA
675 if ((m_testname != 'K') && (m_testname != 'O')) {
676 computeGeometryErrors(volexact,areaexact,domeHexact,
677 volerr,areaerr,maxHerr,avHerr,maxetaerr,centerHerr);
678 m_log->message(1,
679 "geometry : prcntVOL maxH avH relmaxETA\n"); // no longer reporting centerHerr
680 m_log->message(1, " %12.6f%12.6f%12.6f%12.6f\n",
681 100*volerr/volexact, maxHerr, avHerr,
682 maxetaerr/pow(domeHexact,m));
683
684 }
685
686 // temperature errors for F and G
687 if ((m_testname == 'F') || (m_testname == 'G')) {
688 computeTemperatureErrors(maxTerr, avTerr);
689 computeBasalTemperatureErrors(basemaxTerr, baseavTerr, basecenterTerr);
690 m_log->message(1,
691 "temp : maxT avT basemaxT baseavT\n"); // no longer reporting basecenterT
692 m_log->message(1, " %12.6f%12.6f%12.6f%12.6f\n",
693 maxTerr, avTerr, basemaxTerr, baseavTerr);
694
695 } else if ((m_testname == 'K') || (m_testname == 'O')) {
696 computeIceBedrockTemperatureErrors(maxTerr, avTerr, maxTberr, avTberr);
697 m_log->message(1,
698 "temp : maxT avT maxTb avTb\n");
699 m_log->message(1, " %12.6f%12.6f%12.6f%12.6f\n",
700 maxTerr, avTerr, maxTberr, avTberr);
701
702 }
703
704 // strain_heating errors if appropriate; reported in 10^6 J/(s m^3)
705 if ((m_testname == 'F') || (m_testname == 'G')) {
706 compute_strain_heating_errors(max_strain_heating_error, av_strain_heating_error);
707 m_log->message(1,
708 "Sigma : maxSig avSig\n");
709 m_log->message(1, " %12.6f%12.6f\n",
710 max_strain_heating_error*1.0e6, av_strain_heating_error*1.0e6);
711 }
712
713 // surface velocity errors if exact values are available; reported in m year-1
714 if ((m_testname == 'F') || (m_testname == 'G')) {
715 computeSurfaceVelocityErrors(maxUerr, avUerr, maxWerr, avWerr);
716 m_log->message(1,
717 "surf vels : maxUvec avUvec maxW avW\n");
718 m_log->message(1,
719 " %12.6f%12.6f%12.6f%12.6f\n",
720 convert(m_sys, maxUerr, "m second-1", "m year-1"),
721 convert(m_sys, avUerr, "m second-1", "m year-1"),
722 convert(m_sys, maxWerr, "m second-1", "m year-1"),
723 convert(m_sys, avWerr, "m second-1", "m year-1"));
724 }
725
726 // basal melt rate errors if appropriate; reported in m year-1
727 if (m_testname == 'O') {
728 computeBasalMeltRateErrors(maxbmelterr, minbmelterr);
729 if (maxbmelterr != minbmelterr) {
730 m_log->message(1,
731 "IceCompModel WARNING: unexpected Test O situation: max and min of bmelt error\n"
732 " are different: maxbmelterr = %f, minbmelterr = %f\n",
733 convert(m_sys, maxbmelterr, "m second-1", "m year-1"),
734 convert(m_sys, minbmelterr, "m second-1", "m year-1"));
735 }
736 m_log->message(1,
737 "basal melt: max\n");
738 m_log->message(1, " %11.5f\n",
739 convert(m_sys, maxbmelterr, "m second-1", "m year-1"));
740
741 }
742
743 m_log->message(1, "NUM ERRORS DONE\n");
744
745 options::String report_file("-report_file", "NetCDF error report file");
746 bool append = options::Bool("-append", "Append the NetCDF error report");
747
749
750 if (report_file.is_set()) {
751
752 m_log->message(2, "Also writing errors to '%s'...\n", report_file->c_str());
753
754 // Find the number of records in this file:
755 File file(m_grid->com, report_file, io::PISM_NETCDF3, mode); // OK to use netcdf3
756
757 size_t start = file.dimension_length("N");
758
760
761 // Write the dimension variable:
762 write(m_sys, file, start, "N", "1", "run number", start + 1);
763
764 // Always write grid parameters:
765 write(m_sys, file, start, "dx", "meter", "grid spacing", m_grid->dx());
766 write(m_sys, file, start, "dy", "meter", "grid spacing", m_grid->dy());
767 write(m_sys, file, start, "dz", "meter", "grid spacing", m_grid->dz_max());
768
769 // Always write the test name:
770 write(m_sys, file, start, "test", "", "test name", m_testname);
771
772 if ((m_testname != 'K') && (m_testname != 'O')) {
773 write(m_sys, file, start, "relative_volume", "1", "relative volume error", 100*volerr/volexact);
774 write(m_sys, file, start, "relative_max_eta", "1", "relative $\\eta$ error", maxetaerr/pow(domeHexact,m));
775 write(m_sys, file, start, "maximum_thickness", "meters", "maximum ice thickness error", maxHerr);
776 write(m_sys, file, start, "average_thickness", "meters", "average ice thickness error", avHerr);
777 }
778
779 if ((m_testname == 'F') || (m_testname == 'G')) {
780 write(m_sys, file, start, "maximum_temperature", "kelvin", "maximum ice temperature error", maxTerr);
781 write(m_sys, file, start, "average_temperature", "kelvin", "average ice temperature error", avTerr);
782 write(m_sys, file, start, "maximum_basal_temperature", "kelvin", "maximum basal temperature error", basemaxTerr);
783 write(m_sys, file, start, "average_basal_temperature", "kelvin", "average basal temperature error", baseavTerr);
784
785 {
786 units::Converter c(m_sys, "J s^-1 m^-3", "1e6 J s^-1 m^-3");
787 write(m_sys, file, start, "maximum_sigma", "1e6 J s-1 m-3", "maximum strain heating error", c(max_strain_heating_error));
788 write(m_sys, file, start, "average_sigma", "1e6 J s-1 m-3", "average strain heating error", c(av_strain_heating_error));
789 }
790
791 {
792 units::Converter c(m_sys, "m second^-1", "m year^-1");
793 write(m_sys, file, start, "maximum_surface_velocity", "m year-1", "maximum ice surface horizontal velocity error", c(maxUerr));
794 write(m_sys, file, start, "average_surface_velocity", "m year-1", "average ice surface horizontal velocity error", c(avUerr));
795 write(m_sys, file, start, "maximum_surface_w", "m year-1", "maximum ice surface vertical velocity error", c(maxWerr));
796 write(m_sys, file, start, "average_surface_w", "m year-1", "average ice surface vertical velocity error", c(avWerr));
797 }
798 }
799
800 if ((m_testname == 'K') || (m_testname == 'O')) {
801 write(m_sys, file, start, "maximum_temperature", "kelvin", "maximum ice temperature error", maxTerr);
802 write(m_sys, file, start, "average_temperature", "kelvin", "average ice temperature error", avTerr);
803 write(m_sys, file, start, "maximum_bedrock_temperature", "kelvin", "maximum bedrock temperature error", maxTberr);
804 write(m_sys, file, start, "average_bedrock_temperature", "kelvin", "average bedrock temperature error", avTberr);
805 }
806
807 if (m_testname == 'O') {
808 units::Converter c(m_sys, "m second^-1", "m year^-1");
809 write(m_sys, file, start, "maximum_basal_melt_rate", "m year -1", "maximum basal melt rate error", c(maxbmelterr));
810 }
811 }
812
813}
814
815//! \brief Initialize test V.
816/*
817 Try
818
819 pism -test V -y 1000 -part_grid -ssa_method fd -cfbc -o fig4-blue.nc
820 pism -test V -y 1000 -part_grid -ssa_method fd -o fig4-green.nc
821
822 to try to reproduce Figure 4.
823
824 Try
825
826 pism -test V -y 3000 -ssa_method fd -cfbc -o fig5.nc -thickness_calving_threshold 250 -part_grid
827
828 with -Mx 51, -Mx 101, -Mx 201 for figure 5,
829
830 pism -test V -y 300 -ssa_method fd -o fig6-ab.nc
831
832 for 6a and 6b,
833
834 pism -test V -y 300 -ssa_method fd -cfbc -part_grid -o fig6-cd.nc
835
836 for 6c and 6d,
837
838 pism -test V -y 300 -ssa_method fd -cfbc -part_grid -o fig6-ef.nc
839
840 for 6e and 6f.
841
842 */
844
845 {
846 array::Scalar bed_uplift(m_grid, "uplift");
847 bed_uplift.set(0.0);
849
852 }
853
854 // set SSA boundary conditions:
855 double upstream_velocity = convert(m_sys, 300.0, "m year-1", "m second-1"),
856 upstream_thk = 600.0;
857
861
862 for (auto p = m_grid->points(); p; p.next()) {
863 const int i = p.i(), j = p.j();
864
865 if (i <= 2) {
866 m_velocity_bc_mask(i,j) = 1;
867 m_velocity_bc_values(i,j) = {upstream_velocity, 0.0};
868 m_geometry.ice_thickness(i, j) = upstream_thk;
869 m_ice_thickness_bc_mask(i, j) = 1;
870 } else {
871 m_velocity_bc_mask(i,j) = 0;
872 m_velocity_bc_values(i,j) = {0.0, 0.0};
873 m_geometry.ice_thickness(i, j) = 0;
874 m_ice_thickness_bc_mask(i, j) = 0;
875 }
876 }
877
879
881
883}
884
885} // end of namespace pism
std::shared_ptr< EnthalpyConverter > Ptr
unsigned int dimension_length(const std::string &name) const
Get the length of a dimension.
Definition File.cc:420
High-level PISM I/O class.
Definition File.hh:55
array::Scalar1 sea_level_elevation
Definition Geometry.hh:48
array::CellType2 cell_type
Definition Geometry.hh:55
array::Scalar2 ice_thickness
Definition Geometry.hh:51
array::Scalar2 bed_elevation
Definition Geometry.hh:47
virtual void allocate_bed_deformation()
void compute_strain_heating_errors(double &gmax_strain_heating_err, double &gav_strain_heating_err)
Definition iCMthermo.cc:381
virtual void post_step_hook()
Virtual. Does nothing in IceModel. Derived classes can do more computation in each time step.
void reset_thickness_test_A()
Tests A and E have a thickness B.C. (ice_thickness == 0 outside a circle of radius 750km).
void bootstrap_2d(const File &input_file) __attribute__((noreturn))
virtual void allocate_couplers()
virtual void allocate_bedrock_thermal_unit()
Decide which bedrock thermal unit to use.
array::Array3D m_strain_heating3_comp
void test_V_init()
Initialize test V.
virtual void initialize_2d()
void computeSurfaceVelocityErrors(double &gmaxUerr, double &gavUerr, double &gmaxWerr, double &gavWerr)
Definition iCMthermo.cc:438
array::Scalar m_HexactL
virtual void allocate_energy_model()
void computeIceBedrockTemperatureErrors(double &gmaxTerr, double &gavTerr, double &gmaxTberr, double &gavTberr)
Definition iCMthermo.cc:236
virtual void allocate_storage()
Allocate all Arrays defined in IceModel.
void computeTemperatureErrors(double &gmaxTerr, double &gavTerr)
Definition iCMthermo.cc:185
void computeGeometryErrors(double &gvolexact, double &gareaexact, double &gdomeHexact, double &volerr, double &areaerr, double &gmaxHerr, double &gavHerr, double &gmaxetaerr, double &centerHerr)
static const double m_LforFG
virtual void print_summary(bool tempAndAge)
IceCompModel(std::shared_ptr< Grid > g, std::shared_ptr< Context > ctx, int mytest)
void computeBasalMeltRateErrors(double &gmaxbmelterr, double &gminbmelterr)
Definition iCMthermo.cc:504
static const double m_ApforG
void computeBasalTemperatureErrors(double &gmaxTerr, double &gavTerr, double &centerTerr)
Definition iCMthermo.cc:319
std::map< std::string, const Component * > m_submodels
the list of sub-models, for writing model states and obtaining diagnostics
Definition IceModel.hh:252
virtual void allocate_bed_deformation()
std::shared_ptr< stressbalance::StressBalance > m_stress_balance
Definition IceModel.hh:395
std::shared_ptr< ocean::OceanModel > m_ocean
Definition IceModel.hh:280
std::shared_ptr< surface::SurfaceModel > m_surface
Definition IceModel.hh:279
const Time::Ptr m_time
Time manager.
Definition IceModel.hh:246
Geometry m_geometry
Definition IceModel.hh:288
std::shared_ptr< Context > m_ctx
Execution context.
Definition IceModel.hh:240
const Logger::Ptr m_log
Logger.
Definition IceModel.hh:244
virtual void print_summary(bool tempAndAge)
Definition printout.cc:89
VariableMetadata m_output_global_attributes
stores global attributes saved in a PISM output file
Definition IceModel.hh:249
virtual void allocate_storage()
Allocate all Arrays defined in IceModel.
Definition IceModel.cc:171
array::Scalar2 m_velocity_bc_mask
mask to determine Dirichlet boundary locations for the sliding velocity
Definition IceModel.hh:302
Config::Ptr m_config
Configuration flags and parameters.
Definition IceModel.hh:238
std::shared_ptr< energy::BedThermalUnit > m_btu
Definition IceModel.hh:259
array::Scalar1 m_ice_thickness_bc_mask
Mask prescribing locations where ice thickness is held constant.
Definition IceModel.hh:307
const units::System::Ptr m_sys
Unit system.
Definition IceModel.hh:242
array::Vector2 m_velocity_bc_values
Dirichlet boundary velocities.
Definition IceModel.hh:304
std::shared_ptr< ocean::sea_level::SeaLevel > m_sea_level
Definition IceModel.hh:282
std::shared_ptr< energy::EnergyModel > m_energy_model
Definition IceModel.hh:260
const std::shared_ptr< Grid > m_grid
Computational grid.
Definition IceModel.hh:236
std::shared_ptr< bed::BedDef > m_beddef
Definition IceModel.hh:284
void failed()
Indicates a failure of a parallel section.
VariableMetadata & long_name(const std::string &input)
VariableMetadata & units(const std::string &input)
void add(const PetscAccessible &v)
Definition Array.cc:896
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition Array.hh:64
void copy_from(const Array2D< T > &source)
Definition Array2D.hh:73
void scale(double alpha)
Result: v <- v * alpha. Calls VecScale.
Definition Array.cc:224
void set(double c)
Result: v[j] <- c for all j.
Definition Array.cc:629
void update_ghosts()
Updates ghost points.
Definition Array.cc:615
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
Definition Array.cc:476
A class implementing a constant (in terms of the ocean inputs) ocean model. Uses configuration parame...
Definition Constant.hh:29
bool is_set() const
Definition options.hh:35
Class used initTestL() in generating sorted list for ODE solver.
double exponent() const
Definition FlowLaw.cc:74
Climate inputs for verification tests.
std::shared_ptr< System > Ptr
Definition Units.hh:47
#define PISM_ERROR_LOCATION
struct TestHParameters exactH(const double f, const double t, const double r)
Definition exactTestH.c:76
const double B0
Definition exactTestK.c:38
static const double L
Definition exactTestL.cc:40
ExactLParameters exactL(const std::vector< double > &r)
#define H0
Definition exactTestM.c:39
struct TestABCDParameters exactB(const double t, const double r)
struct TestABCDParameters exactD(const double t, const double r)
struct TestABCDParameters exactA(double r)
struct TestABCDParameters exactC(const double t, const double r)
double radius(const Grid &grid, int i, int j)
Returns the distance from the point (i,j) to the origin.
Definition Grid.cc:1377
@ PISM_NETCDF3
Definition IO_Flags.hh:57
@ PISM_READWRITE_MOVE
create a file for writing, move foo.nc to foo.nc~ if present
Definition IO_Flags.hh:74
@ PISM_READWRITE
open an existing file for reading and writing
Definition IO_Flags.hh:70
void write_attributes(const File &file, const VariableMetadata &variable, io::Type nctype)
Write variable attributes to a NetCDF file.
@ PISM_DOUBLE
Definition IO_Flags.hh:52
void write_timeseries(const File &file, const VariableMetadata &metadata, size_t t_start, const std::vector< double > &data)
Write a time-series data to a file.
void define_timeseries(const VariableMetadata &var, const std::string &dimension_name, const File &file, io::Type nctype)
Define a NetCDF variable corresponding to a time-series.
bool Bool(const std::string &option, const std::string &description)
Definition options.cc:190
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
static void write(units::System::Ptr sys, const File &file, size_t start, const char *name, const char *units, const char *long_name, double value, io::Type type=io::PISM_DOUBLE)
void GlobalMax(MPI_Comm comm, double *local, double *result, int count)
static const double v0
Definition exactTestP.cc:50
static const double k
Definition exactTestP.cc:42
TestFGParameters exactFG(double t, double r, const std::vector< double > &z, double Cp)
@ MASK_GROUNDED
Definition Mask.hh:33
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)
static BTUGrid FromOptions(std::shared_ptr< const Context > ctx)
bool operator()(rgrid a, rgrid b)
Comparison used initTestL() in generating sorted list for ODE solver.