Line data Source code
1 : /*
2 : * Copyright (c) 2015: G-CSC, Goethe University Frankfurt
3 : * Author: Markus Breit
4 : *
5 : * This file is part of UG4.
6 : *
7 : * UG4 is free software: you can redistribute it and/or modify it under the
8 : * terms of the GNU Lesser General Public License version 3 (as published by the
9 : * Free Software Foundation) with the following additional attribution
10 : * requirements (according to LGPL/GPL v3 §7):
11 : *
12 : * (1) The following notice must be displayed in the Appropriate Legal Notices
13 : * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14 : *
15 : * (2) The following notice must be displayed at a prominent place in the
16 : * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17 : *
18 : * (3) The following bibliography is recommended for citation and must be
19 : * preserved in all covered files:
20 : * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21 : * parallel geometric multigrid solver on hierarchically distributed grids.
22 : * Computing and visualization in science 16, 4 (2013), 151-164"
23 : * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24 : * flexible software system for simulating pde based models on high performance
25 : * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26 : *
27 : * This program is distributed in the hope that it will be useful,
28 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 : * GNU Lesser General Public License for more details.
31 : */
32 :
33 : #ifndef LIB_GRID__COPY_ATTACHMENT_HANDLER_H_
34 : #define LIB_GRID__COPY_ATTACHMENT_HANDLER_H_
35 :
36 : #include "common/util/smart_pointer.h" // for SmartPtr
37 : #include "lib_grid/grid/grid_observer.h" // for GridObserver
38 : #include "lib_grid/multi_grid.h" // for MultiGrid
39 :
40 : #ifdef UG_PARALLEL
41 : #include "lib_grid/parallelization/util/compol_copy_attachment.h" // ComPol_CopyAttachment
42 : #include "lib_grid/parallelization/distributed_grid.h" // DistributedGridManager
43 : #endif
44 :
45 : namespace ug{
46 :
47 :
48 : /**
49 : * @brief handler for attachments in a multi-grid
50 : *
51 : * When using attachments in a multi-grid hierarchy, one
52 : * EITHER needs to create the attachment after the geometry is refined (and distributed)
53 : * up to the state in which the attachments are used - in this case, every geometric
54 : * object which the data is attached to will have its attachment and there is no problem
55 : * OR one creates the attachment before the geometry is refined (and distributed) - in
56 : * this case, if the attachment is required on elements that are created after creation
57 : * of the attachment, one needs to take care to supply those elements with attachment
58 : * values. This class will do exactly this, but only to a very limited extent:
59 : *
60 : * When this class is assigned a multi-grid, it will propagate attachment values from the
61 : * base level upwards to the children <b>of the same type<\b> by copying.
62 : * Vertical communication is performed on each level to make sure that all those children
63 : * will get their values.
64 : *
65 : * Moreover, making use of the GridObserver interface, this class will copy attachment
66 : * values to each child element (of equal type as their parent) created after assignment
67 : * of the grid.
68 : *
69 : *
70 : * This will not, in general, guarantee that every element of the required type will
71 : * get an attachment value. It will however suffice if the element type the attachment is
72 : * attached to is full-dimensional (in its domain); it will obviously also suffice if the
73 : * attachment values are only required on direct children (of equal type) of coarse grid
74 : * elements, e.g. on d-dimensional elements on a d-dimensional manifold.
75 : *
76 : * Example:
77 : *
78 : * If, in the base level, attachments (a1, a2) are attached to their resp. nodes like this:
79 : *
80 : * a1 --------- a2 <-- lvl 0
81 : *
82 : * then, on the next level, the node marked by "o" will not have an attachment value
83 : * propagated from below (since it does not have a parent of the same type):
84 : *
85 : * a1 --- o --- a2 <-- lvl 1
86 : *
87 : * a1 --------- a2 <-- lvl 0
88 : *
89 : * You may, however, choose to derive another handler class from this implementation
90 : * and treat the cases where an upper-level element is child of an element of different
91 : * type there by overloading copy_from_other_elem_type().
92 : * In the same manner, you might use derivation and overloading (of the copy() method)
93 : * to perform a more specialized way of copying.
94 : *
95 : * @note Implementation relies on a template trick: One cannot - as decreed by the
96 : * standard - specialize template methods of a not fully specialized template class;
97 : * it is possible, however, to @e partially specialize nested template classes of a
98 : * template class. This is what is used here.
99 : *
100 : */
101 : template <typename TElem, typename TAttachment>
102 : class CopyAttachmentHandler : public GridObserver
103 : {
104 : public:
105 : /// constructor
106 0 : CopyAttachmentHandler()
107 0 : : m_bEnableVertComm(true) {}
108 :
109 : /// destructor
110 0 : virtual ~CopyAttachmentHandler()
111 : {
112 0 : if (m_spMG.valid())
113 0 : m_spMG->unregister_observer(this);
114 :
115 : m_aa.invalidate();
116 0 : };
117 :
118 : void set_attachment(const TAttachment& attch)
119 : {
120 : m_a = attch;
121 :
122 : // if we already have a grid, then this must be a reset
123 0 : if (m_spMG.valid())
124 : {
125 : m_aa.invalidate();
126 0 : m_aa.access(*m_spMG, m_a);
127 : }
128 : }
129 :
130 0 : void set_grid(SmartPtr<MultiGrid> mg)
131 : {
132 : // do nothing if given grid is already set
133 0 : if (m_spMG == mg) return;
134 :
135 : // if another grid is already given, unregister from old grid and invalidate accessor
136 0 : if (m_spMG.valid())
137 : {
138 0 : m_spMG->unregister_observer(this);
139 : m_aa.invalidate();
140 : }
141 :
142 : // set new grid
143 0 : m_spMG = mg;
144 0 : UG_COND_THROW(!m_spMG.valid(), "No valid multigrid given!");
145 :
146 : // register as appropriate observer
147 0 : register_as_observer<TElem, void>(m_spMG, this);
148 :
149 : // check that attachment is attached to grid
150 0 : UG_COND_THROW(!m_spMG->has_attachment<TElem>(m_a),
151 : "Given grid does not have given attachment attached to it.");
152 :
153 : // init accessor
154 0 : m_aa.access(*m_spMG, m_a);
155 :
156 : // copy to all levels that are already present
157 0 : propagate_to_levels();
158 : }
159 :
160 : void enable_vertical_communication(bool b)
161 : {
162 : m_bEnableVertComm = b;
163 : }
164 :
165 :
166 : // GridObserver implementations
167 0 : virtual void vertex_created
168 : (
169 : Grid* grid,
170 : Vertex* vrt,
171 : GridObject* pParent = NULL,
172 : bool replacesParent = false
173 : )
174 : {
175 0 : propagate<Vertex, void>(vrt, pParent, this);
176 0 : }
177 :
178 0 : virtual void edge_created
179 : (
180 : Grid* grid,
181 : Edge* e,
182 : GridObject* pParent = NULL,
183 : bool replacesParent = false
184 : )
185 : {
186 : propagate<Edge, void>(e, pParent, this);
187 0 : }
188 :
189 0 : virtual void face_created
190 : (
191 : Grid* grid,
192 : Face* f,
193 : GridObject* pParent = NULL,
194 : bool replacesParent = false
195 : )
196 : {
197 : propagate<Face, void>(f, pParent, this);
198 0 : }
199 :
200 0 : virtual void volume_created
201 : (
202 : Grid* grid,
203 : Volume* vol,
204 : GridObject* pParent = NULL,
205 : bool replacesParent = false
206 : )
207 : {
208 : propagate<Volume, void>(vol, pParent, this);
209 0 : }
210 :
211 : protected:
212 :
213 : // this template will be used if created is called with anything BUT TElem (in that case: do nothing)
214 : template <typename TCreatedElem, typename Dummy>
215 : struct propagate
216 : {
217 : propagate(TCreatedElem* elem, GridObject* pParent, CopyAttachmentHandler<TElem, TAttachment>* cah) {};
218 : };
219 :
220 : // this template will be used if created is called with an elem of type TElem
221 : template <typename Dummy>
222 : struct propagate<TElem, Dummy>
223 : {
224 0 : propagate(TElem* elem, GridObject* pParent, CopyAttachmentHandler<TElem, TAttachment>* cah)
225 : {
226 : // check that parent is given
227 0 : if (!pParent) return;
228 :
229 : // if parent is of different elem type than child
230 0 : TElem* par = dynamic_cast<TElem*>(pParent);
231 0 : if (!par)
232 : {
233 0 : cah->copy_from_other_elem_type(pParent, elem);
234 0 : return;
235 : }
236 :
237 : // copy attachment value from parent to child
238 0 : cah->copy(par, elem);
239 : }
240 : };
241 :
242 : friend struct propagate<TElem, void>;
243 :
244 : template <typename TObserverElem, typename Dummy>
245 : struct register_as_observer
246 : {
247 : register_as_observer(SmartPtr<MultiGrid> mg, CopyAttachmentHandler<TObserverElem, TAttachment>* cah) {};
248 : };
249 :
250 : template <typename Dummy>
251 : struct register_as_observer<Vertex, Dummy>
252 : {
253 : register_as_observer(SmartPtr<MultiGrid> mg, CopyAttachmentHandler<Vertex, TAttachment>* cah)
254 : {
255 0 : mg->register_observer(cah, OT_VERTEX_OBSERVER);
256 0 : }
257 : };
258 : template <typename Dummy>
259 : struct register_as_observer<Edge, Dummy>
260 : {
261 : register_as_observer(SmartPtr<MultiGrid> mg, CopyAttachmentHandler<Edge, TAttachment>* cah)
262 : {
263 : mg->register_observer(cah, OT_EDGE_OBSERVER);
264 : }
265 : };
266 : template <typename Dummy>
267 : struct register_as_observer<Face, Dummy>
268 : {
269 : register_as_observer(SmartPtr<MultiGrid> mg, CopyAttachmentHandler<Face, TAttachment>* cah)
270 : {
271 : mg->register_observer(this, OT_FACE_OBSERVER);
272 : }
273 : };
274 : template <typename Dummy>
275 : struct register_as_observer<Volume, Dummy>
276 : {
277 : register_as_observer(SmartPtr<MultiGrid> mg, CopyAttachmentHandler<Volume, TAttachment>* cah)
278 : {
279 : mg->register_observer(this, OT_VOLUME_OBSERVER);
280 : }
281 : };
282 :
283 :
284 0 : void propagate_to_levels()
285 : {
286 : // ensure a final vertical communication on the top level
287 0 : const size_t nProp = m_bEnableVertComm ? m_spMG->num_levels() + 1 : m_spMG->num_levels();
288 0 : for (size_t i = 1; i < nProp; ++i)
289 0 : propagate_to_level(i, m_bEnableVertComm);
290 0 : }
291 :
292 0 : void propagate_to_level(size_t lvl, bool vertComm = true)
293 : {
294 : #ifdef UG_PARALLEL
295 : // copy from vMasters to vSlaves
296 : if (pcl::NumProcs() > 1 && vertComm)
297 : {
298 : typedef typename GridLayoutMap::Types<TElem>::Layout layout_type;
299 : DistributedGridManager& dgm = *m_spMG->distributed_grid_manager();
300 : GridLayoutMap& glm = dgm.grid_layout_map();
301 : pcl::InterfaceCommunicator<layout_type> icom;
302 :
303 : ComPol_CopyAttachment<layout_type, TAttachment> compolCopy(*m_spMG, m_a);
304 : icom.exchange_data(glm, INT_V_MASTER, INT_V_SLAVE, compolCopy);
305 : icom.communicate();
306 : }
307 : #endif
308 : // iterate over all TElems of level
309 : typedef typename geometry_traits<TElem>::const_iterator iter_type;
310 0 : iter_type iter = m_spMG->begin<TElem>(lvl);
311 0 : iter_type iter_end = m_spMG->end<TElem>(lvl);
312 0 : for (; iter != iter_end; ++iter)
313 : {
314 : TElem* child = *iter;
315 : GridObject* parent = m_spMG->get_parent(*iter);
316 :
317 0 : propagate<TElem, void>(child, parent, this);
318 : }
319 0 : }
320 :
321 0 : virtual void copy(TElem* parent, TElem* child)
322 : {
323 0 : m_aa[child] = m_aa[parent];
324 0 : }
325 :
326 0 : virtual void copy_from_other_elem_type(GridObject* parent, TElem* child) {};
327 :
328 : protected:
329 : /// multigrid
330 : SmartPtr<MultiGrid> m_spMG;
331 :
332 : bool m_bEnableVertComm;
333 :
334 : /// attachment to be handled
335 : TAttachment m_a;
336 :
337 : /// accessor for handled attachment
338 : Grid::AttachmentAccessor<TElem, TAttachment> m_aa;
339 :
340 : };
341 :
342 : } // end namespace ug
343 :
344 : #endif // LIB_GRID__COPY_ATTACHMENT_HANDLER_H__
|