22#include "pism/coupler/ocean/PicoGeometry.hh"
23#include "pism/util/connected_components/label_components.hh"
24#include "pism/util/array/CellType.hh"
25#include "pism/util/pism_utilities.hh"
27#include "pism/coupler/util/options.hh"
28#include "pism/util/Interpolation1D.hh"
29#include "pism/util/Profiling.hh"
30#include "pism/util/Logger.hh"
31#include "pism/util/io/IO_Flags.hh"
38 m_continental_shelf(grid,
"pico_contshelf_mask"),
39 m_boxes(grid,
"pico_box_mask"),
40 m_ice_shelves(grid,
"pico_shelf_mask"),
41 m_basin_mask(m_grid,
"basins"),
42 m_distance_gl(grid,
"pico_distance_gl"),
43 m_distance_cf(grid,
"pico_distance_cf"),
44 m_ocean_mask(grid,
"pico_ocean_mask"),
45 m_lake_mask(grid,
"pico_lake_mask"),
46 m_ice_rises(grid,
"pico_ice_rise_mask"),
47 m_tmp(grid,
"temporary_storage") {
64 "ocean ice_rise continental_ice_sheet, floating_ice";
117 for (
int basin_id = 1; basin_id <
m_n_basins; ++basin_id) {
119 if (not set.empty()) {
120 std::vector<std::string> neighbors;
121 for (
const auto &
n : set) {
124 std::string neighbor_list =
pism::join(neighbors,
", ");
125 m_log->message(3,
"PICO: basin %d neighbors: %s\n", basin_id, neighbor_list.c_str());
130 bool exclude_ice_rises =
m_config->get_flag(
"ocean.pico.exclude_ice_rises");
161 std::vector<int> cfs_in_basins_per_shelf(n_shelves*
m_n_basins, 0);
162 std::vector<int> most_shelf_cells_in_basin(n_shelves, 0);
164 most_shelf_cells_in_basin, cfs_in_basins_per_shelf);
167 most_shelf_cells_in_basin, cfs_in_basins_per_shelf, n_shelves,
170 double continental_shelf_depth =
m_config->get_number(
"ocean.pico.continental_shelf_depth");
176 int n_boxes =
static_cast<int>(
m_config->get_number(
"ocean.pico.number_of_boxes"));
197 auto grid = mask.
grid();
199 int max_index =
static_cast<int>(
array::max(mask));
207 std::vector<double> area(max_index + 1, 0.0);
208 std::vector<double> area1(max_index + 1, 0.0);
213 for (
auto p : grid->points()) {
214 const int i = p.i(), j = p.j();
216 int index = mask.
as_int(i, j);
218 if (index > max_index or index < 0) {
231 GlobalSum(grid->com, area.data(), area1.data(),
static_cast<int>(area.size()));
236 for (
unsigned int k = 0;
k < area.size(); ++
k) {
237 area[
k] = grid->cell_area() * area[
k];
243 int biggest_component = 0;
244 for (
unsigned int k = 0;
k < area.size(); ++
k) {
245 if (area[
k] > area[biggest_component]) {
246 biggest_component =
static_cast<int>(
k);
251 for (
auto p : grid->points()) {
252 const int i = p.i(), j = p.j();
254 int component_index = mask.
as_int(i, j);
256 if (component_index == biggest_component) {
258 }
else if (component_index > 0) {
265 for (
auto p : grid->points()) {
266 const int i = p.i(), j = p.j();
268 int component_index = mask.
as_int(i, j);
270 if (area[component_index] > threshold) {
272 }
else if (component_index > 0) {
298 int reachable_from_domain_edge = 2;
303 for (
auto p :
grid->points()) {
304 const int i = p.i(), j = p.j();
306 if (cell_type.
ocean(i, j)) {
307 m_tmp(i, j) = floating;
310 m_tmp(i, j) = reachable_from_domain_edge;
313 m_tmp(i, j) = background;
345 for (
auto p :
m_grid->points()) {
346 const int i = p.i(), j = p.j();
356 if (exclude_ice_rises) {
365 for (
auto p :
m_grid->points()) {
366 const int i = p.i(), j = p.j();
368 if (
m_tmp(i, j) == 0.0 and cell_type.
icy(i, j)) {
389 double bed_elevation_threshold,
395 for (
auto p :
m_grid->points()) {
396 const int i = p.i(), j = p.j();
400 if (bed_elevation(i, j) > bed_elevation_threshold) {
418 for (
auto p :
m_grid->points()) {
419 const int i = p.i(), j = p.j();
421 if (
m_tmp(i, j) > 0.0) {
451 for (
auto p :
m_grid->points()) {
452 const int i = p.i(), j = p.j();
468 for (
auto p :
m_grid->points()) {
469 const int i = p.i(), j = p.j();
497 for (
auto p :
m_grid->points()) {
498 const int i = p.i(), j = p.j();
535 auto mark_as_neighbors = [&](
int b1,
int b2) {
541 auto adjacent = [&](
int b1,
int b2) {
542 return adjacency_matrix[b1 *
m_n_basins + b2] > 0;
547 for (
auto p :
m_grid->points()) {
548 const int i = p.i(), j = p.j();
555 if (B.c == 0 or not next_to_icefront) {
563 B.n *=
static_cast<int>(j < (
int)
m_grid->My() - 1);
564 B.e *=
static_cast<int>(i < (
int)
m_grid->Mx() - 1);
565 B.s *=
static_cast<int>(j > 0);
566 B.w *=
static_cast<int>(i > 0);
571 if (ice_free_ocean(M.n)) {
572 mark_as_neighbors(B.c, B.n);
575 if (ice_free_ocean(M.s)) {
576 mark_as_neighbors(B.c, B.s);
579 if (ice_free_ocean(M.e)) {
580 mark_as_neighbors(B.c, B.e);
583 if (ice_free_ocean(M.w)) {
584 mark_as_neighbors(B.c, B.w);
590 std::vector<int> tmp(adjacency_matrix.size(), 0);
592 static_cast<int>(tmp.size()));
594 adjacency_matrix = tmp;
598 std::vector<std::set<int> > result(
m_n_basins);
600 for (
int b2 = b1 + 1; b2 <
m_n_basins; ++b2) {
601 if (adjacent(b1, b2)) {
602 result[b1].insert(b2);
603 result[b2].insert(b1);
619 std::vector<int> &most_shelf_cells_in_basin,
620 std::vector<int> &cfs_in_basins_per_shelf) {
622 std::vector<int> n_shelf_cells_per_basin(n_shelves *
m_n_basins,0);
624 std::vector<int> n_shelf_cells_per_basinr(n_shelves *
m_n_basins,0);
625 std::vector<int> cfs_in_basins_per_shelfr(n_shelves *
m_n_basins,0);
626 std::vector<int> most_shelf_cells_in_basinr(n_shelves, 0);
631 for (
auto p :
m_grid->points()) {
632 const int i = p.i(), j = p.j();
633 int s = shelf_mask.
as_int(i, j);
636 n_shelf_cells_per_basin[sb]++;
639 auto M = cell_type.
star(i, j);
644 if (cfs_in_basins_per_shelf[sb] != b) {
645 cfs_in_basins_per_shelf[sb] = b;
652 cfs_in_basins_per_shelfr.data(), n_shelves*
m_n_basins);
654 n_shelf_cells_per_basinr.data(), n_shelves*
m_n_basins);
656 cfs_in_basins_per_shelf = cfs_in_basins_per_shelfr;
657 n_shelf_cells_per_basin = n_shelf_cells_per_basinr;
659 for (
int s = 0; s < n_shelves; s++) {
660 int n_shelf_cells_per_basin_max = 0;
663 if (n_shelf_cells_per_basin[sb] > n_shelf_cells_per_basin_max) {
664 most_shelf_cells_in_basin[s] = b;
665 n_shelf_cells_per_basin_max = n_shelf_cells_per_basin[sb];
678 const std::vector<std::set<int> > &basin_neighbors,
679 const std::vector<int> &most_shelf_cells_in_basin,
680 const std::vector<int> &cfs_in_basins_per_shelf,
688 std::vector<int> n_shelf_cells_to_split(n_shelves *
m_n_basins, 0);
692 for (
auto p :
m_grid->points()) {
693 const int i = p.i(), j = p.j();
696 int shelf = shelf_mask.
as_int(i, j);
697 int b0 = most_shelf_cells_in_basin[shelf];
701 if (basin !=
b0 and (not neighbors) and
702 cfs_in_basins_per_shelf[shelf *
m_n_basins + basin] > 0) {
703 n_shelf_cells_to_split[shelf *
m_n_basins + basin]++;
709 std::vector<int> tmp(n_shelves *
m_n_basins, 0);
713 n_shelf_cells_to_split = tmp;
717 std::vector<int> add_shelf_instance(n_shelves *
m_n_basins, 0);
718 int n_shelf_numbers_to_add = 0;
719 for (
int s = 0; s < n_shelves; s++) {
720 int b0 = most_shelf_cells_in_basin[s];
722 if (n_shelf_cells_to_split[s *
m_n_basins + b] > 0) {
723 n_shelf_numbers_to_add += 1;
724 add_shelf_instance[s *
m_n_basins + b] = n_shelves + n_shelf_numbers_to_add;
725 m_log->message(3,
"\nPICO, split ice shelf s=%d with bmax=%d "
726 "and b=%d and n=%d and si=%d\n", s,
b0, b,
733 for (
auto p :
m_grid->points()) {
734 const int i = p.i(), j = p.j();
737 int s = shelf_mask.
as_int(i, j);
738 if (add_shelf_instance[s *
m_n_basins + b] > 0) {
752 bool exclude_ice_rises,
765 for (
auto p :
m_grid->points()) {
766 const int i = p.i(), j = p.j();
769 ocean_mask.
as_int(i, j) == 1 or
770 (exclude_ice_rises and ice_rises.
as_int(i, j) ==
RISE)) {
774 bool neighbor_to_land =
784 if (neighbor_to_land) {
809 bool exclude_ice_rises,
818 for (
auto p :
m_grid->points()) {
819 const int i = p.i(), j = p.j();
822 ocean_mask.
as_int(i, j) == 1 or
823 (exclude_ice_rises and ice_rises.
as_int(i, j) ==
RISE)) {
827 auto M = ocean_mask.
star(i, j);
829 if (M.n == 2 or M.e == 2 or M.s == 2 or M.w == 2) {
888 auto grid = mask.
grid();
890 std::queue<details::Cell> unmarked_cells;
894 for (
auto p : grid->points()) {
895 const int i = p.i(), j = p.j();
897 if (mask.
as_int(i, j) == 0) {
899 auto R = mask.
star(i, j);
901 if (R.c == 0 and (R.n == 1 or R.s == 1 or R.e == 1 or R.w == 1)) {
906 unmarked_cells.push({i, j + 1});
909 unmarked_cells.push({i, j - 1});
912 unmarked_cells.push({i + 1, j});
915 unmarked_cells.push({i - 1, j});
921 int global_x_size = (
int)grid->Mx();
922 int global_y_size = (
int)grid->My();
924 int x_size = grid->xm();
925 int x_start = grid->xs();
926 int y_size = grid->ym();
927 int y_start = grid->ys();
929 int continue_loop = 1;
930 while (continue_loop != 0) {
945 while (not unmarked_cells.empty()) {
947 auto cell = unmarked_cells.front();
948 unmarked_cells.pop();
951 if ((cell.j >= y_start and cell.j < y_start + y_size) and
952 (cell.i >= x_start and cell.i < x_start + x_size)) {
956 if (cell.j + 1 < global_y_size) {
957 north_cell = mask.
as_int(cell.i, cell.j + 1);
961 south_cell = mask.
as_int(cell.i, cell.j - 1);
964 if (cell.i + 1 < global_x_size) {
965 east_cell = mask.
as_int(cell.i + 1, cell.j);
969 west_cell = mask.
as_int(cell.i - 1, cell.j);
973 if (north_cell > 0 or south_cell > 0 or east_cell > 0 or west_cell > 0) {
980 int min_label = 2 * (
int)std::max(global_x_size, global_y_size);
981 if (north_cell > 0) {
982 min_label = std::min(min_label, north_cell);
984 if (south_cell > 0) {
985 min_label = std::min(min_label, south_cell);
988 min_label = std::min(min_label, east_cell);
991 min_label = std::min(min_label, west_cell);
995 int center_cell = mask.
as_int(cell.i, cell.j);
996 if (center_cell != 0) {
997 min_label = std::min(min_label, center_cell);
1002 if (center_cell == 0 or center_cell > min_label + 1) {
1003 mask(cell.i, cell.j) = min_label + 1;
1007 if (north_cell == 0 or north_cell > min_label + 2) {
1008 unmarked_cells.push({cell.i, cell.j + 1});
1010 if (south_cell == 0 or south_cell > min_label + 2) {
1011 unmarked_cells.push({cell.i, cell.j - 1});
1013 if (east_cell == 0 or east_cell > min_label + 2) {
1014 unmarked_cells.push({cell.i + 1, cell.j});
1016 if (west_cell == 0 or west_cell > min_label + 2) {
1017 unmarked_cells.push({cell.i - 1, cell.j});
1028 auto add_ij = [&mask](
int i,
int j,
int i_n,
int j_n) {
1029 int current = mask.
as_int(i, j);
1031 int neighbor = mask.
as_int(i_n, j_n);
1032 if ((neighbor > 0) and (current == 0 or current > neighbor + 1)) {
1045 for (
auto i = x_start; i < x_start + x_size; i++) {
1046 if (add_ij(i, j, i, j - 1)) {
1047 unmarked_cells.push({ i, j });
1056 int j = y_start + y_size - 1;
1057 if (j != global_y_size - 1) {
1059 for (
auto i = x_start; i < x_start + x_size; i++) {
1060 if (add_ij(i, j, i, j + 1)) {
1061 unmarked_cells.push({ i, j });
1073 for (
auto j = y_start; j < y_start + y_size; j++) {
1074 if (add_ij(i, j, i - 1, j)) {
1075 unmarked_cells.push({ i, j });
1083 int i = x_start + x_size - 1;
1084 if (i != global_x_size - 1) {
1086 for (
auto j = y_start; j < y_start + y_size; j++) {
1087 if (add_ij(i, j, i + 1, j)) {
1088 unmarked_cells.push({ i, j });
1096 if (not unmarked_cells.empty()) {
1099 continue_loop =
GlobalMax(grid->com, continue_loop);
1113 int n_shelves =
static_cast<int>(
array::max(shelf_mask)) + 1;
1115 std::vector<double> GL_distance_max(n_shelves, 0.0);
1116 std::vector<double> GL_distance_max1(n_shelves, 0.0);
1117 std::vector<double> CF_distance_max(n_shelves, 0.0);
1118 std::vector<double> CF_distance_max1(n_shelves, 0.0);
1120 for (
auto p :
m_grid->points()) {
1121 const int i = p.i(), j = p.j();
1123 int shelf_id = shelf_mask.
as_int(i, j);
1124 assert(shelf_id >= 0);
1125 assert(shelf_id < n_shelves + 1);
1127 if (shelf_id == 0) {
1132 if (D_gl(i, j) > GL_distance_max[shelf_id]) {
1133 GL_distance_max[shelf_id] = D_gl(i, j);
1136 if (D_cf(i, j) > CF_distance_max[shelf_id]) {
1137 CF_distance_max[shelf_id] = D_cf(i, j);
1142 GlobalMax(
m_grid->com, GL_distance_max.data(), GL_distance_max1.data(), n_shelves);
1143 GlobalMax(
m_grid->com, CF_distance_max.data(), CF_distance_max1.data(), n_shelves);
1145 GL_distance_max = GL_distance_max1;
1146 CF_distance_max = CF_distance_max1;
1148 double GL_distance_ref = *std::max_element(GL_distance_max.begin(), GL_distance_max.end());
1152 std::vector<int> n_boxes(n_shelves, 0);
1153 const int n_min = 1;
1154 const double zeta = 0.5;
1156 for (
int k = 0;
k < n_shelves; ++
k) {
1157 n_boxes[
k] = n_min + round(pow((GL_distance_max[
k] / GL_distance_ref), zeta) * (max_number_of_boxes - n_min));
1159 n_boxes[
k] = std::min(n_boxes[
k], max_number_of_boxes);
1164 for (
auto p :
m_grid->points()) {
1165 const int i = p.i(), j = p.j();
1167 int d_gl = D_gl.
as_int(i, j);
1168 int d_cf = D_cf.
as_int(i, j);
1170 if (shelf_mask.
as_int(i, j) > 0 and d_gl > 0.0 and d_cf > 0.0) {
1171 int shelf_id = shelf_mask.
as_int(i, j);
1172 int n = n_boxes[shelf_id];
1176 double r = d_gl / (
double)(d_gl + d_cf);
1178 double C = pow(1.0 - r, 2.0);
1179 for (
int k = 0;
k <
n; ++
k) {
1180 if ((
n -
k - 1) / (
double)
n <= C and C <= (
n -
k) / (
double)
n) {
1181 result(i, j) = std::min(d_gl,
k + 1);
std::shared_ptr< const Grid > grid() const
std::shared_ptr< const Config > m_config
configuration database used by this component
const std::shared_ptr< const Grid > m_grid
grid used by this component
const Profiling & profiling() const
std::shared_ptr< const Logger > m_log
logger (for easy access)
A class defining a common interface for most PISM sub-models.
void failed()
Indicates a failure of a parallel section.
void begin(const char *name) const
void end(const char *name) const
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.
void copy_from(const Array2D< T > &source)
stencils::Star< T > star(int i, int j) const
void set_interpolation_type(InterpolationType type)
std::shared_ptr< const Grid > grid() const
void set(double c)
Result: v[j] <- c for all j.
void regrid(const std::string &filename, io::Default default_value)
void update_ghosts()
Updates ghost points.
VariableMetadata & metadata(unsigned int N=0)
Returns a reference to the VariableMetadata object containing metadata for the compoment N.
bool next_to_ice(int i, int j) const
Ice-free margin (at least one of four neighbors has ice).
stencils::Star< int > star_int(int i, int j) const
bool ice_free_ocean(int i, int j) const
bool ocean(int i, int j) const
bool grounded(int i, int j) const
bool icy(int i, int j) const
"Cell type" mask. Adds convenience methods to array::Scalar.
int as_int(int i, int j) const
stencils::Star< int > star_int(int i, int j) const
const array::Scalar & continental_shelf_mask() const
void split_ice_shelves(const array::CellType &cell_type, const array::Scalar &basin_mask, const std::vector< std::set< int > > &basin_neighbors, const std::vector< int > &most_shelf_cells_in_basin, const std::vector< int > &cfs_in_basins_per_shelf, int n_shelves, array::Scalar &shelf_mask)
array::Scalar m_continental_shelf
void compute_box_mask(const array::Scalar &D_gl, const array::Scalar &D_cf, const array::Scalar &shelf_mask, int max_number_of_boxes, array::Scalar &result)
array::Scalar1 m_ice_rises
array::Scalar m_lake_mask
PicoGeometry(std::shared_ptr< const Grid > grid)
void compute_ocean_mask(const array::CellType &cell_type, array::Scalar &result)
const array::Scalar & ice_shelf_mask() const
array::Scalar1 m_distance_gl
void compute_distances_gl(const array::Scalar &ocean_mask, const array::Scalar1 &ice_rises, bool exclude_ice_rises, array::Scalar1 &result)
void compute_distances_cf(const array::Scalar1 &ocean_mask, const array::Scalar &ice_rises, bool exclude_ice_rises, array::Scalar1 &result)
std::vector< std::set< int > > basin_neighbors(const array::CellType1 &cell_type, const array::Scalar1 &basin_mask)
const array::Scalar & ice_rise_mask() const
void compute_ice_shelf_mask(const array::Scalar &ice_rise_mask, const array::Scalar &lake_mask, array::Scalar &result)
array::Scalar1 m_basin_mask
void compute_ice_rises(const array::CellType &cell_type, bool exclude_ice_rises, array::Scalar &result)
array::Scalar1 m_ocean_mask
std::vector< std::set< int > > m_basin_neighbors
array::Scalar m_ice_shelves
void compute_lakes(const array::CellType &cell_type, array::Scalar &result)
void update(const array::Scalar &bed_elevation, const array::CellType1 &cell_type)
void compute_continental_shelf_mask(const array::Scalar &bed_elevation, const array::Scalar &ice_rise_mask, double bed_elevation_threshold, array::Scalar &result)
const array::Scalar & basin_mask() const
const array::Scalar & box_mask() const
array::Scalar1 m_distance_cf
void identify_calving_front_connection(const array::CellType1 &cell_type, const array::Scalar &basin_mask, const array::Scalar &shelf_mask, int n_shelves, std::vector< int > &most_shelf_cells_in_basin, std::vector< int > &cfs_in_basins_per_shelf)
#define PISM_ERROR_LOCATION
double max(const array::Scalar &input)
Finds maximum over all the values in an array::Scalar object. Ignores ghosts.
void label_isolated(array::Scalar1 &mask, int reachable)
void label(array::Scalar1 &mask)
bool domain_edge(const Grid &grid, int i, int j)
bool ice_free_ocean(int M)
bool ocean(int M)
An ocean cell (floating ice or ice-free).
void eikonal_equation(array::Scalar1 &mask)
static void relabel(RelabelingType type, double threshold, array::Scalar &mask)
void GlobalMax(MPI_Comm comm, double *local, double *result, int count)
std::string printf(const char *format,...)
std::string join(const std::vector< std::string > &strings, const std::string &separator)
Concatenate strings, inserting separator between elements.
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)