PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
BTU_Full.cc
Go to the documentation of this file.
1 /* Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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 
28 namespace pism {
29 namespace energy {
30 
31 
32 BTU_Full::BTU_Full(std::shared_ptr<const Grid> g, const BTUGrid &grid)
33  : BedThermalUnit(g),
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("K");
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.
87 void BTU_Full::init_impl(const InputOptions &opts) {
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.find_variable("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) {
112  m_bootstrapping_needed = true;
113  } else {
114  m_bootstrapping_needed = false;
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 
128 unsigned int BTU_Full::Mz_impl() const {
129  return m_Mbz;
130 }
131 
132 
133 double BTU_Full::depth_impl() const {
134  return m_Lbz;
135 }
136 
137 void BTU_Full::define_model_state_impl(const File &output) const {
139  m_temp->define(output, io::PISM_DOUBLE);
140 }
141 
142 void 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 */
156 void BTU_Full::update_impl(const array::Scalar &bedrock_top_temperature,
157  double t, double dt) {
158  (void) t;
159 
161  bootstrap(bedrock_top_temperature);
162  m_bootstrapping_needed = false;
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 
251 void 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
@ REGRID_WITHOUT_REGRID_VARS
Definition: Component.hh:151
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
VariableLookupData find_variable(const std::string &short_name, const std::string &std_name) const
Find a variable using its standard name and/or short name.
Definition: File.cc:361
High-level PISM I/O class.
Definition: File.hh:56
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
Definition: MaxTimestep.hh:31
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:65
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:540
void write(const std::string &filename) const
Definition: Array.cc:800
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
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
virtual void update_impl(const array::Scalar &bedrock_top_temperature, double t, double dt)=0
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:62
@ PISM_GUESS
Definition: IO_Flags.hh:56
@ PISM_READONLY
open an existing file for reading only
Definition: IO_Flags.hh:72
@ 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