opm-grid
ParentToChildrenCellGlobalIdHandle.hpp
1 //===========================================================================
2 //
3 // File: ParentToChildrenCellGlobalIdHandle.hpp
4 //
5 // Created: October 24 2024
6 //
7 // Author(s): Antonella Ritorto <antonella.ritorto@opm-op.com>
8 // Markus Blatt <markus.blatt@opm-op.com>
9 //
10 // $Date$
11 //
12 // $Revision$
13 //
14 //===========================================================================
15 
16 /*
17  Copyright 2024 Equinor ASA
18 
19  This file is part of The Open Porous Media project (OPM).
20  OPM is free software: you can redistribute it and/or modify
21  it under the terms of the GNU General Public License as published by
22  the Free Software Foundation, either version 3 of the License, or
23  (at your option) any later version.
24  OPM is distributed in the hope that it will be useful,
25  but WITHOUT ANY WARRANTY; without even the implied warranty of
26  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  GNU General Public License for more details.
28  You should have received a copy of the GNU General Public License
29  along with OPM. If not, see <http://www.gnu.org/licenses/>.
30 */
31 
32 #ifndef OPM_PARENTTOCHILDRENCELLGLOBALIDHANDLE_HEADER
33 #define OPM_PARENTTOCHILDRENCELLGLOBALIDHANDLE_HEADER
34 
35 
36 #include <opm/grid/cpgrid/Entity.hpp>
37 
38 #include <tuple>
39 #include <vector>
40 
41 
42 namespace
43 {
44 #if HAVE_MPI
45 
47 struct ParentToChildrenCellGlobalIdHandle {
48  // - The container used for gather and scatter contains global ids for interior elements of the refined level grids (LGRs).
49  // Access is done with the local index of a refined cell (child_cell_local_index),
50  // via its parent cell index and its parent cell list of children.
51  // level_cell_global_ids[ level-1 ][ child_cell_local_index ] = global id of the child.
52  // when child_cell_local_index belongs to the children_local_index_list:
53  // parent_to_children_[ element.index() ] = parent_to_children_[ element.index() ] = { level, children_local_index_list }
54  // - We use the number of entries in the scatter method. That number is the number of children when sending.
55  // (we still assume that the number entries is the same as the number of children of the element).
56 
57  using DataType = int;
58 
63  ParentToChildrenCellGlobalIdHandle(const std::vector<std::tuple<int, std::vector<int>>>& parent_to_children,
64  std::vector<std::vector<DataType>>& level_cell_global_ids)
65  : parent_to_children_(parent_to_children)
66  , level_cell_global_ids_(level_cell_global_ids)
67  {
68  }
69 
70  // Not every cell has children. When they have children, the amount might vary.
71  bool fixedSize(std::size_t, std::size_t)
72  {
73  return false;
74  }
75  // Only communicate values attached to cells.
76  bool contains(std::size_t, std::size_t codim)
77  {
78  return codim == 0;
79  }
80  // Communicate variable size: amount of child cells from a parent cell from level zero grid.
81  template <class T> // T = Entity<0>
82  std::size_t size(const T& element)
83  {
84  // Skip values that are not interior, or have no children (in that case, 'invalid' level = -1)
85  const auto& [level, children] = parent_to_children_[element.index()];
86  // [Bug in dune-common] VariableSizeCommunicator will deadlock if a process attempts to send a message of size zero.
87  // This can happen if the size method returns zero for all entities that are shared with another process.
88  // Therefore, when skipping cells without children or for overlap cells, we set the size to 1.
89  if ( (element.partitionType() != Dune::InteriorEntity) || (level == -1))
90  return 1;
91  return children.size();
92  }
93 
94  // Gather global ids of child cells of a coarse interior parent cell
95  template <class B, class T> // T = Entity<0>
96  void gather(B& buffer, const T& element)
97  {
98  // Skip values that are not interior, or have no children (in that case, 'invalid level' = -1)
99  const auto& [level, children] = parent_to_children_[element.index()];
100  // [Bug in dune-common] VariableSizeCommunicator will deadlock if a process tries to send a message with size zero.
101  // To avoid this, for cells without children or for overlap cells, we set the size to 1 and write a single DataType
102  // value (e.g., '42').
103  if ( (element.partitionType() != Dune::InteriorEntity) || (level==-1)) {
104  buffer.write(42);
105  return;
106  }
107  // Store the children's global ids in the buffer when the element is interior and has children.
108  for (const auto& child : children)
109  // Shift level-> level-1 since level_global_ids_ stores only refined level grids global ids.
110  // level_cell_global_ids_[0] corresponds to level 1, ..., level_cell_global_ids_[ maxLevel -1 ] to maxLevel grid.
111  buffer.write(level_cell_global_ids_[level-1][child]);
112  }
113 
114  // Scatter global ids of child cells of a coarse overlap parent cell
115  template <class B, class T> // T = Entity<0>
116  void scatter(B& buffer, const T& element, std::size_t num_children)
117  {
118  const auto& [level, children] = parent_to_children_[element.index()];
119  // Read all values to advance the pointer used by the buffer to the correct index.
120  // (Skip overlap cells without children and interior cells).
121  if ( ( (element.partitionType() == Dune::OverlapEntity) && (level==-1) ) || (element.partitionType() == Dune::InteriorEntity ) ) {
122  // Read all values to advance the pointer used by the buffer
123  // to the correct index
124  for (std::size_t child = 0; child < num_children; ++child) {
125  DataType tmp;
126  buffer.read(tmp);
127  }
128  }
129  else { // Overlap cell with children.
130  // Read and store the values in the correct location directly.
131  // Careful, we assume that the order of the children is the same on
132  // each process.
133  assert(children.size()>0);
134  assert(level>0);
135  for (const auto& child : children) {
136  // Shift level-> level-1 since level_cell_global_ids_ stores only refined level grids cell global ids.
137  // level_cell_global_ids_[0] corresponds to level 1, ..., level_cell_global_ids_[ maxLevel -1 ] to maxLevel grid.
138  auto& target_entry = level_cell_global_ids_[level-1][child];
139  buffer.read(target_entry);
140  }
141  }
142  }
143 
144 private:
145  const std::vector<std::tuple<int, std::vector<int>>>& parent_to_children_;
146  std::vector<std::vector<DataType>>& level_cell_global_ids_;
147 };
148 #endif // HAVE_MPI
149 } // namespace
150 #endif