PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
BTU_Full.cc
Go to the documentation of this file.
1/* Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025 PISM Authors
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 "pism/energy/BTU_Full.hh"
20
21#include "pism/util/io/File.hh"
22#include "pism/util/error_handling.hh"
23#include "pism/util/MaxTimestep.hh"
24#include "pism/util/array/Array3D.hh"
25#include "pism/energy/BedrockColumn.hh"
26#include <memory>
27#include "pism/util/Logger.hh"
28#include "pism/util/io/IO_Flags.hh"
29
30namespace pism {
31namespace energy {
32
33
34BTU_Full::BTU_Full(std::shared_ptr<const Grid> g, const BTUGrid &grid)
36 m_bootstrapping_needed(false) {
37
38 m_k = m_config->get_number("energy.bedrock_thermal.conductivity");
39
40 const double
41 rho = m_config->get_number("energy.bedrock_thermal.density"),
42 c = m_config->get_number("energy.bedrock_thermal.specific_heat_capacity");
43 // build constant diffusivity for heat equation
44 m_D = m_k / (rho * c);
45
46 // validate Lbz
47 if (grid.Lbz <= 0.0) {
48 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Invalid bedrock thermal layer depth: %f m",
49 grid.Lbz);
50 }
51
52 // validate Mbz
53 if (grid.Mbz < 2) {
54 throw RuntimeError::formatted(PISM_ERROR_LOCATION, "Invalid number of layers of the bedrock thermal layer: %d",
55 grid.Mbz);
56 }
57
58 {
59 m_Mbz = grid.Mbz;
60 m_Lbz = grid.Lbz;
61
62 std::vector<double> z(m_Mbz);
63 double dz = m_Lbz / (m_Mbz - 1);
64 for (unsigned int k = 0; k < m_Mbz; ++k) {
65 z[k] = -m_Lbz + k * dz;
66 }
67 z.back() = 0.0;
68
69 m_temp = std::make_shared<array::Array3D>(m_grid, "litho_temp", array::WITHOUT_GHOSTS, z);
70 {
71 auto &z_dim = m_temp->metadata(0).dimension("z");
72
73 z_dim.set_name("zb").long_name("Z-coordinate in bedrock").units("m");
74 z_dim["axis"] = "Z";
75 z_dim["positive"] = "up";
76 }
77
78 m_temp->metadata(0)
79 .long_name("lithosphere (bedrock) temperature, in BTU_Full")
80 .units("kelvin");
81 m_temp->metadata(0)["valid_min"] = {0.0};
82 }
83
84 m_column = std::make_shared<BedrockColumn>("bedrock_column", *m_config, vertical_spacing(), Mz());
85}
86
87
88//! \brief Initialize the bedrock thermal unit.
90
91 m_log->message(2, "* Initializing the bedrock thermal unit...\n");
92
93 // 2D initialization. Takes care of the flux through the bottom surface of the thermal layer.
95
96 // Initialize the temperature field.
97 {
98 // store the current "revision number" of the temperature field
99 const int temp_revision = m_temp->state_counter();
100
101 if (opts.type == INIT_RESTART) {
102 File input_file(m_grid->com, opts.filename, io::PISM_GUESS, io::PISM_READONLY);
103
104 if (input_file.variable_exists("litho_temp")) {
105 m_temp->read(input_file, opts.record);
106 }
107 // otherwise the bedrock temperature is either interpolated from a -regrid_file or filled
108 // using bootstrapping (below)
109 }
110
111 regrid("bedrock thermal layer", *m_temp, REGRID_WITHOUT_REGRID_VARS);
112
113 if (m_temp->state_counter() == temp_revision) {
115 } else {
117 }
118 }
119
121}
122
123
124/** Returns the vertical spacing used by the bedrock grid.
125 */
127 return m_Lbz / (m_Mbz - 1.0);
128}
129
130unsigned int BTU_Full::Mz_impl() const {
131 return m_Mbz;
132}
133
134
135double BTU_Full::depth_impl() const {
136 return m_Lbz;
137}
138
139std::set<VariableMetadata> BTU_Full::state_impl() const {
140 return array::metadata({ &m_bottom_surface_flux, m_temp.get() });
141}
142
143void BTU_Full::write_state_impl(const OutputFile &output) const {
145 m_temp->write(output);
146}
147
149 (void) t;
150 // No time step restriction: we are using an unconditionally stable method.
151 return MaxTimestep("bedrock thermal layer");
152}
153
154
155/** Perform a step of the bedrock thermal model.
156*/
157void BTU_Full::update_impl(const array::Scalar &bedrock_top_temperature,
158 double t, double dt) {
159 (void) t;
160
162 bootstrap(bedrock_top_temperature);
164 }
165
166 if (dt < 0) {
167 throw RuntimeError(PISM_ERROR_LOCATION, "dt < 0 is not allowed");
168 }
169
170 array::AccessScope list{m_temp.get(), &m_bottom_surface_flux, &bedrock_top_temperature};
171
172 ParallelSection loop(m_grid->com);
173 try {
174 for (auto p : m_grid->points()) {
175 const int i = p.i(), j = p.j();
176
177 double *T = m_temp->get_column(i, j);
178
179 m_column->solve(dt, m_bottom_surface_flux(i, j), bedrock_top_temperature(i, j),
180 T, // input
181 T); // output
182
183 // Check that T is positive:
184 for (unsigned int k = 0; k < m_Mbz; ++k) {
185 if (T[k] <= 0.0) {
187 "invalid bedrock temperature: %f kelvin at %d,%d,%d",
188 T[k], i, j, k);
189 }
190 }
191 }
192 } catch (...) {
193 loop.failed();
194 }
195 loop.check();
196
198}
199
200/*! Computes the heat flux from the bedrock thermal layer upward into the
201 ice/bedrock interface:
202 \f[G_0 = -k_b \frac{\partial T_b}{\partial z}\big|_{z=0}.\f]
203 Uses the second-order finite difference expression
204 \f[\frac{\partial T_b}{\partial z}\big|_{z=0} \approx \frac{3 T_b(0) - 4 T_b(-\Delta z) + T_b(-2\Delta z)}{2 \Delta z}\f]
205 where \f$\Delta z\f$ is the equal spacing in the bedrock.
206
207 The above expression only makes sense when `Mbz` = `temp.n_levels` >= 3.
208 When `Mbz` = 2 we use first-order differencing. When temp was not created,
209 the `Mbz` <= 1 cases, we return the stored geothermal flux.
210*/
212
215 return;
216 }
217
218 double dz = this->vertical_spacing();
219 const int k0 = m_Mbz - 1; // Tb[k0] = ice/bed interface temp, at z=0
220
222
223 if (m_Mbz >= 3) {
224
225 for (auto p : m_grid->points()) {
226 const int i = p.i(), j = p.j();
227
228 const double *Tb = m_temp->get_column(i, j);
229 m_top_surface_flux(i, j) = - m_k * (3 * Tb[k0] - 4 * Tb[k0-1] + Tb[k0-2]) / (2 * dz);
230 }
231
232 } else {
233
234 for (auto p : m_grid->points()) {
235 const int i = p.i(), j = p.j();
236
237 const double *Tb = m_temp->get_column(i, j);
238 m_top_surface_flux(i, j) = - m_k * (Tb[k0] - Tb[k0-1]) / dz;
239 }
240
241 }
242}
243
246 throw RuntimeError(PISM_ERROR_LOCATION, "bedrock temperature is not available (bootstrapping is needed)");
247 }
248
249 return *m_temp;
250}
251
252void BTU_Full::bootstrap(const array::Scalar &bedrock_top_temperature) {
253
254 m_log->message(2,
255 " bootstrapping to fill lithosphere temperatures in the bedrock thermal layer\n"
256 " using temperature at the top bedrock surface and geothermal flux\n"
257 " (bedrock temperature is linear in depth)...\n");
258
259 double dz = this->vertical_spacing();
260 const int k0 = m_Mbz - 1; // Tb[k0] = ice/bedrock interface temp
261
262 array::AccessScope list{&bedrock_top_temperature, &m_bottom_surface_flux, m_temp.get()};
263 for (auto p : m_grid->points()) {
264 const int i = p.i(), j = p.j();
265
266 double *Tb = m_temp->get_column(i, j); // Tb points into temp memory
267
268 Tb[k0] = bedrock_top_temperature(i, j);
269 for (int k = k0-1; k >= 0; k--) {
270 Tb[k] = Tb[k+1] + dz * m_bottom_surface_flux(i, j) / m_k;
271 }
272 }
273
274 m_temp->inc_state_counter(); // mark as modified
275}
276
277} // end of namespace energy
278} // end of namespace pism
std::shared_ptr< const Grid > grid() const
Definition Component.cc:107
std::shared_ptr< const Config > m_config
configuration database used by this component
Definition Component.hh:160
const std::shared_ptr< const Grid > m_grid
grid used by this component
Definition Component.hh:158
void regrid(const std::string &module_name, array::Array &variable, RegriddingFlag flag=NO_REGRID_WITHOUT_REGRID_VARS)
Definition Component.cc:152
std::shared_ptr< const Logger > m_log
logger (for easy access)
Definition Component.hh:164
bool variable_exists(const std::string &short_name) const
Checks if a variable exists.
Definition File.cc:378
High-level PISM I/O class.
Definition File.hh:57
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
void failed()
Indicates a failure of a parallel section.
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
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
A virtual class collecting methods common to ice and bedrock 3D fields.
Definition Array3D.hh:33
void write(const OutputFile &file) const
Definition Array.cc:859
virtual MaxTimestep max_timestep_impl(double my_t) const
Definition BTU_Full.cc:148
const array::Array3D & temperature() const
Bedrock thermal layer temperature field.
Definition BTU_Full.cc:244
unsigned int m_Mbz
number of vertical levels within the bedrock
Definition BTU_Full.hh:120
void update_flux_through_top_surface()
Definition BTU_Full.cc:211
std::shared_ptr< array::Array3D > m_temp
Definition BTU_Full.hh:112
virtual unsigned int Mz_impl() const
Definition BTU_Full.cc:130
double m_Lbz
thickness of the bedrock layer, in meters
Definition BTU_Full.hh:122
virtual std::set< VariableMetadata > state_impl() const
Definition BTU_Full.cc:139
virtual void update_impl(const array::Scalar &bedrock_top_temperature, double t, double dt)
Definition BTU_Full.cc:157
std::shared_ptr< BedrockColumn > m_column
Definition BTU_Full.hh:129
bool m_bootstrapping_needed
true if the model needs to "bootstrap" the temperature field during the first time step
Definition BTU_Full.hh:125
virtual void write_state_impl(const OutputFile &output) const
The default (empty implementation).
Definition BTU_Full.cc:143
virtual double depth_impl() const
Definition BTU_Full.cc:135
virtual double vertical_spacing_impl() const
Definition BTU_Full.cc:126
virtual void bootstrap(const array::Scalar &bedrock_top_temperature)
Definition BTU_Full.cc:252
BTU_Full(std::shared_ptr< const Grid > g, const BTUGrid &vertical_grid)
Definition BTU_Full.cc:34
double m_D
diffusivity of the heat flow within the bedrock layer
Definition BTU_Full.hh:117
virtual void init_impl(const InputOptions &opts)
Initialize the bedrock thermal unit.
Definition BTU_Full.cc:89
double m_k
bedrock thermal conductivity
Definition BTU_Full.hh:115
array::Scalar m_bottom_surface_flux
upward heat flux through the bottom surface of the bed thermal layer
virtual void init_impl(const InputOptions &opts)
Initialize the bedrock thermal unit.
array::Scalar m_top_surface_flux
upward heat flux through the top surface of the bed thermal layer
Given the temperature of the top of the bedrock, for the duration of one time-step,...
#define PISM_ERROR_LOCATION
#define rho
Definition exactTestM.c:35
std::set< VariableMetadata > metadata(std::initializer_list< const Array * > vecs)
Definition Array.cc:1244
@ WITHOUT_GHOSTS
Definition Array.hh:63
@ PISM_GUESS
Definition IO_Flags.hh:57
@ PISM_READONLY
open an existing file for reading only
Definition IO_Flags.hh:69
static const double g
Definition exactTestP.cc:36
@ INIT_RESTART
Definition Component.hh:56
static const double k
Definition exactTestP.cc:42
InitializationType type
initialization type
Definition Component.hh:61
std::string filename
name of the input file (if applicable)
Definition Component.hh:63
unsigned int record
index of the record to re-start from
Definition Component.hh:65