33 #include <gsl/gsl_math.h>
35 #include "pism/coupler/util/options.hh"
36 #include "pism/geometry/Geometry.hh"
37 #include "pism/util/ConfigInterface.hh"
38 #include "pism/util/Grid.hh"
39 #include "pism/util/Mask.hh"
40 #include "pism/util/Time.hh"
42 #include "pism/coupler/ocean/Pico.hh"
43 #include "pism/coupler/ocean/PicoGeometry.hh"
44 #include "pism/coupler/ocean/PicoPhysics.hh"
45 #include "pism/util/array/Forcing.hh"
52 m_Soc(m_grid,
"pico_salinity"),
53 m_Soc_box0(m_grid,
"pico_salinity_box0"),
54 m_Toc(m_grid,
"pico_temperature"),
55 m_Toc_box0(m_grid,
"pico_temperature_box0"),
56 m_T_star(m_grid,
"pico_T_star"),
57 m_overturning(m_grid,
"pico_overturning"),
58 m_basal_melt_rate(m_grid,
"pico_basal_melt_rate"),
67 auto buffer_size =
static_cast<int>(
m_config->get_number(
"input.forcing.buffer_size"));
89 .long_name(
"potential temperature of the adjacent ocean")
93 .long_name(
"salinity of the adjacent ocean")
126 m_n_boxes =
static_cast<int>(
m_config->get_number(
"ocean.pico.number_of_boxes"));
132 m_log->message(2,
"* Initializing the Potsdam Ice-shelf Cavity mOdel for the ocean ...\n");
145 m_log->message(4,
"PICO basin min=%f, max=%f\n",
151 m_log->message(2,
" -Using %d drainage basins and values: \n"
152 " gamma_T= %.2e, overturning_coeff = %.2e... \n",
155 m_log->message(2,
" -Depth of continental shelf for computation of temperature and salinity input\n"
156 " is set for whole domain to continental_shelf_depth=%.0f meter\n",
166 ice_density =
m_config->get_number(
"constants.ice.density"),
167 water_density =
m_config->get_number(
"constants.sea_water.density"),
168 g =
m_config->get_number(
"constants.standard_gravity");
202 auto grid = basal_melt_rate.
grid();
210 for (
auto p = grid->points(); p; p.next()) {
212 const int i = p.i(), j = p.j();
214 auto M = cell_type.
box(i, j);
216 bool potential_partially_filled_cell =
223 if (potential_partially_filled_cell) {
224 auto BMR = basal_melt_rate.
box(i, j);
227 double melt_sum = 0.0;
239 basal_melt_rate(i, j) = melt_sum / N;
255 double T_fill_value =
m_config->get_number(
"constants.fresh_water.melting_point_temperature");
272 const auto &cell_type = geometry.
cell_type;
286 std::vector<double> basin_temperature(
m_n_basins);
287 std::vector<double> basin_salinity(
m_n_basins);
352 ice_density =
m_config->get_number(
"constants.ice.density"),
353 water_density =
m_config->get_number(
"constants.sea_water.density"),
354 g =
m_config->get_number(
"constants.standard_gravity");
379 std::vector<double> &temperature,
380 std::vector<double> &salinity)
const {
389 for (
int basin_id = 0; basin_id <
m_n_basins; basin_id++) {
390 temperature[basin_id] = 0.0;
391 salinity[basin_id] = 0.0;
394 array::AccessScope list{ &theta_ocean, &salinity_ocean, &basin_mask, &continental_shelf_mask };
399 for (
auto p =
m_grid->points(); p; p.next()) {
400 const int i = p.i(), j = p.j();
402 if (continental_shelf_mask.
as_int(i, j) == 2) {
403 int basin_id = basin_mask.
as_int(i, j);
405 count[basin_id] += 1;
406 salinity[basin_id] += salinity_ocean(i, j);
407 temperature[basin_id] += theta_ocean(i, j);
421 salinity = salinityr;
422 temperature = temperaturer;
426 temperature[0] = physics.
T_dummy();
427 salinity[0] = physics.
S_dummy();
430 for (
int basin_id = 1; basin_id <
m_n_basins; basin_id++) {
432 if (
count[basin_id] != 0) {
433 salinity[basin_id] /=
count[basin_id];
434 temperature[basin_id] /=
count[basin_id];
436 m_log->message(5,
" %d: temp =%.3f, salinity=%.3f\n", basin_id, temperature[basin_id], salinity[basin_id]);
440 "PICO WARNING: basin %d contains no cells with ocean data on continental shelf\n"
441 " (no values with ocean_contshelf_mask=2).\n"
442 " Using default temperature (%.3f K) and salinity (%.3f g/kg)\n"
443 " since mean salinity and temperature cannot be computed.\n"
444 " This may bias the basal melt rate estimate.\n"
445 " Please check your input data.\n",
448 temperature[basin_id] = physics.
T_dummy();
449 salinity[basin_id] = physics.
S_dummy();
466 const std::vector<double> &basin_temperature,
467 const std::vector<double> &basin_salinity,
471 array::AccessScope list{ &ice_thickness, &basin_mask, &Soc_box0, &Toc_box0, &mask, &shelf_mask };
484 for (
auto p =
m_grid->points(); p; p.next()) {
485 const int i = p.i(), j = p.j();
486 int s = shelf_mask.
as_int(i, j);
487 int b = basin_mask.
as_int(i, j);
493 auto M = mask.
star(i, j);
498 if (cfs_in_basins_per_shelf[s *
m_n_basins + b] != b) {
499 cfs_in_basins_per_shelf[s *
m_n_basins + b] = b;
512 n_shelf_cells = n_shelf_cellsr;
513 n_shelf_cells_per_basin = n_shelf_cells_per_basinr;
514 cfs_in_basins_per_shelf = cfs_in_basins_per_shelfr;
520 if (n_shelf_cells_per_basin[sb] > 0 and cfs_in_basins_per_shelf[sb] == 0) {
521 n_shelf_cells[s] -= n_shelf_cells_per_basin[sb];
522 n_shelf_cells_per_basin[sb] = 0;
530 int low_temperature_counter = 0;
531 for (
auto p =
m_grid->points(); p; p.next()) {
532 const int i = p.i(), j = p.j();
535 Toc_box0(i, j) = 0.0;
536 Soc_box0(i, j) = 0.0;
538 int s = shelf_mask.
as_int(i, j);
543 assert(n_shelf_cells[s] > 0);
544 double N =
std::max(n_shelf_cells[s], 1);
549 Toc_box0(i, j) += basin_temperature[b] * n_shelf_cells_per_basin[sb] / N;
550 Soc_box0(i, j) += basin_salinity[b] * n_shelf_cells_per_basin[sb] / N;
553 double theta_pm = physics.
theta_pm(Soc_box0(i, j), physics.
pressure(ice_thickness(i, j)));
556 if (Toc_box0(i, j) < theta_pm) {
557 const double eps = 0.001;
560 Toc_box0(i, j) = theta_pm + eps;
561 low_temperature_counter += 1;
566 low_temperature_counter =
GlobalSum(
m_grid->com, low_temperature_counter);
567 if (low_temperature_counter > 0) {
570 "PICO WARNING: temperature has been below pressure melting temperature in %d cases,\n"
571 " setting it to pressure melting temperature\n",
572 low_temperature_counter);
594 const double T0 =
m_config->get_number(
"constants.fresh_water.melting_point_temperature"),
595 beta_CC =
m_config->get_number(
"constants.ice.beta_Clausius_Clapeyron"),
596 g =
m_config->get_number(
"constants.standard_gravity"),
597 ice_density =
m_config->get_number(
"constants.ice.density");
599 array::AccessScope list{ &ice_thickness, &cell_type, &shelf_mask, &Toc_box0, &Soc_box0,
600 &Toc, &Soc, &basal_melt_rate, &basal_temperature };
602 for (
auto p =
m_grid->points(); p; p.next()) {
603 const int i = p.i(), j = p.j();
606 if (shelf_mask.
as_int(i, j) > 0) {
607 double pressure = physics.
pressure(ice_thickness(i, j));
609 basal_melt_rate(i, j) =
611 basal_temperature(i, j) = physics.
T_pm(Soc_box0(i, j), pressure);
614 Toc(i, j) = Toc_box0(i, j);
615 Soc(i, j) = Soc_box0(i, j);
618 const double pressure = ice_density *
g * ice_thickness(i, j);
620 basal_temperature(i, j) = T0 -
beta_CC * pressure;
621 basal_melt_rate(i, j) = 0.0;
645 array::AccessScope list{ &ice_thickness, &shelf_mask, &box_mask, &T_star, &Toc_box0, &Toc,
646 &Soc_box0, &Soc, &overturning, &basal_melt_rate, &basal_temperature };
648 int n_Toc_failures = 0;
652 for (
auto p =
m_grid->points(); p; p.next()) {
653 const int i = p.i(), j = p.j();
655 int shelf_id = shelf_mask.
as_int(i, j);
657 if (box_mask.
as_int(i, j) == 1 and shelf_id > 0) {
659 const double pressure = physics.
pressure(ice_thickness(i, j));
661 T_star(i, j) = physics.
T_star(Soc_box0(i, j), Toc_box0(i, j), pressure);
663 auto Toc_box1 = physics.
Toc_box1(box1_area[shelf_id], T_star(i, j), Soc_box0(i, j), Toc_box0(i, j));
667 if (Toc_box1.failed) {
669 "PICO WARNING: negative square root argument at %d, %d\n"
670 " probably because of positive T_star=%f \n"
671 " Not aborting, but setting square root to 0... \n",
677 Toc(i, j) = Toc_box1.value;
678 Soc(i, j) = physics.
Soc_box1(Toc_box0(i, j), Soc_box0(i, j), Toc(i, j));
680 overturning(i, j) = physics.
overturning(Soc_box0(i, j), Soc(i, j), Toc_box0(i, j), Toc(i, j));
683 basal_melt_rate(i, j) = physics.
melt_rate(physics.
theta_pm(Soc(i, j), pressure), Toc(i, j));
684 basal_temperature(i, j) = physics.
T_pm(Soc(i, j), pressure);
689 if (n_Toc_failures > 0) {
691 "PICO WARNING: square-root argument for temperature calculation\n"
692 " has been negative in %d cases.\n",
714 std::vector<bool> use_beckmann_goosse(
m_n_shelves);
717 &Soc, &basal_melt_rate, &basal_temperature };
720 for (
int box = 2; box <=
m_n_boxes; ++box) {
728 use_beckmann_goosse[s] = (salinity[s] == 0.0 or
729 temperature[s] == 0.0 or
730 overturning[s] == 0.0);
733 std::vector<double> box_area;
736 int n_beckmann_goosse_cells = 0;
738 for (
auto p =
m_grid->points(); p; p.next()) {
739 const int i = p.i(), j = p.j();
741 int shelf_id = shelf_mask.
as_int(i, j);
743 if (box_mask.
as_int(i, j) == box and shelf_id > 0) {
745 if (use_beckmann_goosse[shelf_id]) {
746 n_beckmann_goosse_cells += 1;
752 S_previous = salinity[shelf_id],
753 T_previous = temperature[shelf_id],
754 overturning_box1 = overturning[shelf_id];
757 double pressure = physics.
pressure(ice_thickness(i, j));
760 T_star(i, j) = physics.
T_star(S_previous, T_previous, pressure);
761 Toc(i, j) = physics.
Toc(box_area[shelf_id], T_previous, T_star(i, j), overturning_box1, S_previous);
762 Soc(i, j) = physics.
Soc(S_previous, T_previous, Toc(i, j));
765 basal_melt_rate(i, j) = physics.
melt_rate(physics.
theta_pm(Soc(i, j), pressure), Toc(i, j));
766 basal_temperature(i, j) = physics.
T_pm(Soc(i, j), pressure);
771 n_beckmann_goosse_cells =
GlobalSum(
m_grid->com, n_beckmann_goosse_cells);
772 if (n_beckmann_goosse_cells > 0) {
775 "PICO WARNING: [box %d]: switched to the Beckmann Goosse (2003) model at %d locations\n"
776 " (no boundary data from the previous box)\n",
777 box, n_beckmann_goosse_cells);
815 std::vector<double> &result)
const {
829 for (
auto p =
m_grid->points(); p; p.next()) {
830 const int i = p.i(), j = p.j();
832 int shelf_id = shelf_mask.
as_int(i, j);
834 if (box_mask.
as_int(i, j) == box_id) {
835 n_cells_per_box[shelf_id] += 1;
836 result[shelf_id] += field(i, j);
850 if (n_cells[s] > 0) {
851 result[s] /=
static_cast<double>(n_cells[s]);
867 std::vector<double> &result)
const {
871 auto cell_area =
m_grid->cell_area();
873 for (
auto p =
m_grid->points(); p; p.next()) {
874 const int i = p.i(), j = p.j();
876 int shelf_id = shelf_mask.
as_int(i, j);
878 if (shelf_id > 0 and box_mask.
as_int(i, j) == box_id) {
879 result[shelf_id] += cell_area;
888 result[i] = result1[i];
const Time & time() 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
static Ptr wrap(const T &input)
High-level PISM I/O class.
array::CellType2 cell_type
array::Scalar2 ice_thickness
array::Scalar2 bed_elevation
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
stencils::Box< T > box(int i, int j) const
stencils::Star< T > star(int i, int j) const
void define(const File &file, io::Type default_type) const
Define variables corresponding to an Array in a file opened using file.
void write(const std::string &filename) const
std::shared_ptr< const Grid > grid() const
void set(double c)
Result: v[j] <- c for all j.
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.
bool floating_ice(int i, int j) const
"Cell type" mask. Adds convenience methods to array::Scalar.
int as_int(int i, int j) const
std::shared_ptr< array::Scalar > m_shelf_base_mass_flux
std::shared_ptr< array::Scalar > m_shelf_base_temperature
std::shared_ptr< array::Scalar > m_water_column_pressure
virtual void define_model_state_impl(const File &output) const
The default (empty implementation).
virtual DiagnosticList diagnostics_impl() const
virtual void write_model_state_impl(const File &output) const
The default (empty implementation).
A very rudimentary PISM ocean model.
const array::Scalar & continental_shelf_mask() const
const array::Scalar & ice_shelf_mask() const
const array::Scalar & ice_rise_mask() const
void update(const array::Scalar &bed_elevation, const array::CellType1 &cell_type)
const array::Scalar & basin_mask() const
const array::Scalar & box_mask() const
double pressure(double ice_thickness) const
double overturning_coeff() const
double ice_density() const
TocBox1 Toc_box1(double area, double T_star, double Soc_box0, double Toc_box0) const
double Toc(double box_area, double temperature, double T_star, double overturning, double salinity) const
double continental_shelf_depth() const
double melt_rate(double pm_point, double Toc) const
equation 8 in the PICO paper.
double overturning(double Soc_box0, double Soc, double Toc_box0, double Toc) const
equation 3 in the PICO paper. See also equation 4.
double theta_pm(double salinity, double pressure) const
double Soc_box1(double Toc_box0, double Soc_box0, double Toc) const
double T_pm(double salinity, double pressure) const
double melt_rate_beckmann_goosse(double pot_pm_point, double Toc) const
Beckmann & Goosse meltrate.
double T_star(double salinity, double temperature, double pressure) const
See equation A6 and lines before in PICO paper.
double Soc(double salinity, double temperature, double Toc) const
void set_ocean_input_fields(const PicoPhysics &physics, const array::Scalar &ice_thickness, const array::CellType1 &mask, const array::Scalar &basin_mask, const array::Scalar &shelf_mask, const std::vector< double > &basin_temperature, const std::vector< double > &basin_salinity, array::Scalar &Toc_box0, array::Scalar &Soc_box0) const
Set ocean ocean input from box 0 as boundary condition for box 1.
std::shared_ptr< array::Forcing > m_salinity_ocean
void write_model_state_impl(const File &output) const
The default (empty implementation).
MaxTimestep max_timestep_impl(double t) const
void process_box1(const PicoPhysics &physics, const array::Scalar &ice_thickness, const array::Scalar &shelf_mask, const array::Scalar &box_mask, const array::Scalar &Toc_box0, const array::Scalar &Soc_box0, array::Scalar &basal_melt_rate, array::Scalar &basal_temperature, array::Scalar &T_star, array::Scalar &Toc, array::Scalar &Soc, array::Scalar &overturning)
void compute_box_area(int box_id, const array::Scalar &shelf_mask, const array::Scalar &box_mask, std::vector< double > &result) const
void define_model_state_impl(const File &output) const
The default (empty implementation).
Pico(std::shared_ptr< const Grid > g)
array::Scalar1 m_basal_melt_rate
void update_impl(const Geometry &geometry, double t, double dt)
void compute_ocean_input_per_basin(const PicoPhysics &physics, const array::Scalar &basin_mask, const array::Scalar &continental_shelf_mask, const array::Scalar &salinity_ocean, const array::Scalar &theta_ocean, std::vector< double > &temperature, std::vector< double > &salinity) const
Compute temperature and salinity input from ocean data by averaging.
void compute_box_average(int box_id, const array::Scalar &field, const array::Scalar &shelf_mask, const array::Scalar &box_mask, std::vector< double > &result) const
std::shared_ptr< array::Forcing > m_theta_ocean
void process_other_boxes(const PicoPhysics &physics, const array::Scalar &ice_thickness, const array::Scalar &shelf_mask, const array::Scalar &box_mask, array::Scalar &basal_melt_rate, array::Scalar &basal_temperature, array::Scalar &T_star, array::Scalar &Toc, array::Scalar &Soc) const
void init_impl(const Geometry &geometry)
void beckmann_goosse(const PicoPhysics &physics, const array::Scalar &ice_thickness, const array::Scalar &shelf_mask, const array::CellType &cell_type, const array::Scalar &Toc_box0, const array::Scalar &Soc_box0, array::Scalar &basal_melt_rate, array::Scalar &basal_temperature, array::Scalar &Toc, array::Scalar &Soc)
std::map< std::string, Diagnostic::Ptr > diagnostics_impl() const
array::Scalar m_overturning
static const double beta_CC
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.
@ PISM_READONLY
open an existing file for reading only
bool ocean(int M)
An ocean cell (floating ice or ice-free).
static void extend_basal_melt_rates(const array::CellType1 &cell_type, array::Scalar1 &basal_melt_rate)
void compute_average_water_column_pressure(const Geometry &geometry, double ice_density, double water_density, double g, array::Scalar &result)
std::map< std::string, Diagnostic::Ptr > DiagnosticList
T combine(const T &a, const T &b)
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)