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