ug4
attachment_pipe.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009-2015: G-CSC, Goethe University Frankfurt
3  * Author: Sebastian Reiter
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 __UTIL__ATTACHMENT_PIPE__IMPL__
34 #define __UTIL__ATTACHMENT_PIPE__IMPL__
35 
36 #include "attachment_pipe.h"
38 
39 namespace ug
40 {
41 template <class TElem, class TElemHandler>
44  m_attachmentEntryIteratorHash(13),
45  m_numElements(0),
46  m_numDataEntries(0),
47  m_containerSize(0),
48  m_pHandler(NULL)
49 {
50 }
51 
52 template <class TElem, class TElemHandler>
54 AttachmentPipe(typename atraits::ElemHandlerPtr pHandler) :
55  m_attachmentEntryIteratorHash(13),
56  m_numElements(0),
57  m_numDataEntries(0),
58  m_containerSize(0),
59  m_pHandler(pHandler)
60 {
61 }
62 
63 template <class TElem, class TElemHandler>
66 {
67 // clear attachment entries
68  for(AttachmentEntryIterator iter = m_attachmentEntryContainer.begin();
69  iter != m_attachmentEntryContainer.end(); iter++)
70  {
71  delete (*iter).m_pAttachment;
72  delete (*iter).m_pContainer;
73  }
74 }
75 
76 template <class TElem, class TElemHandler>
77 void
79 clear()
80 {
81  clear_elements();
83 }
84 
85 template <class TElem, class TElemHandler>
86 void
89 {
90  m_stackFreeEntries = UINTStack();
91  resize_attachment_containers(0);
92  m_numElements = 0;
93  m_numDataEntries = 0;
94 }
95 
96 template <class TElem, class TElemHandler>
97 void
100 {
101  m_attachmentEntryContainer.clear();
102  m_attachmentEntryIteratorHash.clear();
103 }
104 
105 template <class TElem, class TElemHandler>
106 void
108 reset_values(size_t dataIndex)
109 {
110  for(AttachmentEntryIterator iter = m_attachmentEntryContainer.begin();
111  iter != m_attachmentEntryContainer.end(); iter++)
112  {
113  (*iter).m_pContainer->reset_entry(dataIndex);
114  }
115 }
116 
117 
118 
119 template <class TElem, class TElemHandler>
120 void
122 reserve(size_t numElems)
123 {
124  if(numElems > get_container_size())
125  resize_attachment_containers(numElems);
126 }
127 
128 template <class TElem, class TElemHandler>
129 void
131 register_element(TElem elem)
132 {
133  size_t newInd;
134 // check if there is a free entry
135 
136  if(!m_stackFreeEntries.empty())
137  {
138  // take it
139  newInd = m_stackFreeEntries.top();
140  m_stackFreeEntries.pop();
141 
142  // initialize attachments with default constructor
143  reset_values(newInd);
144  }
145  else
146  {
147  // add a new entry
148  newInd = m_numDataEntries++;
149  // make sure that the data containers are big enough.
150  grow_attachment_containers(m_numDataEntries);
151  }
152 
153 // assign new attachment index to the element
154  atraits::set_data_index(m_pHandler, elem, newInd);
155 
156 // increase element count
157  m_numElements++;
158 }
159 
160 template <class TElem, class TElemHandler>
161 void
163 unregister_element(const TElem& elem)
164 {
165 // get the attachment index
166  size_t ind = atraits::get_data_index(m_pHandler, elem);
167 // store the index in the stack of free entries
168  m_stackFreeEntries.push(ind);
169 // decrease element count
170  m_numElements--;
171 }
172 
173 
174 template <class TElem, class TElemHandler>
175 template <class TAttachment>
176 void
178 attach(TAttachment& attachment,
179  const typename TAttachment::ValueType& defaultValue,
180  uint options)
181 {
182 // make sure, that the attachment is not already attached
183  if(!has_attachment(attachment))
184  {
185  // create a new element and insert it into the entryContainer.
186  // resize the new data-container to the size of the element container.
187  // store the returned iterator in the iteratorHash to allow fast access.
188  IAttachment* pClonedAttachment = attachment.clone();
189  IAttachmentDataContainer* pClonedContainer = attachment.create_container(defaultValue);
190  pClonedContainer->resize(get_container_size());
191  AttachmentEntryIterator iter = m_attachmentEntryContainer.
192  insert(m_attachmentEntryContainer.end(),
193  AttachmentEntry(pClonedAttachment,
194  pClonedContainer, options));
195  m_attachmentEntryIteratorHash.insert(pClonedAttachment->id(), iter);
196  }
197  else
198  {
199 //TODO: do something!
200  }
201 }
202 
203 template <class TElem, class TElemHandler>
204 void
206 attach(IAttachment& attachment, uint options)
207 {
208 // make sure, that the attachment is not already attached
209  if(!has_attachment(attachment))
210  {
211  // create a new element and insert it into the entryContainer.
212  // resize the new data-container to the size of the element container.
213  // store the returned iterator in the iteratorHash to allow fast access.
214  IAttachment* pClonedAttachment = attachment.clone();
215  IAttachmentDataContainer* pClonedContainer = pClonedAttachment->create_container();
216  pClonedContainer->resize(get_container_size());
217  AttachmentEntryIterator iter = m_attachmentEntryContainer.insert(m_attachmentEntryContainer.end(), AttachmentEntry(pClonedAttachment, pClonedContainer, options));
218  m_attachmentEntryIteratorHash.insert(pClonedAttachment->id(), iter);
219  }
220  else
221  {
222 //TODO: do something!
223  }
224 }
225 
226 template <class TElem, class TElemHandler>
227 void
229 detach(IAttachment& attachment)
230 {
231  if(has_attachment(attachment))
232  {
233  AttachmentEntryIterator iter = m_attachmentEntryIteratorHash.get_entry(attachment.id());
234  delete ((*iter).m_pAttachment);
235  ((*iter).m_pAttachment) = NULL;
236  delete((*iter).m_pContainer);
237  ((*iter).m_pContainer) = NULL;
238  m_attachmentEntryContainer.erase(iter);
239  m_attachmentEntryIteratorHash.erase(attachment.id());
240  }
241 }
242 
243 template <class TElem, class TElemHandler>
244 bool
246 has_attachment(IAttachment& attachment) const
247 {
248  return m_attachmentEntryIteratorHash.has_entry(attachment.id());
249 }
250 
251 
252 template <class TElem, class TElemHandler>
253 template <class TAttachment>
254 typename TAttachment::ValueType*
256 get_data_array(TAttachment& attachment)
257 {
258  if(has_attachment(attachment))
259  return get_data_container(attachment)->get_ptr();
260 
261  return NULL;
262 }
263 
264 template <class TElem, class TElemHandler>
267 get_data_container(IAttachment& attachment) const
268 {
270  if(m_attachmentEntryIteratorHash.get_entry(iter, attachment.id()))
271  return iter->m_pContainer;
272  return NULL;
273 }
274 
275 template <class TElem, class TElemHandler>
276 template <class TAttachment>
277 typename TAttachment::ContainerType*
279 get_data_container(TAttachment& attachment)
280 {
282  if(m_attachmentEntryIteratorHash.get_entry(iter, attachment.id()))
283  return static_cast<typename TAttachment::ContainerType*>(iter->m_pContainer);
284  return NULL;
285 }
286 
287 template <class TElem, class TElemHandler>
288 void
290 defragment()
291 {
292  if(!is_fragmented())
293  return;
294 
295 // if num_elements == 0, then simply resize all data-containers to 0.
296  if(num_elements() == 0)
297  {
298  // just clear the attachment containers.
299  for(AttachmentEntryIterator iter = m_attachmentEntryContainer.begin();
300  iter != m_attachmentEntryContainer.end(); iter++)
301  {
302  (*iter).m_pContainer->resize(0);
303  }
304  m_stackFreeEntries = UINTStack();
305  m_numDataEntries = 0;
306  }
307  else
308  {
309  // calculate the fragmentation array. It has to be of the same size as the fragmented data containers.
310  std::vector<uint> vNewIndices(num_data_entries(), INVALID_ATTACHMENT_INDEX);
311 
312  // iterate through the elements and calculate the new index of each
313  size_t counter = 0;
314  typename atraits::element_iterator iter = atraits::elements_begin(m_pHandler);
315  typename atraits::element_iterator end = atraits::elements_end(m_pHandler);
316 
317  for(; iter != end; ++iter){
318  vNewIndices[atraits::get_data_index(m_pHandler, (*iter))] = counter;
319  atraits::set_data_index(m_pHandler, (*iter), counter);
320  ++counter;
321  }
322 
323  // after defragmentation there are no free indices.
324  m_stackFreeEntries = UINTStack();
325  m_numDataEntries = counter;
326 
327  // now iterate through the attached data-containers and defragment each one.
328  {
329  for(AttachmentEntryIterator iter = m_attachmentEntryContainer.begin();
330  iter != m_attachmentEntryContainer.end(); iter++)
331  {
332  (*iter).m_pContainer->defragment(&vNewIndices.front(), num_elements());
333  }
334  }
335  }
336 }
337 
338 /*
339 template <class TElem, class TElemHandler>
340 void
341 AttachmentPipe<TElem, TElemHandler>::
342 defragment()
343 {
344  if(!is_fragmented())
345  return;
346 
347 // if num_elements == 0, then simply resize all data-containers to 0.
348  if(num_elements() == 0)
349  {
350  // just clear the attachment containers.
351  for(AttachmentEntryIterator iter = m_attachmentEntryContainer.begin();
352  iter != m_attachmentEntryContainer.end(); iter++)
353  {
354  (*iter).m_pContainer->resize(0);
355  }
356  }
357  else
358  {
359  // calculate the fragmentation array. It has to be of the same size as the fragmented data containers.
360  std::vector<uint> vNewIndices(num_data_entries(), INVALID_ATTACHMENT_INDEX);
361 
362  // iterate through the elements and calculate the new index of each
363  size_t counter = 0;
364  {
365  typename ElemEntryVec::iterator iter;
366  typename ElemEntryVec::iterator copyHere = m_vEntries.begin();
367  for(iter = m_vEntries.begin(); iter != m_vEntries.end(); ++iter)
368  {
369  if(!atraits::entry_is_invalid(*iter))
370  {
371  vNewIndices[atraits::get_data_index(m_pHandler, (*iter))] = counter;
372  atraits::set_data_index(m_pHandler, (*iter), counter);
373  ++counter;
374 
375  // copy entries
376  *copyHere = *iter;
377  ++copyHere;
378  }
379  }
380 
381  // resize m_vEntries
382  m_vEntries.resize(counter);
383  }
384 
385  // now iterate through the attached data-containers and defragment each one.
386  {
387  for(AttachmentEntryIterator iter = m_attachmentEntryContainer.begin();
388  iter != m_attachmentEntryContainer.end(); iter++)
389  {
390  (*iter).m_pContainer->defragment(&vNewIndices.front(), num_elements());
391  }
392  }
393  }
394 }
395 */
396 template <class TElem, class TElemHandler>
397 void
399 resize_attachment_containers(size_t newSize)
400 {
401 //UG_LOG("resizing attachment containers\n");
402  //PROFILE_BEGIN(AttachmentResize);
403  m_containerSize = newSize;
404  for(AttachmentEntryIterator iter = m_attachmentEntryContainer.begin();
405  iter != m_attachmentEntryContainer.end(); iter++)
406  {
407  (*iter).m_pContainer->resize(newSize);
408  }
409  //PROFILE_END();
410 //UG_LOG("done\n");
411 }
412 
413 template <class TElem, class TElemHandler>
414 void
416 grow_attachment_containers(size_t newMinSize)
417 {
418  //if(!m_attachmentEntryContainer.empty())
419  {
420  // if the container-size is smaller than newMinSize, we will increase it
421  // by a factor of 2 (at least)
422  size_t actSize = get_container_size();
423 
424  if(actSize < newMinSize)
425  {
426  size_t newSize = actSize * 2;
427  if(newSize < newMinSize)
428  newSize = newMinSize;
429 
430  resize_attachment_containers(newSize);
431  }
432  }
433 }
434 
435 template <class TElem, class TElemHandler>
436 size_t
439 {
440  return m_containerSize;
441 }
442 
445 // AttachmentAccessor
446 template <class TElem, class TAttachment, class TElemHandler>
448 AttachmentAccessor() : m_pContainer(NULL), m_pHandler(NULL)
449 {
450 }
451 
452 template <class TElem, class TAttachment, class TElemHandler>
455 {
456  m_pContainer = aa.m_pContainer;
457  m_pHandler = aa.m_pHandler;
458 }
459 
460 template <class TElem, class TAttachment, class TElemHandler>
463 {
464  m_pContainer = static_cast<typename TAttachment::ContainerType*>(attachmentPipe.get_data_container(attachment));
465  m_pHandler = attachmentPipe.get_elem_handler();
466  assert(m_pContainer && "ERROR in AttachmentAccessor::AttachmentAccessor(attachmentPipe, attachment): attachment not attached to attachmentPipe!");
467 }
468 
469 template <class TElem, class TAttachment, class TElemHandler>
470 bool
472 access(AttachmentPipe<TElem, TElemHandler>& attachmentPipe, TAttachment& attachment)
473 {
474  if(!attachmentPipe.has_attachment(attachment))
475  return false;
476 
477  m_pContainer = static_cast<typename TAttachment::ContainerType*>(attachmentPipe.get_data_container(attachment));
478  m_pHandler = attachmentPipe.get_elem_handler();
479  assert(m_pContainer && "ERROR in AttachmentAccessor::access(attachmentPipe, attachment): attachment not attached to attachmentPipe!");
480 
481  return true;
482 }
483 
484 }// end of namespace
485 
486 #endif
Used to access data that has been attached to an attachment pipe.
Definition: attachment_pipe.h:510
TElemHandler * m_pHandler
Definition: attachment_pipe.h:588
bool access(attachment_pipe &attachmentPipe, TAttachment &attachment)
Definition: attachment_pipe.hpp:472
ContainerType * m_pContainer
Definition: attachment_pipe.h:587
TAttachment attachment
Definition: attachment_pipe.h:512
AttachmentAccessor()
Definition: attachment_pipe.hpp:448
Handles data which has been attached to the pipe using callbacks for the element.
Definition: attachment_pipe.h:337
size_t get_container_size()
Definition: attachment_pipe.hpp:438
void attach(TAttachment &attachment, const typename TAttachment::ValueType &defaultValue, uint options)
attaches a new data-array to the pipe.
Definition: attachment_pipe.hpp:178
void resize_attachment_containers(size_t newSize)
Definition: attachment_pipe.hpp:399
void reset_values(size_t dataIndex)
fills the attached data at the given index with the default values.
Definition: attachment_pipe.hpp:108
TAttachment::ValueType * get_data_array(TAttachment &attachment)
Lets you access the raw data array associated with the given attachment.
Definition: attachment_pipe.hpp:256
std::stack< size_t > UINTStack
Definition: attachment_pipe.h:474
void clear_elements()
clears elements and associated data but keeps registered attachments
Definition: attachment_pipe.hpp:88
void grow_attachment_containers(size_t newMinSize)
Definition: attachment_pipe.hpp:416
void reserve(size_t numElems)
Reserves memory for element- and data-entries.
Definition: attachment_pipe.hpp:122
void clear()
calls both clear_elements and clear_attachments.
Definition: attachment_pipe.hpp:79
void register_element(TElem elem)
Registers a new element at the attachment pipe.
Definition: attachment_pipe.hpp:131
void clear_attachments()
clears registered attachments and associated data but keeps existing elements.
Definition: attachment_pipe.hpp:99
void detach(IAttachment &attachment)
Removes the data associated with the given attachment from the pipe.
Definition: attachment_pipe.hpp:229
AttachmentPipe()
Definition: attachment_pipe.hpp:43
void defragment()
Definition: attachment_pipe.hpp:290
AttachmentEntryContainer::iterator AttachmentEntryIterator
Definition: attachment_pipe.h:342
~AttachmentPipe()
Definition: attachment_pipe.hpp:65
IAttachmentDataContainer * get_data_container(IAttachment &attachment) const
Returns the data container managing the data array for the given attachment.
Definition: attachment_pipe.hpp:267
bool has_attachment(IAttachment &attachment) const
Returns true if the given attachment is currently attached to the pipe.
Definition: attachment_pipe.hpp:246
void unregister_element(const TElem &elem)
Unregisters the given element.
Definition: attachment_pipe.hpp:163
atraits::ElemHandlerPtr get_elem_handler()
Definition: attachment_pipe.h:352
the interface for an attachment-data-container.
Definition: attachment_pipe.h:72
virtual void resize(size_t iSize)=0
resize the data array
the interface for attachments.
Definition: attachment_pipe.h:239
virtual IAttachment * clone()=0
virtual IAttachmentDataContainer * create_container()=0
unsigned int id() const
Definition: uid.h:60
void element_iterator
Definition: attachment_pipe.h:313
void * ElemHandlerPtr
Definition: attachment_pipe.h:310
virtual void clear_attachments(typename TDomain::grid_type &grid)
unsigned int uint
Definition: types.h:114
the ug namespace
@ INVALID_ATTACHMENT_INDEX
Definition: attachment_pipe.h:58
This struct is used by AttachmentPipe in order to manage its attachments.
Definition: attachment_pipe.h:287