1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 #ifndef UG_MESSAGE_BUFFER_HH
4 #define UG_MESSAGE_BUFFER_HH
5 
6 #include <algorithm>
7 
8 #include <dune/common/parallel/mpihelper.hh>
9 
10 #include <dune/grid/common/gridenums.hh>
11 
12 namespace Dune {
13 
14   /** converts the UG speak message buffers to DUNE speak and vice-versa */
15   template <class DataHandle, int gridDim, int codim>
16   class UGMessageBuffer
17   {
18     typedef UGMessageBuffer<DataHandle, gridDim, codim>  ThisType;
19     typedef UGGrid<gridDim>                              GridType;
20     typedef typename DataHandle::DataType DataType;
21 
22     using Entity = typename UGGrid<gridDim>::template Codim<codim>::Entity;
23     using EntityImp = typename Entity::Implementation;
24 
UGMessageBuffer(void * ugData)25     UGMessageBuffer(void *ugData)
26     {
27       ugData_ = static_cast<char*>(ugData);
28     };
29 
30   public:
write(const DataType & t)31     void write(const DataType &t)
32     { this->writeRaw_<DataType>(t);  }
33 
read(DataType & t)34     void read(DataType &t)
35     { this->readRaw_<DataType>(t);  }
36 
37   private:
38     friend class Dune::UGGrid<gridDim>;
39 
40     template <class ValueType>
writeRaw_(const ValueType & v)41     void writeRaw_(const ValueType &v)
42     {
43       std::copy(
44         reinterpret_cast<const char*>(&v),
45         reinterpret_cast<const char*>(&v) + sizeof(ValueType),
46         reinterpret_cast<char*>(ugData_)
47         );
48       ugData_ += sizeof(ValueType);
49     }
50 
51     template <class ValueType>
readRaw_(ValueType & v)52     void readRaw_(ValueType &v)
53     {
54       std::copy(
55         reinterpret_cast<const char*>(ugData_),
56         reinterpret_cast<const char*>(ugData_) + sizeof(ValueType),
57         reinterpret_cast<char*>(&v)
58         );
59       ugData_ += sizeof(ValueType);
60     }
61 
62     // called by DDD_IFOneway to serialize the data structure to
63     // be sent
ugGather_(DDD::DDDContext &,typename UG_NS<gridDim>::DDD_OBJ obj,void * data)64     static int ugGather_(
65 #if DUNE_UGGRID_HAVE_DDDCONTEXT
66       DDD::DDDContext&,
67 #endif
68       typename UG_NS<gridDim>::DDD_OBJ obj, void* data)
69     {
70       // cast the DDD object to a UG entity pointer
71       auto ugEP = reinterpret_cast<typename Dune::UG_NS<gridDim>::template Entity<codim>::T*>(obj);
72 
73       // construct a DUNE entity from the UG entity pointer
74       Entity entity(EntityImp(ugEP, grid_));
75 
76       // safety check to only communicate what is needed
77       if ((level == -1 && isToplevelLeaf(ugEP)) || entity.level() == level)
78       {
79         ThisType msgBuf(static_cast<DataType*>(data));
80         if (!duneDataHandle_->fixedSize(gridDim, codim))
81           msgBuf.template writeRaw_<unsigned>(duneDataHandle_->size(entity));
82         duneDataHandle_->gather(msgBuf, entity);
83       }
84 
85       return 0;
86     }
87 
88     // called by DDD_IFOneway to deserialize the data structure
89     // that has been received
ugScatter_(DDD::DDDContext &,typename UG_NS<gridDim>::DDD_OBJ obj,void * data)90     static int ugScatter_(
91 #if DUNE_UGGRID_HAVE_DDDCONTEXT
92       DDD::DDDContext&,
93 #endif
94       typename UG_NS<gridDim>::DDD_OBJ obj, void* data)
95     {
96       // cast the DDD object to a UG entity pointer
97       auto ugEP = reinterpret_cast<typename Dune::UG_NS<gridDim>::template Entity<codim>::T*>(obj);
98 
99       // construct a DUNE entity from the UG entity pointer
100       Entity entity(EntityImp(ugEP, grid_));
101 
102       // safety check to only communicate what is needed
103       if ((level == -1 && isToplevelLeaf(ugEP)) || entity.level() == level)
104       {
105         ThisType msgBuf(static_cast<DataType*>(data));
106         int size;
107         if (!duneDataHandle_->fixedSize(gridDim, codim))
108           msgBuf.readRaw_(size);
109         else
110           size = duneDataHandle_->size(entity);
111         if (size > 0)
112           duneDataHandle_->scatter(msgBuf, entity, size);
113 
114       }
115 
116       return 0;
117     }
118 
119     /** \brief Test whether entity is leaf and has no copies on higher (i.e., finer) levels
120      *
121      * Entities of the leaf grid view are equivalence class of entities of the level view.
122      * Therefore, the isLeaf method of the grid interface sometimes returns true for entities
123      * that have copies on a finer level.  In communication, we really want to call gather
124      * and scatter for these entities only once.  Therefore we use the following special
125      * implementation that returns true only if an entity is leaf and it has now children.
126      */
isToplevelLeaf(const typename Dune::UG_NS<gridDim>::template Entity<codim>::T * ugEP)127     static bool isToplevelLeaf(const typename Dune::UG_NS<gridDim>::template Entity<codim>::T* ugEP)
128     {
129       // safety check to only communicate what is needed
130       bool isLeaf = UG_NS<gridDim>::isLeaf(ugEP);
131 
132       // Edges: Simply checking isLeaf here will return 'true' for each top-level
133       // leaf and *and* its lower-level copies (if it has any).  However, we really
134       // want only the highest-level copy, because otherwise gather will be called
135       // more than once for that edge (interpreted as a leaf grid edge).  Therefore
136       // we need a tigher criterion.
137       if constexpr (gridDim-codim==1)
138       {
139         if (isLeaf)
140         {
141           // isLeaf is true, i.e. we either are a top-level leaf oder or a copy of one.
142           // If we are are lower-level copy then both of our end nodes have children,
143           // and these two children are connected.
144           auto nodeA = ugEP->links[0].nbnode;
145           auto nodeB = ugEP->links[1].nbnode;
146 
147           if (nodeA->son && nodeB->son && UG_NS<gridDim>::GetEdge(nodeA->son, nodeB->son))
148             isLeaf = false;
149         }
150       }
151 
152       // Facets: No such handling is currently needed, because UGGridLeafIndexSet<GridImp>::update
153       // does not assign leaf indices of leaf facets to their copy-fathers.
154       // This may be a bug...
155 
156       return isLeaf;
157     }
158 
159     // returns number of bytes required for the UG message buffer
160     template <class GridView>
ugBufferSize(const GridView & gv)161     static unsigned ugBufferSize(const GridView &gv)
162     {
163       // If the data handle claims to have the same number of data items for each entity
164       // of the given codimension, then just ask for that numbering giving the first entity.
165       if (duneDataHandle_->fixedSize(gridDim, codim))
166       {
167         auto element = gv.template begin<0, InteriorBorder_Partition>();
168         return sizeof(DataType)
169                * duneDataHandle_->size(element->template subEntity<codim>(0));
170       }
171 
172       // iterate over all entities, find the maximum size for
173       // the current rank
174       std::size_t maxSize = 0;
175       if constexpr (codim==gridDim || codim==0)
176       {
177         for (const auto& entity : entities(gv, Codim<codim>(), Dune::Partitions::all))
178           maxSize = std::max(maxSize, duneDataHandle_->size(entity));
179       }
180       else
181       {
182         for (const auto& element : elements(gv, Dune::Partitions::all))
183         {
184           int numberOfSubentities = element.subEntities(codim);
185           for (int k = 0; k < numberOfSubentities; k++)
186           {
187             const auto subEntity = element.template subEntity<codim>(k);
188 
189             maxSize = std::max(maxSize, duneDataHandle_->size(subEntity));
190           }
191         }
192       }
193 
194       // find maximum size for all ranks
195       maxSize = gv.comm().max(maxSize);
196       if (maxSize==0)
197         return 0;
198 
199       // Add the size of an unsigned integer to the actual buffer size,
200       // for storing the actual number of objects for each entity.
201       return sizeof(unsigned) + sizeof(DataType)*maxSize;
202     }
203 
204     static const GridType* grid_;
205     static DataHandle *duneDataHandle_;
206     static int level;
207     char *ugData_;
208   };
209 
210 }   // end namespace Dune
211 
212 #endif  // UG_MESSAGE_BUFFER_HH
213