23 #include <gsl/gsl_interp.h>
28 #include "pism/age/Isochrones.hh"
29 #include "pism/util/Context.hh"
30 #include "pism/util/MaxTimestep.hh"
31 #include "pism/util/Time.hh"
32 #include "pism/stressbalance/StressBalance.hh"
33 #include "pism/util/array/Array3D.hh"
34 #include "pism/util/array/Scalar.hh"
35 #include "pism/util/interpolation.hh"
36 #include "pism/util/petscwrappers/Vec.hh"
58 for (
size_t k = 0;
k < N - 1;
k++) {
59 if (a[
k] > a[
k + 1]) {
73 const std::vector<double> ×) {
74 using namespace details;
77 if ((
int)times.size() > N_max) {
79 "the total number of isochronal layers (%d) exceeds '%s' = %d",
83 const auto &time = grid->ctx()->time();
88 result->metadata().long_name(
"thicknesses of isochronal layers").units(
"m");
91 pism::printf(
"times for isochrones in '%s'; earliest deposition times for layers in '%s'",
93 auto &z = result->metadata(0).z();
96 .long_name(z_description)
97 .units(time->units_string());
98 z[
"calendar"] = time->calendar();
110 static std::shared_ptr<array::Array3D>
112 const std::vector<double> &requested_times) {
114 auto grid = input.
grid();
116 const auto &input_times = input.
levels();
122 "deposition times in '%s' have to be non-decreasing",
127 for (
auto t : input_times) {
135 for (
auto t : requested_times) {
136 if (t > last_kept_time) {
146 const int i = p.i(), j = p.j();
149 auto *out = result->get_column(i, j);
151 for (
size_t k = 0;
k < N_layers_to_copy; ++
k) {
163 const std::vector<double> ×) {
164 double T_start = time.
start(), T_end = time.
end();
166 std::vector<double> result;
167 for (
auto t : times) {
168 if (t >= T_start and t <= T_end) {
181 using namespace details;
185 std::vector<double> result(n_deposition_times);
197 using namespace details;
211 if (N_deposition_times == 0) {
213 "'%s' = '%s' has no times within the modeled time span [%s, %s]",
218 if ((
int)N_deposition_times > N_max) {
221 "the number of times (%d) in '%s' exceeds the allowed maximum ('%s' = %d)",
238 const File &input_file,
int record) {
242 auto N = (int)result->levels().size();
244 auto metadata = result->metadata(0);
246 auto variable_info = input_file.
find_variable(metadata.get_name(), metadata[
"standard_name"]);
249 grid->registration());
261 std::vector<double> Z(N);
262 for (
int k = 0;
k < N; ++
k) {
267 lic.
z = std::make_shared<Interpolation>(
NEAREST, Z, Z);
280 const File &input_file,
int record) {
283 result->read(input_file, record);
296 if (t <= current_time) {
309 auto regrid_file = config.
get_string(
"input.regrid.file");
311 if (regrid_file.empty()) {
328 auto grid = layer_thickness.
grid();
330 auto N = layer_thickness.
levels().size();
334 for (
auto p = grid->points(); p; p.next()) {
335 const int i = p.i(), j = p.j();
339 double H_total = 0.0;
340 for (
int k = 0;
k < (int)N; ++
k) {
346 double S = ice_thickness(i, j) / H_total;
347 for (
size_t k = 0;
k < N; ++
k) {
358 std::shared_ptr<const stressbalance::StressBalance> stress_balance)
359 :
Component(grid), m_stress_balance(stress_balance) {
383 using namespace details;
392 initialize(regrid_file, (
int)last_record,
true);
405 auto N_deposition_times = requested_times.size();
407 if (N_bootstrap < 0) {
413 "* Bootstrapping the isochrone tracking model, adding %d isochronal layers...\n",
416 if (N_bootstrap + (
int)N_deposition_times > N_max) {
420 "%s (%d) + %s (%d) exceeds the allowed maximum (%s = %d)",
N_boot_parameter,
424 if (N_bootstrap > 0) {
429 for (
const auto &t : requested_times) {
439 for (
auto p =
m_grid->points(); p; p.next()) {
440 const int i = p.i(), j = p.j();
442 double H = ice_thickness(i, j);
445 for (
int k = 0;
k < N_bootstrap; ++
k) {
446 column[
k] = H /
static_cast<double>(N_bootstrap);
456 for (
auto p =
m_grid->points(); p; p.next()) {
457 const int i = p.i(), j = p.j();
464 std::vector<std::string> dates;
468 m_log->message(3,
"Deposition times: %s\n",
join(dates,
", ").c_str());
473 e.
add_context(
"bootstrapping the isochrone tracking model");
484 using namespace details;
486 m_log->message(2,
"* Initializing the isochrone tracking model from '%s'...\n",
489 if (use_interpolation) {
490 m_log->message(2,
" [using bilinear interpolation to read layer thicknesses]\n");
496 std::shared_ptr<array::Array3D> tmp;
498 if (use_interpolation) {
513 std::vector<std::string> dates;
517 m_log->message(3,
"Deposition times: %s\n",
join(dates,
", ").c_str());
523 e.
add_context(
"initializing the isochrone tracking model");
538 initialize(regrid_file, (
int)last_record,
true);
567 for (
auto p =
m_grid->points(); p; p.next()) {
568 const int i = p.i(), j = p.j();
574 double dH = top_surface_mass_balance(i, j);
578 if (H[
k] + dH >= 0.0) {
591 double dH = bottom_surface_mass_balance(i, j);
595 if (H[
k] + dH >= 0.0) {
617 H_min =
m_config->get_number(
"geometry.ice_free_thickness_standard");
620 auto Q = [](
double U,
double f_n,
double f_p) {
return U * (U >= 0 ? f_n : f_p); };
622 for (
auto p =
m_grid->points(); p; p.next()) {
623 const int i = p.i(), j = p.j();
625 const double *d_c =
m_tmp->get_column(i, j), *d_n =
m_tmp->get_column(i, j + 1),
626 *d_e =
m_tmp->get_column(i + 1, j), *d_s =
m_tmp->get_column(i, j - 1),
627 *d_w =
m_tmp->get_column(i - 1, j);
632 double d_total = 0.0;
663 double Q_n = Q(0.5 * (V + V_n), d_c[
k], d_n[
k]), Q_e = Q(0.5 * (U + U_e), d_c[
k], d_e[
k]),
664 Q_s = Q(0.5 * (V + V_s), d_s[
k], d_c[
k]), Q_w = Q(0.5 * (U + U_w), d_w[
k], d_c[
k]);
666 d[
k] = d_c[
k] - dt * ((Q_e - Q_w) / dx + (Q_n - Q_s) / dy);
682 assert(ice_thickness(i, j) < H_min or d_total > 0.0);
686 double S = ice_thickness(i, j) / d_total;
724 "Isochrone tracking: reached isochrones.max_n_layers and can't add more.\n"
725 " SMB will contribute to the current top layer.");
739 "Isochrone tracking: no stress balance provided. "
740 "Cannot compute the maximum time step.");
756 return { t0 - t,
"isochrones" };
760 return {
"isochrones" };
802 using namespace details;
808 auto description =
pism::printf(
"depth below surface of isochrones for times in '%s'",
811 m_vars[0].long_name(description).units(
"m");
812 auto &z = m_vars[0].z();
827 result->metadata(0) = m_vars[0];
829 size_t N = result->levels().size();
833 for (
auto p =
m_grid->points(); p; p.next()) {
834 const int i = p.i(), j = p.j();
836 double *
column = result->get_column(i, j);
839 double total_depth = 0.0;
840 for (
int k = (
int)N - 1;
k >= 0; --
k) {
const units::System::Ptr m_sys
unit system used by this component
const Time & time() const
std::shared_ptr< const Grid > grid() const
const Config::ConstPtr m_config
configuration database used by this component
const Logger::ConstPtr m_log
logger (for easy access)
const std::shared_ptr< const Grid > m_grid
grid used by this component
DiagnosticList diagnostics() const
A class defining a common interface for most PISM sub-models.
double get_number(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
std::string get_string(const std::string &name, UseFlag flag=REMEMBER_THIS_USE) const
A class for storing and accessing PISM configuration flags and parameters.
A template derived from Diagnostic, adding a "Model".
static Ptr wrap(const T &input)
std::shared_ptr< Diagnostic > Ptr
void read_variable(const std::string &variable_name, const std::vector< unsigned int > &start, const std::vector< unsigned int > &count, double *ip) const
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.
unsigned int nrecords() const
Get the number of records. Uses the length of an unlimited dimension.
std::string filename() const
unsigned int dimension_length(const std::string &name) const
Get the length of a dimension.
High-level PISM I/O class.
std::shared_ptr< array::Array3D > m_layer_thickness
isochronal layer thicknesses
void bootstrap(const array::Scalar &ice_thickness)
MaxTimestep max_timestep_deposition_times(double t) const
void update(double t, double dt, const array::Array3D &u, const array::Array3D &v, const array::Scalar &ice_thickness, const array::Scalar &top_surface_mass_balance, const array::Scalar &bottom_surface_mass_balance)
MaxTimestep max_timestep_impl(double t) const
std::shared_ptr< array::Array3D > m_tmp
temporary storage needed for time stepping
void write_model_state_impl(const File &output) const
std::shared_ptr< const stressbalance::StressBalance > m_stress_balance
Isochrones(std::shared_ptr< const Grid > grid, std::shared_ptr< const stressbalance::StressBalance > stress_balance)
DiagnosticList diagnostics_impl() const
size_t m_top_layer_index
The index of the topmost isochronal layer.
double top_layer_deposition_time() const
void define_model_state_impl(const File &output) const
void restart(const File &input_file, int record)
const array::Array3D & layer_thicknesses() const
void initialize(const File &input_file, int record, bool use_interpolation)
MaxTimestep max_timestep_cfl() const
std::array< int, 4 > count
std::array< int, 4 > start
std::shared_ptr< Interpolation > z
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
void add_context(const std::string &message)
Add a message providing some context. This way we can (sort of) get a stack trace even though C++ exc...
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
std::string units_string() const
Internal time units as a string.
double current() const
Current time, in seconds.
std::vector< double > parse_times(const std::string &spec) const
std::string date(double T) const
Returns the date corresponding to time T.
std::string calendar() const
Returns the calendar string.
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
double interpolate(int i, int j, double z) const
Return value of scalar quantity at level z (m) above base of ice (by linear interpolation).
std::shared_ptr< Array3D > duplicate(Kind ghostedp=WITHOUT_GHOSTS) const
double * get_column(int i, int j)
A virtual class collecting methods common to ice and bedrock 3D fields.
const std::vector< double > & levels() const
const std::string & get_name() const
Get the name of an Array object.
std::shared_ptr< const Grid > grid() const
IsochroneDepths(const Isochrones *m)
std::shared_ptr< array::Array > compute_impl() const
Report isochrone depth below surface, in meters.
Wrapper around VecGetArray and VecRestoreArray.
#define PISM_ERROR_LOCATION
double max(const array::Scalar &input)
Finds maximum over all the values in an array::Scalar object. Ignores ghosts.
double min(const array::Scalar &input)
Finds minimum over all the values in an array::Scalar object. Ignores ghosts.
static const char * N_max_parameter
static std::vector< double > prune_deposition_times(const Time &time, const std::vector< double > ×)
std::vector< double > deposition_times(const Config &config, const Time &time)
static void renormalize(const array::Scalar &ice_thickness, array::Array3D &layer_thickness)
static const char * isochrone_depth_variable_name
static std::shared_ptr< array::Array3D > allocate_layer_thickness(std::shared_ptr< const Grid > grid, const std::vector< double > ×)
static size_t n_active_layers(std::vector< double > deposition_times, double current_time)
static std::shared_ptr< array::Array3D > allocate_layer_thickness(const array::Array3D &input, double T_start, const std::vector< double > &requested_times)
static const char * layer_thickness_variable_name
static const char * N_boot_parameter
static const char * deposition_time_variable_name
static std::shared_ptr< array::Array3D > read_layer_thickness(std::shared_ptr< const Grid > grid, const File &input_file, int record)
static bool regridp(const Config &config)
static const char * times_parameter
static std::shared_ptr< array::Array3D > regrid_layer_thickness(std::shared_ptr< const Grid > grid, const File &input_file, int record)
static std::vector< double > deposition_times(const File &input_file)
static bool non_decreasing(const std::vector< double > &a)
Checks if a vector of doubles is not decreasing.
static Vector3 column(const double A[3][3], size_t k)
void regrid_spatial_variable(SpatialVariableMetadata &variable, const Grid &internal_grid, const LocalInterpCtx &lic, const File &file, double *output)
Regrid from a NetCDF file into a distributed array output.
@ PISM_READONLY
open an existing file for reading only
std::string printf(const char *format,...)
std::map< std::string, Diagnostic::Ptr > DiagnosticList
std::set< std::string > set_split(const std::string &input, char separator)
Transform a separator-separated list (a string) into a set of strings.
bool member(const std::string &string, const std::set< std::string > &set)
std::string join(const std::vector< std::string > &strings, const std::string &separator)
Concatenate strings, inserting separator between elements.
Star stencil points (in the map-plane).
static double S(unsigned n)