21 #include "pism/coupler/ocean/PicoGeometry.hh"
22 #include "pism/util/label_components.hh"
23 #include "pism/util/array/CellType.hh"
24 #include "pism/util/pism_utilities.hh"
25 #include "pism/util/petscwrappers/Vec.hh"
27 #include "pism/coupler/util/options.hh"
28 #include "pism/util/interpolation.hh"
35 m_continental_shelf(grid,
"pico_contshelf_mask"),
36 m_boxes(grid,
"pico_box_mask"),
37 m_ice_shelves(grid,
"pico_shelf_mask"),
38 m_basin_mask(m_grid,
"basins"),
39 m_distance_gl(grid,
"pico_distance_gl"),
40 m_distance_cf(grid,
"pico_distance_cf"),
41 m_ocean_mask(grid,
"pico_ocean_mask"),
42 m_lake_mask(grid,
"pico_lake_mask"),
43 m_ice_rises(grid,
"pico_ice_rise_mask"),
44 m_tmp(grid,
"temporary_storage") {
61 "ocean ice_rise continental_ice_sheet, floating_ice";
116 for (
int basin_id = 1; basin_id <
m_n_basins; ++basin_id) {
118 if (not set.empty()) {
119 std::vector<std::string> neighbors;
120 for (
const auto &
n : set) {
123 std::string neighbor_list =
pism::join(neighbors,
", ");
124 m_log->message(3,
"PICO: basin %d neighbors: %s\n", basin_id, neighbor_list.c_str());
129 bool exclude_ice_rises =
m_config->get_flag(
"ocean.pico.exclude_ice_rises");
156 std::vector<int> cfs_in_basins_per_shelf(n_shelves*
m_n_basins, 0);
157 std::vector<int> most_shelf_cells_in_basin(n_shelves, 0);
159 most_shelf_cells_in_basin, cfs_in_basins_per_shelf);
162 most_shelf_cells_in_basin, cfs_in_basins_per_shelf, n_shelves,
165 double continental_shelf_depth =
m_config->get_number(
"ocean.pico.continental_shelf_depth");
171 int n_boxes =
static_cast<int>(
m_config->get_number(
"ocean.pico.number_of_boxes"));
192 auto grid = mask.
grid();
194 int max_index =
static_cast<int>(
array::max(mask));
202 std::vector<double> area(max_index + 1, 0.0);
203 std::vector<double> area1(max_index + 1, 0.0);
208 for (
auto p = grid->points(); p; p.next()) {
209 const int i = p.i(), j = p.j();
211 int index = mask.
as_int(i, j);
213 if (index > max_index or index < 0) {
226 GlobalSum(grid->com, area.data(), area1.data(), area.size());
231 for (
unsigned int k = 0;
k < area.size(); ++
k) {
232 area[
k] = grid->cell_area() * area[
k];
238 int biggest_component = 0;
239 for (
unsigned int k = 0;
k < area.size(); ++
k) {
240 if (area[
k] > area[biggest_component]) {
241 biggest_component =
static_cast<int>(
k);
246 for (
auto p = grid->points(); p; p.next()) {
247 const int i = p.i(), j = p.j();
249 int component_index = mask.
as_int(i, j);
251 if (component_index == biggest_component) {
253 }
else if (component_index > 0) {
260 for (
auto p = grid->points(); p; p.next()) {
261 const int i = p.i(), j = p.j();
263 int component_index = mask.
as_int(i, j);
265 if (area[component_index] > threshold) {
267 }
else if (component_index > 0) {
293 for (
auto p =
grid->points(); p; p.next()) {
294 const int i = p.i(), j = p.j();
296 if (cell_type.
ocean(i, j)) {
329 for (
auto p =
m_grid->points(); p; p.next()) {
330 const int i = p.i(), j = p.j();
339 if (exclude_ice_rises) {
343 m_config->get_number(
"ocean.pico.maximum_ice_rise_area",
"m2"),
348 for (
auto p =
m_grid->points(); p; p.next()) {
349 const int i = p.i(), j = p.j();
351 if (
m_tmp(i, j) == 0.0 and cell_type.
icy(i, j)) {
370 double bed_elevation_threshold,
374 for (
auto p =
m_grid->points(); p; p.next()) {
375 const int i = p.i(), j = p.j();
379 if (bed_elevation(i, j) > bed_elevation_threshold) {
395 for (
auto p =
m_grid->points(); p; p.next()) {
396 const int i = p.i(), j = p.j();
398 if (
m_tmp(i, j) > 0.0) {
402 if (bed_elevation(i, j) > bed_elevation_threshold and
425 for (
auto p =
m_grid->points(); p; p.next()) {
426 const int i = p.i(), j = p.j();
440 for (
auto p =
m_grid->points(); p; p.next()) {
441 const int i = p.i(), j = p.j();
465 for (
auto p =
m_grid->points(); p; p.next()) {
466 const int i = p.i(), j = p.j();
499 auto mark_as_neighbors = [&](
int b1,
int b2) {
505 auto adjacent = [&](
int b1,
int b2) {
506 return adjacency_matrix[b1 *
m_n_basins + b2] > 0;
511 for (
auto p =
m_grid->points(); p; p.next()) {
512 const int i = p.i(), j = p.j();
519 if (B.c == 0 or not next_to_icefront) {
527 B.n *=
static_cast<int>(j < (int)
m_grid->My() - 1);
528 B.e *=
static_cast<int>(i < (int)
m_grid->Mx() - 1);
529 B.s *=
static_cast<int>(j > 0);
530 B.w *=
static_cast<int>(i > 0);
536 mark_as_neighbors(B.c, B.n);
540 mark_as_neighbors(B.c, B.s);
544 mark_as_neighbors(B.c, B.e);
548 mark_as_neighbors(B.c, B.w);
554 std::vector<int> tmp(adjacency_matrix.size(), 0);
556 static_cast<int>(tmp.size()));
558 adjacency_matrix = tmp;
562 std::vector<std::set<int> > result(
m_n_basins);
564 for (
int b2 = b1 + 1; b2 <
m_n_basins; ++b2) {
565 if (adjacent(b1, b2)) {
566 result[b1].insert(b2);
567 result[b2].insert(b1);
583 std::vector<int> &most_shelf_cells_in_basin,
584 std::vector<int> &cfs_in_basins_per_shelf) {
586 std::vector<int> n_shelf_cells_per_basin(n_shelves *
m_n_basins,0);
588 std::vector<int> n_shelf_cells_per_basinr(n_shelves *
m_n_basins,0);
589 std::vector<int> cfs_in_basins_per_shelfr(n_shelves *
m_n_basins,0);
590 std::vector<int> most_shelf_cells_in_basinr(n_shelves, 0);
595 for (
auto p =
m_grid->points(); p; p.next()) {
596 const int i = p.i(), j = p.j();
597 int s = shelf_mask.
as_int(i, j);
600 n_shelf_cells_per_basin[sb]++;
603 auto M = cell_type.
star(i, j);
608 if (cfs_in_basins_per_shelf[sb] != b) {
609 cfs_in_basins_per_shelf[sb] = b;
616 cfs_in_basins_per_shelfr.data(), n_shelves*
m_n_basins);
618 n_shelf_cells_per_basinr.data(), n_shelves*
m_n_basins);
620 cfs_in_basins_per_shelf = cfs_in_basins_per_shelfr;
621 n_shelf_cells_per_basin = n_shelf_cells_per_basinr;
623 for (
int s = 0; s < n_shelves; s++) {
624 int n_shelf_cells_per_basin_max = 0;
627 if (n_shelf_cells_per_basin[sb] > n_shelf_cells_per_basin_max) {
628 most_shelf_cells_in_basin[s] = b;
629 n_shelf_cells_per_basin_max = n_shelf_cells_per_basin[sb];
642 const std::vector<std::set<int> > &basin_neighbors,
643 const std::vector<int> &most_shelf_cells_in_basin,
644 const std::vector<int> &cfs_in_basins_per_shelf,
652 std::vector<int> n_shelf_cells_to_split(n_shelves *
m_n_basins, 0);
656 for (
auto p =
m_grid->points(); p; p.next()) {
657 const int i = p.i(), j = p.j();
660 int shelf = shelf_mask.
as_int(i, j);
661 int b0 = most_shelf_cells_in_basin[shelf];
665 if (basin !=
b0 and (not neighbors) and
666 cfs_in_basins_per_shelf[shelf *
m_n_basins + basin] > 0) {
667 n_shelf_cells_to_split[shelf *
m_n_basins + basin]++;
673 std::vector<int> tmp(n_shelves *
m_n_basins, 0);
677 n_shelf_cells_to_split = tmp;
681 std::vector<int> add_shelf_instance(n_shelves *
m_n_basins, 0);
682 int n_shelf_numbers_to_add = 0;
683 for (
int s = 0; s < n_shelves; s++) {
684 int b0 = most_shelf_cells_in_basin[s];
686 if (n_shelf_cells_to_split[s *
m_n_basins + b] > 0) {
687 n_shelf_numbers_to_add += 1;
688 add_shelf_instance[s *
m_n_basins + b] = n_shelves + n_shelf_numbers_to_add;
689 m_log->message(3,
"\nPICO, split ice shelf s=%d with bmax=%d "
690 "and b=%d and n=%d and si=%d\n", s,
b0, b,
697 for (
auto p =
m_grid->points(); p; p.next()) {
698 const int i = p.i(), j = p.j();
701 int s = shelf_mask.
as_int(i, j);
702 if (add_shelf_instance[s *
m_n_basins + b] > 0) {
716 bool exclude_ice_rises,
729 for (
auto p =
m_grid->points(); p; p.next()) {
730 const int i = p.i(), j = p.j();
733 ocean_mask.
as_int(i, j) == 1 or
734 (exclude_ice_rises and ice_rises.
as_int(i, j) ==
RISE)) {
738 bool neighbor_to_land =
748 if (neighbor_to_land) {
771 bool exclude_ice_rises,
780 for (
auto p =
m_grid->points(); p; p.next()) {
781 const int i = p.i(), j = p.j();
784 ocean_mask.
as_int(i, j) == 1 or
785 (exclude_ice_rises and ice_rises.
as_int(i, j) ==
RISE)) {
789 auto M = ocean_mask.
star(i, j);
791 if (M.n == 2 or M.e == 2 or M.s == 2 or M.w == 2) {
832 auto grid = mask.
grid();
834 double current_label = 1;
835 double continue_loop = 1;
836 while (continue_loop != 0) {
840 for (
auto p = grid->points(); p; p.next()) {
841 const int i = p.i(), j = p.j();
843 if (mask.
as_int(i, j) == 0) {
845 auto R = mask.
star(i, j);
848 (R.n == current_label or R.s == current_label or
849 R.e == current_label or R.w == current_label)) {
852 mask(i, j) = current_label + 1;
861 continue_loop =
GlobalMax(grid->com, continue_loop);
875 int n_shelves =
static_cast<int>(
array::max(shelf_mask)) + 1;
877 std::vector<double> GL_distance_max(n_shelves, 0.0);
878 std::vector<double> GL_distance_max1(n_shelves, 0.0);
879 std::vector<double> CF_distance_max(n_shelves, 0.0);
880 std::vector<double> CF_distance_max1(n_shelves, 0.0);
882 for (
auto p =
m_grid->points(); p; p.next()) {
883 const int i = p.i(), j = p.j();
885 int shelf_id = shelf_mask.
as_int(i, j);
886 assert(shelf_id >= 0);
887 assert(shelf_id < n_shelves + 1);
894 if (D_gl(i, j) > GL_distance_max[shelf_id]) {
895 GL_distance_max[shelf_id] = D_gl(i, j);
898 if (D_cf(i, j) > CF_distance_max[shelf_id]) {
899 CF_distance_max[shelf_id] = D_cf(i, j);
904 GlobalMax(
m_grid->com, GL_distance_max.data(), GL_distance_max1.data(), n_shelves);
905 GlobalMax(
m_grid->com, CF_distance_max.data(), CF_distance_max1.data(), n_shelves);
907 GL_distance_max = GL_distance_max1;
908 CF_distance_max = CF_distance_max1;
910 double GL_distance_ref = *std::max_element(GL_distance_max.begin(), GL_distance_max.end());
914 std::vector<int> n_boxes(n_shelves, 0);
916 const double zeta = 0.5;
918 for (
int k = 0;
k < n_shelves; ++
k) {
919 n_boxes[
k] = n_min + round(pow((GL_distance_max[
k] / GL_distance_ref), zeta) * (max_number_of_boxes - n_min));
921 n_boxes[
k] =
std::min(n_boxes[
k], max_number_of_boxes);
926 for (
auto p =
m_grid->points(); p; p.next()) {
927 const int i = p.i(), j = p.j();
929 int d_gl = D_gl.
as_int(i, j);
930 int d_cf = D_cf.
as_int(i, j);
932 if (shelf_mask.
as_int(i, j) > 0 and d_gl > 0.0 and d_cf > 0.0) {
933 int shelf_id = shelf_mask.
as_int(i, j);
934 int n = n_boxes[shelf_id];
938 double r = d_gl / (double)(d_gl + d_cf);
940 double C = pow(1.0 - r, 2.0);
941 for (
int k = 0;
k <
n; ++
k) {
942 if ((
n -
k - 1) / (
double)
n <=
C and
C <= (
n -
k) / (
double)
n) {
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
A class defining a common interface for most PISM sub-models.
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.
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)
std::shared_ptr< petsc::Vec > allocate_proc0_copy() const
void update_ghosts()
Updates ghost points.
unsigned int stencil_width() const
Get the stencil width of the current Array. 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.
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
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
std::shared_ptr< petsc::Vec > m_tmp_p0
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.
double min(const array::Scalar &input)
Finds minimum over all the values in an array::Scalar object. Ignores ghosts.
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,...)
void label_components(array::Scalar &mask, petsc::Vec &mask_p0, bool identify_icebergs, double mask_grounded)
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)