PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
AgeModel.cc
Go to the documentation of this file.
1/* Copyright (C) 2016, 2017, 2019, 2020, 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
20#include "pism/age/AgeModel.hh"
21#include "pism/age/AgeColumnSystem.hh"
22#include "pism/util/error_handling.hh"
23#include "pism/util/io/File.hh"
24#include <memory>
25#include "pism/util/Logger.hh"
26#include "pism/util/io/IO_Flags.hh"
27
28namespace pism {
29
31 const array::Array3D *u,
32 const array::Array3D *v,
33 const array::Array3D *w)
34 : ice_thickness(thickness), u3(u), v3(v), w3(w) {
35 // empty
36}
37
39 ice_thickness = NULL;
40 u3 = NULL;
41 v3 = NULL;
42 w3 = NULL;
43}
44
45static void check_input(const array::Array *ptr, const char *name) {
46 if (ptr == NULL) {
48 "ice age model input %s was not provided", name);
49 }
50}
51
53 check_input(ice_thickness, "ice_thickness");
54 check_input(u3, "u3");
55 check_input(v3, "v3");
56 check_input(w3, "w3");
57}
58
59AgeModel::AgeModel(std::shared_ptr<const Grid> grid,
60 std::shared_ptr<const stressbalance::StressBalance> stress_balance)
61 : Component(grid),
62 // FIXME: should be able to use width=1...
63 m_ice_age(m_grid, "age", array::WITH_GHOSTS, m_grid->z(), m_config->get_number("grid.max_stencil_width")),
64 m_work(m_grid, "work_vector", array::WITHOUT_GHOSTS, m_grid->z()),
65 m_stress_balance(stress_balance) {
66
68 .long_name("age of ice")
69 .units("s");
70
71 m_ice_age.metadata()["valid_min"] = {0.0};
72
73 m_work.metadata().units("s");
74}
75
76/*!
77Let \f$\tau(t,x,y,z)\f$ be the age of the ice. Denote the three-dimensional
78velocity field within the ice fluid as \f$(u,v,w)\f$. The age equation
79is \f$d\tau/dt = 1\f$, that is, ice may move but it gets one year older in one
80year. Thus
81 \f[ \frac{\partial \tau}{\partial t} + u \frac{\partial \tau}{\partial x}
82 + v \frac{\partial \tau}{\partial y} + w \frac{\partial \tau}{\partial z} = 1 \f]
83This equation is purely advective and hyperbolic. The right-hand side is "1" as
84long as age \f$\tau\f$ and time \f$t\f$ are measured in the same units.
85Because the velocity field is incompressible, \f$\nabla \cdot (u,v,w) = 0\f$,
86we can rewrite the equation as
87 \f[ \frac{\partial \tau}{\partial t} + \nabla \left( (u,v,w) \tau \right) = 1 \f]
88There is a conservative first-order numerical method; see AgeColumnSystem::solveThisColumn().
89
90The boundary condition is that when the ice falls as snow it has age zero.
91That is, \f$\tau(t,x,y,h(t,x,y)) = 0\f$ in accumulation areas. There is no
92boundary condition elsewhere on the ice upper surface, as the characteristics
93go outward in the ablation zone. If the velocity in the bottom cell of ice
94is upward (\f$w>0\f$) then we also apply a zero age boundary condition,
95\f$\tau(t,x,y,0) = 0\f$. This is the case where ice freezes on at the base,
96either grounded basal ice freezing on stored water in till, or marine basal ice.
97(Note that the water that is frozen-on as ice might be quite "old" in the sense
98that its most recent time in the atmosphere was long ago; this comment is
99relevant to any analysis which relates isotope ratios to modeled age.)
100
101The numerical method is a conservative form of first-order upwinding, but the
102vertical advection term is computed implicitly. Thus there is no CFL-type
103stability condition from the vertical velocity; CFL is only for the horizontal
104velocity. We use a finely-spaced, equally-spaced vertical grid in the
105calculation. Note that the columnSystemCtx methods coarse_to_fine() and
106fine_to_coarse() interpolate back and forth between this fine grid and
107the storage grid. The storage grid may or may not be equally-spaced. See
108AgeColumnSystem::solve() for the actual method.
109 */
110void AgeModel::update(double t, double dt, const AgeModelInputs &inputs) {
111
112 // fix a compiler warning
113 (void) t;
114
115 inputs.check();
116
117 const array::Scalar &ice_thickness = *inputs.ice_thickness;
118
119 const array::Array3D
120 &u3 = *inputs.u3,
121 &v3 = *inputs.v3,
122 &w3 = *inputs.w3;
123
124 AgeColumnSystem system(m_grid->z(), "age",
125 m_grid->dx(), m_grid->dy(), dt,
126 m_ice_age, u3, v3, w3); // linear system to solve in each column
127
128 size_t Mz_fine = system.z().size();
129 std::vector<double> x(Mz_fine); // space for solution
130
131 array::AccessScope list{&ice_thickness, &u3, &v3, &w3, &m_ice_age, &m_work};
132
133 unsigned int Mz = m_grid->Mz();
134
135 ParallelSection loop(m_grid->com);
136 try {
137 for (auto p : m_grid->points()) {
138 const int i = p.i(), j = p.j();
139
140 system.init(i, j, ice_thickness(i, j));
141
142 if (system.ks() == 0) {
143 // if no ice, set the entire column to zero age
144 m_work.set_column(i, j, 0.0);
145 } else {
146 // general case: solve advection PDE
147
148 // solve the system for this column; call checks that params set
149 system.solve(x);
150
151 // put solution in array::Array3D
152 system.fine_to_coarse(x, i, j, m_work);
153
154 // Ensure that the age of the ice is non-negative.
155 //
156 // FIXME: this is a kludge. We need to ensure that our numerical method has the maximum
157 // principle instead. (We may still need this for correctness, though.)
158 double *column = m_work.get_column(i, j);
159 for (unsigned int k = 0; k < Mz; ++k) {
160 if (column[k] < 0.0) {
161 column[k] = 0.0;
162 }
163 }
164 }
165 }
166 } catch (...) {
167 loop.failed();
168 }
169 loop.check();
170
172}
173
175 return m_ice_age;
176}
177
179
180 if (m_stress_balance == nullptr) {
182 "AgeModel: no stress balance provided."
183 " Cannot compute max. time step.");
184 }
185
186 return MaxTimestep(m_stress_balance->max_timestep_cfl_3d().dt_max.value(), "age model");
187}
188
189void AgeModel::init(const InputOptions &opts) {
190
191 m_log->message(2, "* Initializing the age model...\n");
192
193
194 double initial_age_years = m_config->get_number("age.initial_value", "years");
195
196 if (opts.type == INIT_RESTART) {
197 File input_file(m_grid->com, opts.filename, io::PISM_GUESS, io::PISM_READONLY);
198
199 if (input_file.variable_exists("age")) {
200 m_ice_age.read(input_file, opts.record);
201 } else {
202 m_log->message(2,
203 "PISM WARNING: input file '%s' does not have the 'age' variable.\n"
204 " Setting it to %f years...\n",
205 opts.filename.c_str(), initial_age_years);
206 m_ice_age.set(m_config->get_number("age.initial_value", "seconds"));
207 }
208 } else {
209 m_log->message(2, " - setting initial age to %.4f years\n", initial_age_years);
210 m_ice_age.set(m_config->get_number("age.initial_value", "seconds"));
211 }
212
214}
215
216std::set<VariableMetadata> AgeModel::state_impl() const {
217 return array::metadata({ &m_ice_age });
218}
219
220void AgeModel::write_state_impl(const OutputFile &output) const {
221 m_ice_age.write(output);
222}
223
224} // end of namespace pism
void init(int i, int j, double thickness)
void solve(std::vector< double > &x)
First-order upwind scheme with implicit in the vertical: one column solve.
Tridiagonal linear system for vertical column of age (pure advection) problem.
const array::Array3D * w3
Definition AgeModel.hh:41
void check() const
Definition AgeModel.cc:52
const array::Array3D * v3
Definition AgeModel.hh:40
const array::Array3D * u3
Definition AgeModel.hh:39
const array::Scalar * ice_thickness
Definition AgeModel.hh:38
array::Array3D m_ice_age
Definition AgeModel.hh:60
AgeModel(std::shared_ptr< const Grid > grid, std::shared_ptr< const stressbalance::StressBalance > stress_balance)
Definition AgeModel.cc:59
std::set< VariableMetadata > state_impl() const
Definition AgeModel.cc:216
std::shared_ptr< const stressbalance::StressBalance > m_stress_balance
Definition AgeModel.hh:62
void write_state_impl(const OutputFile &output) const
The default (empty implementation).
Definition AgeModel.cc:220
array::Array3D m_work
Definition AgeModel.hh:61
MaxTimestep max_timestep_impl(double t) const
Definition AgeModel.cc:178
const array::Array3D & age() const
Definition AgeModel.cc:174
void init(const InputOptions &opts)
Definition AgeModel.cc:189
void update(double t, double dt, const AgeModelInputs &inputs)
Definition AgeModel.cc:110
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
A class defining a common interface for most PISM sub-models.
Definition Component.hh:118
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
VariableMetadata & long_name(const std::string &input)
VariableMetadata & 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 Array3D &input)
Definition Array3D.cc:215
void set_column(int i, int j, double c)
Set all values of scalar quantity to given a single value in a particular column.
Definition Array3D.cc:56
double * get_column(int i, int j)
Definition Array3D.cc:127
A virtual class collecting methods common to ice and bedrock 3D fields.
Definition Array3D.hh:33
void read(const std::string &filename, unsigned int time)
Definition Array.cc:753
void write(const OutputFile &file) const
Definition Array.cc:859
void set(double c)
Result: v[j] <- c for all j.
Definition Array.cc:659
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
Definition Array.cc:467
Abstract class for reading, writing, allocating, and accessing a DA-based PETSc Vec (2D and 3D fields...
Definition Array.hh:209
const std::vector< double > & z() const
void fine_to_coarse(const std::vector< double > &input, int i, int j, array::Array3D &output) const
unsigned int ks() const
#define PISM_ERROR_LOCATION
std::set< VariableMetadata > metadata(std::initializer_list< const Array * > vecs)
Definition Array.cc:1244
@ PISM_GUESS
Definition IO_Flags.hh:57
@ PISM_READONLY
open an existing file for reading only
Definition IO_Flags.hh:69
static void check_input(const array::Array *ptr, const char *name)
Definition AgeModel.cc:45
@ 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