20 #include "pism/energy/utilities.hh"
22 #include "pism/energy/bootstrapping.hh"
23 #include "pism/util/ConfigInterface.hh"
24 #include "pism/util/Context.hh"
25 #include "pism/util/EnthalpyConverter.hh"
26 #include "pism/util/Grid.hh"
27 #include "pism/util/Logger.hh"
28 #include "pism/util/VariableMetadata.hh"
29 #include "pism/util/array/Array3D.hh"
30 #include "pism/util/array/Scalar.hh"
31 #include "pism/util/error_handling.hh"
32 #include "pism/util/pism_utilities.hh"
51 auto grid = result.
grid();
56 const unsigned int Mz = grid->Mz();
57 const std::vector<double> &z = grid->z();
59 for (
auto p = grid->points(); p; p.next()) {
60 const int i = p.i(), j = p.j();
62 const double *Tij = temperature.
get_column(i, j);
65 for (
unsigned int k = 0;
k < Mz; ++
k) {
66 const double depth = ice_thickness(i, j) - z[
k];
67 Enthij[
k] = EC->enthalpy_permissive(Tij[
k], 0.0, EC->pressure(depth));
79 auto grid = result.
grid();
84 const unsigned int Mz = grid->Mz();
85 const std::vector<double> &z = grid->z();
87 for (
auto p = grid->points(); p; p.next()) {
88 const int i = p.i(), j = p.j();
90 const double *E = enthalpy.
get_column(i, j), H = ice_thickness(i, j);
93 for (
unsigned int k = 0;
k < Mz; ++
k) {
94 const double depth = H - z[
k];
95 T[
k] = EC->temperature(E[
k], EC->pressure(depth));
109 auto grid = result.
grid();
112 array::AccessScope list{ &temperature, &liquid_water_fraction, &ice_thickness, &result };
114 const unsigned int Mz = grid->Mz();
115 const std::vector<double> &z = grid->z();
117 for (
auto p = grid->points(); p; p.next()) {
118 const int i = p.i(), j = p.j();
120 const double *T = temperature.
get_column(i, j);
121 const double *omega = liquid_water_fraction.
get_column(i, j);
124 for (
unsigned int k = 0;
k < Mz; ++
k) {
125 const double depth = ice_thickness(i, j) - z[
k];
126 E[
k] = EC->enthalpy_permissive(T[
k], omega[
k], EC->pressure(depth));
139 auto grid = result.
grid();
146 .
long_name(
"liquid water fraction in ice (between 0 and 1)")
153 for (
auto p = grid->points(); p; p.next()) {
154 const int i = p.i(), j = p.j();
156 const double *Enthij = enthalpy.
get_column(i, j);
159 for (
unsigned int k = 0;
k < grid->Mz(); ++
k) {
160 const double depth = ice_thickness(i, j) - grid->z(
k);
161 omegaij[
k] = EC->water_fraction(Enthij[
k], EC->pressure(depth));
182 auto grid = result.
grid();
188 .
long_name(
"cts = E/E_s(p), so cold-temperate transition surface is at cts = 1")
193 const unsigned int Mz = grid->Mz();
194 const std::vector<double> &z = grid->z();
196 for (
auto p = grid->points(); p; p.next()) {
197 const int i = p.i(), j = p.j();
200 const double *enthalpy = ice_enthalpy.
get_column(i,j);
202 for (
unsigned int k = 0;
k < Mz; ++
k) {
203 const double depth = ice_thickness(i,j) - z[
k];
204 CTS[
k] = enthalpy[
k] / EC->enthalpy_cts(EC->pressure(depth));
221 double enthalpy_sum = 0.0;
223 auto grid = ice_enthalpy.
grid();
226 auto cell_area = grid->cell_area();
228 const std::vector<double> &z = grid->z();
233 for (
auto p = grid->points(); p; p.next()) {
234 const int i = p.i(), j = p.j();
236 const double H = ice_thickness(i, j);
238 if (H >= thickness_threshold) {
239 const int ks = grid->kBelowHeight(H);
244 for (
int k = 0;
k < ks; ++
k) {
245 enthalpy_sum += cell_area * E[
k] * (z[
k+1] - z[
k]);
247 enthalpy_sum += cell_area * E[ks] * (H - z[ks]);
255 enthalpy_sum *= config->get_number(
"constants.ice.density");
257 return GlobalSum(grid->com, enthalpy_sum);
333 auto grid = result.
grid();
334 auto ctx = grid->ctx();
335 auto config = ctx->config();
336 auto log = ctx->log();
337 auto EC = ctx->enthalpy_converter();
339 auto use_smb = config->get_string(
"bootstrapping.temperature_heuristic") ==
"smb";
343 " - Filling 3D ice temperatures using surface temperature"
344 " (and mass balance for velocity estimate)...\n");
348 " - Filling 3D ice temperatures using surface temperature"
349 " (and a quartic guess without SMB)...\n");
353 ice_k = config->get_number(
"constants.ice.thermal_conductivity"),
354 ice_density = config->get_number(
"constants.ice.density"),
355 ice_c = config->get_number(
"constants.ice.specific_heat_capacity"),
356 K = ice_k / (ice_density * ice_c),
357 T_min = config->get_number(
"energy.minimum_allowed_temperature"),
358 T_melting = config->get_number(
"constants.fresh_water.melting_point_temperature",
362 &ice_thickness, &basal_heat_flux, &result};
366 for (
auto p = grid->points(); p; p.next()) {
367 const int i = p.i(), j = p.j();
370 T_surface =
std::min(ice_surface_temp(i, j), T_melting),
371 H = ice_thickness(i, j),
372 G = basal_heat_flux(i, j);
374 const unsigned int ks = grid->kBelowHeight(H);
376 if (G < 0.0 and ks > 0) {
377 std::string units = basal_heat_flux.
metadata()[
"units"];
379 const char *quantity = (Mbz > 0 ?
380 "temperature of the bedrock thermal layer" :
383 "Negative upward heat flux (%f %s) through the bottom of the ice column\n"
384 "is not allowed by PISM's ice temperature bootstrapping method.\n"
385 "Please check the %s at i=%d, j=%d.",
386 G, units.c_str(), quantity, i, j);
389 if (T_surface < T_min) {
391 "T_surface(%d,%d) = %f < T_min = %f Kelvin",
392 i, j, T_surface, T_min);
401 const double SMB = surface_mass_balance(i, j) / ice_density;
403 for (
unsigned int k = 0;
k < ks;
k++) {
404 const double z = grid->z(
k);
410 for (
unsigned int k = 0;
k < ks;
k++) {
411 const double z = grid->z(
k);
418 for (
unsigned int k = 0;
k < ks;
k++) {
421 "T(%d,%d,%d) = %f < T_min = %f Kelvin",
422 i, j,
k, T[
k], T_min);
427 for (
unsigned int k = ks;
k < grid->Mz();
k++) {
446 surface_mass_balance, basal_heat_flux,
std::shared_ptr< const Config > ConstPtr
std::shared_ptr< EnthalpyConverter > Ptr
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.
double * get_column(int i, int j)
A virtual class collecting methods common to ice and bedrock 3D fields.
void set_name(const std::string &name)
Sets the variable name to name.
std::shared_ptr< const Grid > grid() const
void inc_state_counter()
Increment the object state counter.
void update_ghosts()
Updates ghost points.
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
#define PISM_ERROR_LOCATION
double min(const array::Scalar &input)
Finds minimum over all the values in an array::Scalar object. Ignores ghosts.
void compute_liquid_water_fraction(const array::Array3D &enthalpy, const array::Scalar &ice_thickness, array::Array3D &result)
Compute the liquid fraction corresponding to enthalpy and ice_thickness.
void bootstrap_ice_temperature(const array::Scalar &ice_thickness, const array::Scalar &ice_surface_temp, const array::Scalar &surface_mass_balance, const array::Scalar &basal_heat_flux, array::Array3D &result)
Create a temperature field within the ice from provided ice thickness, surface temperature,...
void compute_cts(const array::Array3D &ice_enthalpy, const array::Scalar &ice_thickness, array::Array3D &result)
Compute the CTS field, CTS = E/E_s(p), from ice_enthalpy and ice_thickness, and put in result.
double ice_temperature_guess(EnthalpyConverter::Ptr EC, double H, double z, double T_surface, double G, double ice_k)
double ice_temperature_guess_smb(EnthalpyConverter::Ptr EC, double H, double z, double T_surface, double G, double ice_k, double K, double SMB)
void compute_enthalpy_cold(const array::Array3D &temperature, const array::Scalar &ice_thickness, array::Array3D &result)
Compute ice enthalpy from temperature temperature by assuming the ice has zero liquid fraction.
void compute_temperature(const array::Array3D &enthalpy, const array::Scalar &ice_thickness, array::Array3D &result)
void bootstrap_ice_enthalpy(const array::Scalar &ice_thickness, const array::Scalar &ice_surface_temp, const array::Scalar &surface_mass_balance, const array::Scalar &basal_heat_flux, array::Array3D &result)
void compute_enthalpy(const array::Array3D &temperature, const array::Array3D &liquid_water_fraction, const array::Scalar &ice_thickness, array::Array3D &result)
Compute result (enthalpy) from temperature and liquid fraction.
double total_ice_enthalpy(double thickness_threshold, const array::Array3D &ice_enthalpy, const array::Scalar &ice_thickness)
Computes the total ice enthalpy in J.
static double K(double psi_x, double psi_y, double speed, double epsilon)
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)