PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
iceCompModel.cc
Go to the documentation of this file.
1// Copyright (C) 2004-2025 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/Config.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/pism_options.hh"
53#include "pism/util/pism_utilities.hh"
54#include "pism/util/io/IO_Flags.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 auto 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()) {
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()) {
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()) {
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()) {
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 */, double dt) {
598 // we always show a summary at every step
600}
601
602static void write(const File &file, unsigned int start, const char *name, const char *units,
603 const char *long_name, double value) {
604
606
607 file.define_variable(name, io::PISM_DOUBLE, { "N" });
608 file.write_attribute(name, "units", units);
609 file.write_attribute(name, "long_name", long_name);
610
611 file.write_variable(name, { start }, { 1 }, &value);
612}
613
615 // geometry errors to report (for all tests except K and O):
616 // -- max thickness error
617 // -- average (at each grid point on whole grid) thickness error
618 // -- max (thickness)^(2n+2)/n error
619 // -- volume error
620 // -- area error
621 // and temperature errors (for tests F & G & K & O):
622 // -- max T error over 3D domain of ice
623 // -- av T error over 3D domain of ice
624 // and basal temperature errors (for tests F & G):
625 // -- max basal temp error
626 // -- average (at each grid point on whole grid) basal temp error
627 // and bedrock temperature errors (for tests K & O):
628 // -- max Tb error over 3D domain of bedrock
629 // -- av Tb error over 3D domain of bedrock
630 // and strain-heating (Sigma) errors (for tests F & G):
631 // -- max Sigma error over 3D domain of ice (in 10^-3 K a^-1)
632 // -- av Sigma error over 3D domain of ice (in 10^-3 K a^-1)
633 // and basal melt rate error (for test O):
634 // -- max bmelt error over base of ice
635 // and surface velocity errors (for tests F & G):
636 // -- max |<us,vs> - <usex,vsex>| error
637 // -- av |<us,vs> - <usex,vsex>| error
638 // -- max ws error
639 // -- av ws error
640 // and basal sliding errors (for test E):
641 // -- max ub error
642 // -- max vb error
643 // -- max |<ub,vb> - <ubexact,vbexact>| error
644 // -- av |<ub,vb> - <ubexact,vbexact>| error
645
646 bool no_report = options::Bool("-no_report", "Don't report numerical errors");
647
648 if (no_report) {
649 return;
650 }
651
652 double maxbmelterr = 0.0, minbmelterr = 0.0, volexact = 0.0, areaexact = 0.0, domeHexact = 0.0,
653 volerr = 0.0, areaerr = 0.0, maxHerr = 0.0, avHerr = 0.0, maxetaerr = 0.0,
654 centerHerr = 0.0;
655 double maxTerr = 0.0, avTerr = 0.0, basemaxTerr = 0.0, baseavTerr = 0.0, basecenterTerr = 0.0,
656 maxTberr = 0.0, avTberr = 0.0;
657 double max_strain_heating_error = 0.0, av_strain_heating_error = 0.0;
658 double maxUerr = 0.0, avUerr = 0.0, maxWerr = 0.0, avWerr = 0.0;
659
660 const rheology::FlowLaw &flow_law = *m_stress_balance->modifier()->flow_law();
661 const double m = (2.0 * flow_law.exponent() + 2.0) / flow_law.exponent();
662
663 auto EC = m_ctx->enthalpy_converter();
664
665 if ((m_testname == 'F' or m_testname == 'G') and m_testname != 'V' and
666 not FlowLawIsPatersonBuddCold(flow_law, *m_config, EC)) {
667 m_log->message(1,
668 "WARNING: flow law must be cold part of Paterson-Budd ('-siafd_flow_law arr')\n"
669 " for reported errors in test %c to be meaningful!\n",
670 m_testname);
671 }
672
673 m_log->message(1,
674 "NUMERICAL ERRORS evaluated at final time (relative to exact solution):\n");
675
676
677 // geometry (thickness, vol) errors if appropriate; reported in m except for relmaxETA
678 if ((m_testname != 'K') && (m_testname != 'O')) {
679 computeGeometryErrors(volexact,areaexact,domeHexact,
680 volerr,areaerr,maxHerr,avHerr,maxetaerr,centerHerr);
681 m_log->message(1,
682 "geometry : prcntVOL maxH avH relmaxETA\n"); // no longer reporting centerHerr
683 m_log->message(1, " %12.6f%12.6f%12.6f%12.6f\n",
684 100*volerr/volexact, maxHerr, avHerr,
685 maxetaerr/pow(domeHexact,m));
686
687 }
688
689 // temperature errors for F and G
690 if ((m_testname == 'F') || (m_testname == 'G')) {
691 computeTemperatureErrors(maxTerr, avTerr);
692 computeBasalTemperatureErrors(basemaxTerr, baseavTerr, basecenterTerr);
693 m_log->message(1,
694 "temp : maxT avT basemaxT baseavT\n"); // no longer reporting basecenterT
695 m_log->message(1, " %12.6f%12.6f%12.6f%12.6f\n",
696 maxTerr, avTerr, basemaxTerr, baseavTerr);
697
698 } else if ((m_testname == 'K') || (m_testname == 'O')) {
699 computeIceBedrockTemperatureErrors(maxTerr, avTerr, maxTberr, avTberr);
700 m_log->message(1,
701 "temp : maxT avT maxTb avTb\n");
702 m_log->message(1, " %12.6f%12.6f%12.6f%12.6f\n",
703 maxTerr, avTerr, maxTberr, avTberr);
704
705 }
706
707 // strain_heating errors if appropriate; reported in 10^6 J/(s m^3)
708 if ((m_testname == 'F') || (m_testname == 'G')) {
709 compute_strain_heating_errors(max_strain_heating_error, av_strain_heating_error);
710 m_log->message(1,
711 "Sigma : maxSig avSig\n");
712 m_log->message(1, " %12.6f%12.6f\n",
713 max_strain_heating_error*1.0e6, av_strain_heating_error*1.0e6);
714 }
715
716 // surface velocity errors if exact values are available; reported in m year-1
717 if ((m_testname == 'F') || (m_testname == 'G')) {
718 computeSurfaceVelocityErrors(maxUerr, avUerr, maxWerr, avWerr);
719 m_log->message(1,
720 "surf vels : maxUvec avUvec maxW avW\n");
721 m_log->message(1,
722 " %12.6f%12.6f%12.6f%12.6f\n",
723 convert(m_sys, maxUerr, "m second-1", "m year-1"),
724 convert(m_sys, avUerr, "m second-1", "m year-1"),
725 convert(m_sys, maxWerr, "m second-1", "m year-1"),
726 convert(m_sys, avWerr, "m second-1", "m year-1"));
727 }
728
729 // basal melt rate errors if appropriate; reported in m year-1
730 if (m_testname == 'O') {
731 computeBasalMeltRateErrors(maxbmelterr, minbmelterr);
732 if (maxbmelterr != minbmelterr) {
733 m_log->message(1,
734 "IceCompModel WARNING: unexpected Test O situation: max and min of bmelt error\n"
735 " are different: maxbmelterr = %f, minbmelterr = %f\n",
736 convert(m_sys, maxbmelterr, "m second-1", "m year-1"),
737 convert(m_sys, minbmelterr, "m second-1", "m year-1"));
738 }
739 m_log->message(1,
740 "basal melt: max\n");
741 m_log->message(1, " %11.5f\n",
742 convert(m_sys, maxbmelterr, "m second-1", "m year-1"));
743
744 }
745
746 m_log->message(1, "NUM ERRORS DONE\n");
747
748 options::String report_file("-report_file", "NetCDF error report file");
749 bool append = options::Bool("-append", "Append the NetCDF error report");
750
752
753 if (report_file.is_set()) {
754
755 m_log->message(2, "Also writing errors to '%s'...\n", report_file->c_str());
756
757 // Find the number of records in this file:
758 File file(m_grid->com, report_file, io::PISM_NETCDF3, mode); // OK to use netcdf3
759
760 size_t start = file.dimension_length("N");
761
762 for (const auto& arg : m_output_global_attributes.all_strings()) {
763 file.write_attribute("PISM_GLOBAL", arg.first, arg.second);
764 }
765
766 // Write the dimension variable:
767 write(file, start, "N", "1", "run number", start + 1);
768
769 // Always write grid parameters:
770 write(file, start, "dx", "meter", "grid spacing", m_grid->dx());
771 write(file, start, "dy", "meter", "grid spacing", m_grid->dy());
772 write(file, start, "dz", "meter", "grid spacing", m_grid->dz_max());
773
774 // Always write the test name:
775 write(file, start, "test", "", "test name", m_testname);
776
777 if ((m_testname != 'K') && (m_testname != 'O')) {
778 write(file, start, "relative_volume", "1", "relative volume error", 100*volerr/volexact);
779 write(file, start, "relative_max_eta", "1", "relative $\\eta$ error", maxetaerr/pow(domeHexact,m));
780 write(file, start, "maximum_thickness", "meters", "maximum ice thickness error", maxHerr);
781 write(file, start, "average_thickness", "meters", "average ice thickness error", avHerr);
782 }
783
784 if ((m_testname == 'F') || (m_testname == 'G')) {
785 write(file, start, "maximum_temperature", "kelvin", "maximum ice temperature error", maxTerr);
786 write(file, start, "average_temperature", "kelvin", "average ice temperature error", avTerr);
787 write(file, start, "maximum_basal_temperature", "kelvin", "maximum basal temperature error", basemaxTerr);
788 write(file, start, "average_basal_temperature", "kelvin", "average basal temperature error", baseavTerr);
789
790 {
791 units::Converter c(m_sys, "J s^-1 m^-3", "1e6 J s^-1 m^-3");
792 write(file, start, "maximum_sigma", "1e6 J s-1 m-3", "maximum strain heating error", c(max_strain_heating_error));
793 write(file, start, "average_sigma", "1e6 J s-1 m-3", "average strain heating error", c(av_strain_heating_error));
794 }
795
796 {
797 units::Converter c(m_sys, "m second^-1", "m year^-1");
798 write(file, start, "maximum_surface_velocity", "m year-1", "maximum ice surface horizontal velocity error", c(maxUerr));
799 write(file, start, "average_surface_velocity", "m year-1", "average ice surface horizontal velocity error", c(avUerr));
800 write(file, start, "maximum_surface_w", "m year-1", "maximum ice surface vertical velocity error", c(maxWerr));
801 write(file, start, "average_surface_w", "m year-1", "average ice surface vertical velocity error", c(avWerr));
802 }
803 }
804
805 if ((m_testname == 'K') || (m_testname == 'O')) {
806 write(file, start, "maximum_temperature", "kelvin", "maximum ice temperature error", maxTerr);
807 write(file, start, "average_temperature", "kelvin", "average ice temperature error", avTerr);
808 write(file, start, "maximum_bedrock_temperature", "kelvin", "maximum bedrock temperature error", maxTberr);
809 write(file, start, "average_bedrock_temperature", "kelvin", "average bedrock temperature error", avTberr);
810 }
811
812 if (m_testname == 'O') {
813 units::Converter c(m_sys, "m second^-1", "m year^-1");
814 write(file, start, "maximum_basal_melt_rate", "m year -1", "maximum basal melt rate error", c(maxbmelterr));
815 }
816 }
817
818}
819
820//! \brief Initialize test V.
821/*
822 Try
823
824 pism -test V -y 1000 -part_grid -ssa_method fd -cfbc -o fig4-blue.nc
825 pism -test V -y 1000 -part_grid -ssa_method fd -o fig4-green.nc
826
827 to try to reproduce Figure 4.
828
829 Try
830
831 pism -test V -y 3000 -ssa_method fd -cfbc -o fig5.nc -thickness_calving_threshold 250 -part_grid
832
833 with -Mx 51, -Mx 101, -Mx 201 for figure 5,
834
835 pism -test V -y 300 -ssa_method fd -o fig6-ab.nc
836
837 for 6a and 6b,
838
839 pism -test V -y 300 -ssa_method fd -cfbc -part_grid -o fig6-cd.nc
840
841 for 6c and 6d,
842
843 pism -test V -y 300 -ssa_method fd -cfbc -part_grid -o fig6-ef.nc
844
845 for 6e and 6f.
846
847 */
849
850 {
851 array::Scalar bed_uplift(m_grid, "uplift");
852 bed_uplift.set(0.0);
854
857 }
858
859 // set SSA boundary conditions:
860 double upstream_velocity = convert(m_sys, 300.0, "m year-1", "m second-1"),
861 upstream_thk = 600.0;
862
866
867 for (auto p : m_grid->points()) {
868 const int i = p.i(), j = p.j();
869
870 if (i <= 2) {
871 m_velocity_bc_mask(i,j) = 1;
872 m_velocity_bc_values(i,j) = {upstream_velocity, 0.0};
873 m_geometry.ice_thickness(i, j) = upstream_thk;
874 m_ice_thickness_bc_mask(i, j) = 1;
875 } else {
876 m_velocity_bc_mask(i,j) = 0;
877 m_velocity_bc_values(i,j) = {0.0, 0.0};
878 m_geometry.ice_thickness(i, j) = 0;
879 m_ice_thickness_bc_mask(i, j) = 0;
880 }
881 }
882
884
886
888}
889
890} // end of namespace pism
void define_dimension(const std::string &name, size_t length) const
Definition File.cc:537
void write_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, const double *op) const
Definition File.cc:717
void define_variable(const std::string &name, io::Type nctype, const std::vector< std::string > &dims) const
Define a variable.
Definition File.cc:548
void write_attribute(const std::string &var_name, const std::string &att_name, io::Type nctype, const std::vector< double > &values) const
Write a multiple-valued double attribute.
Definition File.cc:595
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:57
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.
virtual void print_summary(bool tempAndAge, double dt)
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
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:297
virtual void allocate_bed_deformation()
std::shared_ptr< stressbalance::StressBalance > m_stress_balance
Definition IceModel.hh:439
std::shared_ptr< ocean::OceanModel > m_ocean
Definition IceModel.hh:325
std::shared_ptr< surface::SurfaceModel > m_surface
Definition IceModel.hh:324
std::shared_ptr< Config > m_config
Configuration flags and parameters.
Definition IceModel.hh:278
Geometry m_geometry
Definition IceModel.hh:333
std::shared_ptr< Context > m_ctx
Execution context.
Definition IceModel.hh:280
std::shared_ptr< Logger > m_log
Logger.
Definition IceModel.hh:284
VariableMetadata m_output_global_attributes
stores global attributes saved in a PISM output file
Definition IceModel.hh:293
std::shared_ptr< Time > m_time
Time manager.
Definition IceModel.hh:286
double dt() const
Definition IceModel.cc:151
virtual void allocate_storage()
Allocate all Arrays defined in IceModel.
Definition IceModel.cc:196
array::Scalar2 m_velocity_bc_mask
mask to determine Dirichlet boundary locations for the sliding velocity
Definition IceModel.hh:347
std::shared_ptr< energy::BedThermalUnit > m_btu
Definition IceModel.hh:304
array::Scalar1 m_ice_thickness_bc_mask
Mask prescribing locations where ice thickness is held constant.
Definition IceModel.hh:352
const units::System::Ptr m_sys
Unit system.
Definition IceModel.hh:282
array::Vector2 m_velocity_bc_values
Dirichlet boundary velocities.
Definition IceModel.hh:349
std::shared_ptr< ocean::sea_level::SeaLevel > m_sea_level
Definition IceModel.hh:327
virtual void print_summary(bool tempAndAge, double dt)
Definition printout.cc:89
std::shared_ptr< energy::EnergyModel > m_energy_model
Definition IceModel.hh:305
const std::shared_ptr< Grid > m_grid
Computational grid.
Definition IceModel.hh:276
std::shared_ptr< bed::BedDef > m_beddef
Definition IceModel.hh:329
void failed()
Indicates a failure of a parallel section.
VariableMetadata & long_name(const std::string &input)
VariableMetadata & units(const std::string &input)
const std::map< std::string, std::string > & all_strings() const
void add(const PetscAccessible &v)
Definition Array.cc:917
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition Array.hh:66
void copy_from(const Array2D< T > &source)
Definition Array2D.hh:101
void scale(double alpha)
Result: v <- v * alpha. Calls VecScale.
Definition Array.cc:227
void set(double c)
Result: v[j] <- c for all j.
Definition Array.cc:659
void update_ghosts()
Updates ghost points.
Definition Array.cc:645
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
Definition Array.cc:467
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:76
Climate inputs for verification tests.
#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:1367
@ PISM_NETCDF3
Definition IO_Flags.hh:58
@ PISM_READWRITE_MOVE
create a file for writing, move foo.nc to foo.nc~ if present
Definition IO_Flags.hh:75
@ PISM_READWRITE
open an existing file for reading and writing
Definition IO_Flags.hh:71
@ PISM_UNLIMITED
Definition IO_Flags.hh:80
@ PISM_DOUBLE
Definition IO_Flags.hh:53
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
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
static void write(const File &file, unsigned int start, const char *name, const char *units, const char *long_name, double value)
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.