PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
btutest.cc
Go to the documentation of this file.
1// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025 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 <memory>
20#include <petsc.h>
21
22static char help[] =
23 "Tests BedThermalUnit using Test K, without IceModel.\n\n";
24
25#include "pism/util/pism_options.hh"
26#include "pism/util/Grid.hh"
27#include "pism/verification/BTU_Verification.hh"
28#include "pism/energy/BTU_Minimal.hh"
29#include "pism/util/Time.hh"
30#include "pism/util/Config.hh"
31
32#include "pism/verification/tests/exactTestK.h"
33
34#include "pism/util/petscwrappers/PetscInitializer.hh"
35#include "pism/util/error_handling.hh"
36#include "pism/util/Context.hh"
37#include "pism/util/EnthalpyConverter.hh"
38#include "pism/util/MaxTimestep.hh"
39#include "pism/util/Logger.hh"
40#include "pism/util/io/SynchronousOutputWriter.hh"
41#include "pism/util/io/io_helpers.hh"
42
43//! Allocate the verification context. Uses ColdEnthalpyConverter.
44std::shared_ptr<pism::Context> btutest_context(MPI_Comm com, const std::string &prefix) {
45 using namespace pism;
46
47 // unit system
49
50 // logger
51 auto logger = std::make_shared<Logger>(com, 1);
52
53 auto config = config_from_options(com, sys);
54
55 logger->set_threshold(static_cast<int>(config->get_number("output.runtime.verbosity")));
56
57 int Mx = 3;
58 double Lx = 1500;
59 // default horizontal grid parameters
60 config->set_number("grid.Mx", Mx);
61 config->set_number("grid.My", Mx);
62 config->set_number("grid.Lx", Lx); // in km
63 config->set_number("grid.Ly", Lx); // in km
64
65 // default vertical grid parameters
66 config->set_number("grid.Mbz", 11);
67 config->set_number("grid.Lbz", 1000); // in m
68
69 // when Grid constructor is called, these settings are used
70 config->set_string("time.start", "0s");
71 config->set_number("time.run_length", 1.0);
72
73 set_config_from_options(*config);
74 config->resolve_filenames();
75
76 print_config(*logger, 3, *config);
77
78 auto time = std::make_shared<Time>(com, config, *logger, sys);
79
80 std::shared_ptr<EnthalpyConverter> EC(new ColdEnthalpyConverter(*config));
81
82 return std::shared_ptr<Context>(new Context(com, sys, config, EC, time, logger, prefix));
83}
84
85int main(int argc, char *argv[]) {
86
87 using namespace pism;
88
89 MPI_Comm com = MPI_COMM_WORLD;
90 petsc::Initializer petsc(argc, argv, help);
91
92 com = MPI_COMM_WORLD;
93
94 try {
95 std::shared_ptr<Context> ctx = btutest_context(com, "pism_btutest");
96 auto log = ctx->log();
97
98 std::string usage =
99 " pism_btutest -Mbz NN -Lbz 1000.0 [-o OUT.nc -ys A -ye B -dt C -Mz D -Lz E]\n"
100 "where these are required because they are used in BedThermalUnit:\n"
101 " -Mbz number of bedrock thermal layer levels to use\n"
102 " -Lbz 1000.0 depth of bedrock thermal layer (required; Lbz=1000.0 m in Test K)\n"
103 "and these are allowed:\n"
104 " -o output file name; NetCDF format\n"
105 " -ys start year in using Test K\n"
106 " -ye end year in using Test K\n"
107 " -dt time step B (= positive float) in years\n";
108
109 bool done = maybe_show_usage(*log, "BTUTEST %s (test program for BedThermalUnit)", usage);
110 if (done) {
111 return 0;
112 }
113
114 log->message(2,
115 " initializing Grid from options ...\n");
116
117 auto config = ctx->config();
118
119 grid::Parameters P(*config);
120
122 P.ownership_ranges_from_options(*ctx->config(), ctx->size());
123
124 // create grid and set defaults
125 std::shared_ptr<Grid> grid(new Grid(ctx, P));
126
127 auto outname = config->get_string("output.file");
128
129 options::Real dt_years(ctx->unit_system(),
130 "-dt", "Time-step, in years", "years", 1.0);
131
132 // allocate tools and Arrays
133 array::Scalar bedtoptemp(grid, "bedtoptemp");
134 bedtoptemp.metadata(0).long_name("temperature at top of bedrock thermal layer").units("kelvin");
135
136 array::Scalar heat_flux_at_ice_base(grid, "upward_heat_flux_at_ice_base");
137 heat_flux_at_ice_base.metadata(0)
138 .long_name("upward geothermal flux at bedrock thermal layer base")
139 .units("W m^-2")
140 .output_units("mW m^-2");
141
142 // initialize BTU object:
143 energy::BTUGrid bedrock_grid = energy::BTUGrid::FromOptions(ctx);
144
145 std::shared_ptr<energy::BedThermalUnit> btu;
146
147 if (bedrock_grid.Mbz > 1) {
148 btu.reset(new energy::BTU_Verification(grid, bedrock_grid, 'K', false));
149 } else {
150 btu.reset(new energy::BTU_Minimal(grid));
151 }
152
153 InputOptions opts = process_input_options(com, config);
154 btu->init(opts);
155
156 double dt_seconds = units::convert(ctx->unit_system(), dt_years, "years", "seconds");
157
158 // worry about time step
159 int N = (int)ceil((ctx->time()->end() - ctx->time()->start()) / dt_seconds);
160 dt_seconds = (ctx->time()->end() - ctx->time()->start()) / (double)N;
161 log->message(2,
162 " user set timestep of %.4f years ...\n"
163 " reset to %.4f years to get integer number of steps ... \n",
164 dt_years.value(), units::convert(ctx->unit_system(), dt_seconds, "seconds", "years"));
165 MaxTimestep max_dt = btu->max_timestep(0.0);
166 log->message(2,
167 " BedThermalUnit reports max timestep of %.4f years ...\n",
168 units::convert(ctx->unit_system(), max_dt.value(), "seconds", "years"));
169
170 // actually do the time-stepping
171 log->message(2," running ...\n");
172 for (int n = 0; n < N; n++) {
173 // time at start of time-step
174 const double time = ctx->time()->start() + dt_seconds * (double)n;
175
176 // compute exact ice temperature at z=0 at time y
177 {
178 array::AccessScope list(bedtoptemp);
179 for (auto p : grid->points()) {
180 const int i = p.i(), j = p.j();
181
182 bedtoptemp(i,j) = exactK(time, 0.0, 0).T;
183 }
184 }
185 // no need to update ghost values
186
187 // update the temperature inside the thermal layer using bedtoptemp
188 btu->update(bedtoptemp, time, dt_seconds);
189 log->message(2,".");
190 }
191
192 log->message(2, "\n done ...\n");
193
194 // compute final output heat flux G_0 at z=0
195 heat_flux_at_ice_base.copy_from(btu->flux_through_top_surface());
196
197 auto time = ctx->time();
198
199 // get, and tell stdout, the correct answer from Test K
200 const double FF = exactK(time->end(), 0.0, 0).F;
201 log->message(2,
202 " exact Test K reports upward heat flux at z=0, at end time %s, as G_0 = %.7f W m-2;\n",
203 time->date(time->end()).c_str(), FF);
204
205 // compute numerical error
206 heat_flux_at_ice_base.shift(-FF);
207 double max_error = heat_flux_at_ice_base.norm(NORM_INFINITY)[0];
208 double avg_error = heat_flux_at_ice_base.norm(NORM_1)[0];
209 heat_flux_at_ice_base.shift(+FF); // shift it back for writing
210 avg_error /= (grid->Mx() * grid->My());
211 log->message(2,
212 "case dt = %.5f:\n", dt_years.value());
213 log->message(1,
214 "NUMERICAL ERRORS in upward heat flux at z=0 relative to exact solution:\n");
215 log->message(1,
216 "bheatflx0 : max prcntmax av\n");
217 log->message(1,
218 " %11.7f %11.7f %11.7f\n",
219 max_error, 100.0*max_error/FF, avg_error);
220 log->message(1, "NUM ERRORS DONE\n");
221
222 auto writer = std::make_shared<SynchronousOutputWriter>(grid->com, *config);
223 writer->initialize({}, true);
224
225 // Write results to an output file:
226 OutputFile file(writer, outname);
227
228 file.define_variable(time->metadata());
229 file.append_time(time->current());
230
231 auto variables =
232 pism::combine(btu->state(), array::metadata({ &bedtoptemp, &heat_flux_at_ice_base }));
233
234 for (const auto &v : variables) {
235 file.define_variable(v);
236 }
237
238 btu->write_state(file);
239 bedtoptemp.write(file);
240 heat_flux_at_ice_base.write(file);
241
242 log->message(2, "done.\n");
243 }
244 catch (...) {
245 handle_fatal_errors(com);
246 return 1;
247 }
248
249 return 0;
250}
int main(int argc, char *argv[])
Definition btutest.cc:85
static char help[]
Definition btutest.cc:22
std::shared_ptr< pism::Context > btutest_context(MPI_Comm com, const std::string &prefix)
Allocate the verification context. Uses ColdEnthalpyConverter.
Definition btutest.cc:44
An EnthalpyConverter for use in verification tests.
Describes the PISM grid and the distribution of data across processors.
Definition Grid.hh:285
double value() const
Get the value of the maximum time step.
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
void append_time(double time_seconds) const
Definition OutputFile.cc:41
void define_variable(const VariableMetadata &variable) const
Definition OutputFile.cc:31
VariableMetadata & long_name(const std::string &input)
VariableMetadata & units(const std::string &input)
VariableMetadata & output_units(const std::string &input)
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 write(const OutputFile &file) const
Definition Array.cc:859
void shift(double alpha)
Result: v[j] <- v[j] + alpha for all j. Calls VecShift.
Definition Array.cc:219
std::vector< double > norm(int n) const
Computes the norm of all the components of an Array.
Definition Array.cc:699
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
Definition Array.cc:467
void vertical_grid_from_options(const Config &config)
Process -Mz and -Lz; set z;.
Definition Grid.cc:1316
void ownership_ranges_from_options(const Config &config, unsigned int size)
Re-compute ownership ranges. Uses current values of Mx and My.
Definition Grid.cc:1181
Grid parameters; used to collect defaults before an Grid is allocated.
Definition Grid.hh:100
std::shared_ptr< System > Ptr
Definition Units.hh:47
struct TestKParameters exactK(double t, double z, int bedrock_is_ice)
Definition exactTestK.c:129
#define n
Definition exactTestM.c:37
T combine(const T &a, const T &b)