22 #include "pism/util/connected_components.hh"
23 #include "pism/util/IceModelVec2CellType.hh"
24 #include "pism/util/pism_utilities.hh"
25 #include "pism/util/petscwrappers/Vec.hh"
27 #include "pism/coupler/util/options.hh"
38 m_distance_gl(grid,
"pico_distance_gl",
WITH_GHOSTS),
39 m_distance_cf(grid,
"pico_distance_cf",
WITH_GHOSTS),
42 m_ice_rises(grid,
"pico_ice_rise_mask",
WITH_GHOSTS),
49 "ocean ice_rise continental_ice_sheet, floating_ice";
106 std::vector<std::string> neighbors;
107 for (
const auto &
n : p.second) {
110 std::string neighbor_list =
pism::join(neighbors,
", ");
111 m_log->message(3,
"PICO: basin %d neighbors: %s\n",
112 p.first, neighbor_list.c_str());
116 bool exclude_ice_rises =
m_config->get_flag(
"ocean.pico.exclude_ice_rises");
143 std::vector<int> cfs_in_basins_per_shelf(n_shelves*
m_n_basins, 0);
144 std::vector<int> most_shelf_cells_in_basin(n_shelves, 0);
146 most_shelf_cells_in_basin, cfs_in_basins_per_shelf);
149 most_shelf_cells_in_basin, cfs_in_basins_per_shelf, n_shelves,
152 double continental_shelf_depth =
m_config->get_number(
"ocean.pico.continental_shelf_depth");
158 int n_boxes =
static_cast<int>(
m_config->get_number(
"ocean.pico.number_of_boxes"));
181 int max_index =
static_cast<int>(mask.
range()[1]);
189 std::vector<double> area(max_index + 1, 0.0);
190 std::vector<double> area1(max_index + 1, 0.0);
196 const int i = p.i(), j = p.j();
198 int index = mask.
as_int(i, j);
200 if (index > max_index or index < 0) {
213 GlobalSum(grid->com, area.data(), area1.data(), area.size());
218 for (
unsigned int k = 0;
k < area.size(); ++
k) {
219 area[
k] = grid->cell_area() * area[
k];
225 int biggest_component = 0;
226 for (
unsigned int k = 0;
k < area.size(); ++
k) {
227 if (area[
k] > area[biggest_component]) {
228 biggest_component =
static_cast<int>(
k);
234 const int i = p.i(), j = p.j();
236 int component_index = mask.
as_int(i, j);
238 if (component_index == biggest_component) {
240 }
else if (component_index > 0) {
248 const int i = p.i(), j = p.j();
250 int component_index = mask.
as_int(i, j);
252 if (area[component_index] > threshold) {
254 }
else if (component_index > 0) {
271 if (
m_grid->rank() == 0) {
274 static_cast<int>(
m_grid->My()),
275 static_cast<int>(
m_grid->Mx()),
307 const int i = p.i(), j = p.j();
309 if (cell_type.
ocean(i, j)) {
326 if (
m_grid->rank() == 0) {
358 const int i = p.i(), j = p.j();
367 if (exclude_ice_rises) {
371 m_config->get_number(
"ocean.pico.maximum_ice_rise_area",
"m2"),
377 const int i = p.i(), j = p.j();
379 if (
m_tmp(i, j) == 0.0 and cell_type.
icy(i, j)) {
398 double bed_elevation_threshold,
403 const int i = p.i(), j = p.j();
407 if (bed_elevation(i, j) > bed_elevation_threshold) {
423 if (
m_grid->rank() == 0) {
439 const int i = p.i(), j = p.j();
441 if (
m_tmp(i, j) > 0.0) {
445 if (bed_elevation(i, j) > bed_elevation_threshold and
469 const int i = p.i(), j = p.j();
484 const int i = p.i(), j = p.j();
509 const int i = p.i(), j = p.j();
542 auto mark_as_neighbors = [&](
int b1,
int b2) {
548 auto adjacent = [&](
int b1,
int b2) {
549 return adjacency_matrix[b1 *
m_n_basins + b2] > 0;
555 const int i = p.i(), j = p.j();
562 if (B.ij == 0 or not next_to_icefront) {
570 B.n *=
static_cast<int>(j < (int)
m_grid->My() - 1);
571 B.e *=
static_cast<int>(i < (int)
m_grid->Mx() - 1);
572 B.s *=
static_cast<int>(j > 0);
573 B.w *=
static_cast<int>(i > 0);
576 auto M = cell_type.
star(i, j);
579 mark_as_neighbors(B.ij, B.n);
583 mark_as_neighbors(B.ij, B.s);
587 mark_as_neighbors(B.ij, B.e);
591 mark_as_neighbors(B.ij, B.w);
597 std::vector<int> tmp(adjacency_matrix.size(), 0);
599 static_cast<int>(tmp.size()));
601 adjacency_matrix = tmp;
605 std::map<int,std::set<int> > result;
607 for (
int b2 = b1 + 1; b2 <
m_n_basins; ++b2) {
608 if (adjacent(b1, b2)) {
609 result[b1].insert(b2);
610 result[b2].insert(b1);
626 std::vector<int> &most_shelf_cells_in_basin,
627 std::vector<int> &cfs_in_basins_per_shelf) {
629 std::vector<int> n_shelf_cells_per_basin(n_shelves *
m_n_basins,0);
631 std::vector<int> n_shelf_cells_per_basinr(n_shelves *
m_n_basins,0);
632 std::vector<int> cfs_in_basins_per_shelfr(n_shelves *
m_n_basins,0);
633 std::vector<int> most_shelf_cells_in_basinr(n_shelves, 0);
639 const int i = p.i(), j = p.j();
640 int s = shelf_mask.
as_int(i, j);
643 n_shelf_cells_per_basin[sb]++;
646 auto M = cell_type.
star(i, j);
651 if (cfs_in_basins_per_shelf[sb] != b) {
652 cfs_in_basins_per_shelf[sb] = b;
659 cfs_in_basins_per_shelfr.data(), n_shelves*
m_n_basins);
661 n_shelf_cells_per_basinr.data(), n_shelves*
m_n_basins);
663 cfs_in_basins_per_shelf = cfs_in_basins_per_shelfr;
664 n_shelf_cells_per_basin = n_shelf_cells_per_basinr;
666 for (
int s = 0; s < n_shelves; s++) {
667 int n_shelf_cells_per_basin_max = 0;
670 if (n_shelf_cells_per_basin[sb] > n_shelf_cells_per_basin_max) {
671 most_shelf_cells_in_basin[s] = b;
672 n_shelf_cells_per_basin_max = n_shelf_cells_per_basin[sb];
685 const std::map<
int, std::set<int> > &basin_neighbors,
686 const std::vector<int> &most_shelf_cells_in_basin,
687 const std::vector<int> &cfs_in_basins_per_shelf,
692 std::vector<int> n_shelf_cells_to_split(n_shelves *
m_n_basins, 0);
699 const int i = p.i(), j = p.j();
702 int s = shelf_mask.
as_int(i, j);
703 int b0 = most_shelf_cells_in_basin[s];
706 if (b !=
b0 and (not neighbors) and
707 cfs_in_basins_per_shelf[s *
m_n_basins + b] > 0) {
718 std::vector<int> tmp(n_shelves *
m_n_basins, 0);
722 n_shelf_cells_to_split = tmp;
726 std::vector<int> add_shelf_instance(n_shelves *
m_n_basins, 0);
727 int n_shelf_numbers_to_add = 0;
728 for (
int s = 0; s < n_shelves; s++) {
729 int b0 = most_shelf_cells_in_basin[s];
731 if (n_shelf_cells_to_split[s *
m_n_basins + b] > 0) {
732 n_shelf_numbers_to_add += 1;
733 add_shelf_instance[s *
m_n_basins + b] = n_shelves + n_shelf_numbers_to_add;
734 m_log->message(3,
"\nPICO, split ice shelf s=%d with bmax=%d "
735 "and b=%d and n=%d and si=%d\n", s,
b0, b,
743 const int i = p.i(), j = p.j();
746 int s = shelf_mask.
as_int(i, j);
747 if (add_shelf_instance[s *
m_n_basins + b] > 0) {
761 bool exclude_ice_rises,
775 const int i = p.i(), j = p.j();
778 ocean_mask.
as_int(i, j) == 1 or
779 (exclude_ice_rises and ice_rises.
as_int(i, j) ==
RISE)) {
783 bool neighbor_to_land =
793 if (neighbor_to_land) {
816 bool exclude_ice_rises,
826 const int i = p.i(), j = p.j();
829 ocean_mask.
as_int(i, j) == 1 or
830 (exclude_ice_rises and ice_rises.
as_int(i, j) ==
RISE)) {
834 auto M = ocean_mask.
star(i, j);
836 if (M.n == 2 or M.e == 2 or M.s == 2 or M.w == 2) {
879 double current_label = 1;
880 double continue_loop = 1;
881 while (continue_loop != 0) {
886 const int i = p.i(), j = p.j();
888 if (mask.
as_int(i, j) == 0) {
890 auto R = mask.
star(i, j);
893 (R.n == current_label or R.s == current_label or
894 R.e == current_label or R.w == current_label)) {
897 mask(i, j) = current_label + 1;
906 continue_loop =
GlobalMax(grid->com, continue_loop);
920 int n_shelves =
static_cast<int>(shelf_mask.
range()[1]) + 1;
922 std::vector<double> GL_distance_max(n_shelves, 0.0);
923 std::vector<double> GL_distance_max1(n_shelves, 0.0);
924 std::vector<double> CF_distance_max(n_shelves, 0.0);
925 std::vector<double> CF_distance_max1(n_shelves, 0.0);
928 const int i = p.i(), j = p.j();
930 int shelf_id = shelf_mask.
as_int(i, j);
931 assert(shelf_id >= 0);
932 assert(shelf_id < n_shelves + 1);
939 if (D_gl(i, j) > GL_distance_max[shelf_id]) {
940 GL_distance_max[shelf_id] = D_gl(i, j);
943 if (D_cf(i, j) > CF_distance_max[shelf_id]) {
944 CF_distance_max[shelf_id] = D_cf(i, j);
949 GlobalMax(
m_grid->com, GL_distance_max.data(), GL_distance_max1.data(), n_shelves);
950 GlobalMax(
m_grid->com, CF_distance_max.data(), CF_distance_max1.data(), n_shelves);
952 GL_distance_max = GL_distance_max1;
953 CF_distance_max = CF_distance_max1;
955 double GL_distance_ref = *std::max_element(GL_distance_max.begin(), GL_distance_max.end());
959 std::vector<int> n_boxes(n_shelves, 0);
961 const double zeta = 0.5;
963 for (
int k = 0;
k < n_shelves; ++
k) {
964 n_boxes[
k] = n_min + round(pow((GL_distance_max[
k] / GL_distance_ref), zeta) * (max_number_of_boxes - n_min));
966 n_boxes[
k] =
std::min(n_boxes[
k], max_number_of_boxes);
972 const int i = p.i(), j = p.j();
974 int d_gl = D_gl.
as_int(i, j);
975 int d_cf = D_cf.
as_int(i, j);
977 if (shelf_mask.
as_int(i, j) > 0 and d_gl > 0.0 and d_cf > 0.0) {
978 int shelf_id = shelf_mask.
as_int(i, j);
979 int n = n_boxes[shelf_id];
983 double r = d_gl / (double)(d_gl + d_cf);
985 double C = pow(1.0 - r, 2.0);
986 for (
int k = 0;
k <
n; ++
k) {
987 if ((
n -
k - 1) / (
double)
n <=
C and
C <= (
n -
k) / (
double)
n) {
Makes sure that we call begin_access() and end_access() for all accessed IceModelVecs.
const Config::ConstPtr m_config
configuration database used by this component
const Logger::ConstPtr m_log
logger (for easy access)
const IceGrid::ConstPtr m_grid
grid used by this component
A class defining a common interface for most PISM sub-models.
std::shared_ptr< const IceGrid > ConstPtr
bool next_to_ice(int i, int j) const
Ice-free margin (at least one of four neighbors has ice).
bool icy(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
"Cell type" mask. Adds convenience methods to IceModelVec2Int.
int as_int(int i, int j) const
stencils::Star< int > star(int i, int j) const
A simple class "hiding" the fact that the mask is stored as floating-point scalars (instead of intege...
void copy_from(const IceModelVec2S &source)
void update_ghosts()
Updates ghost points.
unsigned int stencil_width() const
Get the stencil width of the current IceModelVec. Returns 0 if ghosts are not available.
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
void set_attrs(const std::string &pism_intent, const std::string &long_name, const std::string &units, const std::string &glaciological_units, const std::string &standard_name, unsigned int component)
Sets NetCDF attributes of an IceModelVec object.
void regrid(const std::string &filename, RegriddingFlag flag, double default_value=0.0)
void set(double c)
Result: v[j] <- c for all j.
void get_from_proc0(petsc::Vec &onp0)
Gets a local IceModelVec2 from processor 0.
IceGrid::ConstPtr grid() const
void put_on_proc0(petsc::Vec &onp0) const
Puts a local IceModelVec2S on processor 0.
std::array< double, 2 > range() const
Result: min <- min(v[j]), max <- max(v[j]).
std::shared_ptr< petsc::Vec > allocate_proc0_copy() const
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
void compute_box_mask(const IceModelVec2Int &D_gl, const IceModelVec2Int &D_cf, const IceModelVec2Int &shelf_mask, int max_number_of_boxes, IceModelVec2Int &result)
std::shared_ptr< petsc::Vec > m_tmp_p0
void compute_ice_shelf_mask(const IceModelVec2Int &ice_rise_mask, const IceModelVec2Int &lake_mask, IceModelVec2Int &result)
const IceModelVec2Int & continental_shelf_mask() const
void split_ice_shelves(const IceModelVec2CellType &cell_type, const IceModelVec2Int &basin_mask, const std::map< int, 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, IceModelVec2Int &shelf_mask)
void compute_continental_shelf_mask(const IceModelVec2S &bed_elevation, const IceModelVec2Int &ice_rise_mask, double bed_elevation_threshold, IceModelVec2Int &result)
IceModelVec2Int m_distance_gl
const IceModelVec2Int & basin_mask() const
IceModelVec2Int m_continental_shelf
void compute_ice_rises(const IceModelVec2CellType &cell_type, bool exclude_ice_rises, IceModelVec2Int &result)
IceModelVec2Int m_ice_rises
PicoGeometry(IceGrid::ConstPtr grid)
void identify_calving_front_connection(const IceModelVec2CellType &cell_type, const IceModelVec2Int &basin_mask, const IceModelVec2Int &shelf_mask, int n_shelves, std::vector< int > &most_shelf_cells_in_basin, std::vector< int > &cfs_in_basins_per_shelf)
void compute_ocean_mask(const IceModelVec2CellType &cell_type, IceModelVec2Int &result)
void compute_distances_cf(const IceModelVec2Int &ocean_mask, const IceModelVec2Int &ice_rises, bool exclude_ice_rises, IceModelVec2Int &result)
const IceModelVec2Int & ice_shelf_mask() const
void compute_distances_gl(const IceModelVec2Int &ocean_mask, const IceModelVec2Int &ice_rises, bool exclude_ice_rises, IceModelVec2Int &result)
void update(const IceModelVec2S &bed_elevation, const IceModelVec2CellType &cell_type)
IceModelVec2Int m_lake_mask
IceModelVec2Int m_ocean_mask
std::map< int, std::set< int > > m_basin_neighbors
void compute_lakes(const IceModelVec2CellType &cell_type, IceModelVec2Int &result)
const IceModelVec2Int & box_mask() const
IceModelVec2Int m_ice_shelves
IceModelVec2Int m_basin_mask
const IceModelVec2Int & ice_rise_mask() const
std::map< int, std::set< int > > basin_neighbors(const IceModelVec2CellType &cell_type, const IceModelVec2Int &basin_mask)
IceModelVec2Int m_distance_cf
Wrapper around VecGetArray and VecRestoreArray.
void label_connected_components(double *image, int nrows, int ncols, bool identify_icebergs, int mask_grounded, int first_label)
#define PISM_ERROR_LOCATION
bool ice_free_ocean(int M)
bool ocean(int M)
An ocean cell (floating ice or ice-free).
static void relabel(RelabelingType type, double threshold, IceModelVec2Int &mask)
void eikonal_equation(IceModelVec2Int &mask)
double max(const IceModelVec2S &input)
Finds maximum over all the values in an IceModelVec2S object. Ignores ghosts.
void GlobalMax(MPI_Comm comm, double *local, double *result, int count)
std::string printf(const char *format,...)
double min(const IceModelVec2S &input)
Finds minimum over all the values in an IceModelVec2S object. Ignores ghosts.
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)
bool grid_edge(const IceGrid &grid, int i, int j)