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