ug4
libGrid - Overview

Grid


The central class of libGrid is the Grid class. It handles element creation, neighbourhood management, data-attachments and observers. The class MultiGrid is derived from Grid, and adds a hierarchical structure to the grids elements.



Geometric Objects


Geometric Objects are the building blocks of a grid. There are four different basic geometric objects:

Those basic objects are then further specialized:

For hanging-node support the following objects are introduced:

All geometric objects deriving from Edge, Face or Volume feature methods to access the vertices of an element:

Furthermore they define methods like

Please check the documentation of the different base types.



Object Creation


Geometric Objects are created through the ug::Grid::create method (or ug::MultiGrid::create). Since the Grid class only knows about the basic geometric objects, ug::Grid::create<TGeomObj> is a template method, that takes the type of the geometric object that is to be created as template argument:

using namespace ug;(
...
Grid g;
// create vertices
Vertex* v1 = *g.create<Vertex>();
Vertex* v2 = *g.create<Vertex>();
// create an edge
g.create<Edge>(EdgeDescriptor(v1, v2));
the ug namespace

The create method takes an optional parameter:

ug::Grid::create(GeometricObject* pParent = NULL);
geometry_traits< TGeomObj >::iterator create(GridObject *pParent=NULL)
create a custom element.
Definition: grid_impl.hpp:69

The parent is used in different ways:

  • ug::GridSubsetHandler can automatically assign a subset based on the parents subset.
  • ug::Selector can automatically assign the selection-status based on the parents selection status.
  • A ug::MultiGrid inserts elements one level above the parents level.
  • You can use the parent in your own grid-observer specializations (derive from ug::GridObserver)

All those beahviours can be enabled / disabled in the respective classes.



Object Iteration


libGrid uses the technique of iterators for geometric-object access. A separate iterator-type exists for each object-type:

You can query a grid for a begin and an end-iterator for each geometric-object type using ug::Grid::begin and ug::Grid::end. Both methods are template methods. The template argument specifies the type of geometric-object over which you want to iterate.

// Let g be a grid that already contains some geometric objects
// iterate over all vertices
for(VertexIterator iter = g.begin<Vertex>();
iter != g.end<Vertex>(); ++iter)
{
Vertex* v = *iter;
...
}
// iterate over all faces
for(FaceIterator iter = g.begin<Face>();
iter != g.end<Face>(); ++iter)
{
Face* f = *iter;
...
}
// iterate over all triangles
for(TriangleIterator iter = g.begin<Triangle>();
iter != g.end<Triangle>(); ++iter)
{
Triangle* t = *iter;
...
}
ElementStorage< Vertex >::SectionContainer::iterator VertexIterator
This Iterator will be used as base-class for iterators of specialized geometric objects.
Definition: grid_base_object_traits.h:73
ElementStorage< Face >::SectionContainer::iterator FaceIterator
Definition: grid_base_object_traits.h:79
geometry_traits< Triangle >::iterator TriangleIterator
Definition: grid_objects_2d.h:211

The same technique can be used to iterate over all Triangles of a subset:

using namespace ug;
...
Grid g;
SubsetHandler sh(g); // short for GridSubsetHandler
...
// iterate over all triangles in subset 0
for(TriangleIterator iter = sh.begin<Triangle>(0);
iter != sh.end<Triangle>(0); ++iter)
{
Triangle* t = *iter;
...
}
Manages the elements of a grid and their interconnection.
Definition: grid.h:132
GridSubsetHandler SubsetHandler
Definition: subset_handler_grid.h:376

or a ug::Selector

...
Selector sel(g);
...
for(TriangleIterator iter = sel.begin<Triangle>();
iter != sel.end<Triangle>(); ++iter)
...

or a level of a ug::MultiGrid

...
MultiGrid mg;
...
for(TriangleIterator iter = mg.begin<Triangle>(0);
iter != mg.end<Triangle>(0); ++iter)

or triangles on level l in subset i of a ug::MultiGridSubsetHandler

...
MGSubsetHandler mgsh(mg); // short for MultiGridSubsetHandler
...
for(TriangleIterator iter = mgsh.begin<Triangle>(i, l);
iter != mgsh.end<Triangle>(i, l); ++iter)
...

There are even more classes that support this way of geometric-object iteration.

See also
ug::GridObjectCollection



Attachments


Through attachments custom data can be associated with the geometric objects in a ug::Grid or a subset of a ug::GridSubsetHandler or ug::MultiGridSubsetHandler. Data is attached to all objects of the same basic type at once (ug::Vertex, ug::Edge, ug::Face, ug::Volume).

Lets say we wanted to associate an integer with each vertex in a grid g. This could be done as follows:

// we define the attachment type
typedef Attachment<int> AInt;
// The instance of the attachment-type serves as identifier for the attachment.
AInt aInt;
// Let g be an instance of ug::Grid or ug::MultiGrid
g.attach_to_vertices(aInt);
Attachment< int > AInt
Definition: common_attachments.h:55

When aInt is being attached to the vertices of the grid, memory is automatically allocated and associated with the vertices. If you add or remove vertices, the memory is adjusted in the background.

To access the integer-value that is associated with each vertex, an attachment-accessor is required:

// a vertex-attachment-accessor for attachments of type AInt
// We want it to operate on the Grid g and on the attachment aInt
Grid::VertexAttachmentAccessor<AInt> aaInt(g, aInt);
// iterate over all vertices of the grid and assign 12 to the attached integer-value
for(VertexIterator iter = grid.vertices_begin(); iter != grid.vertices_end(); ++iter)
aaInt[*iter] = 12;

The vertex-attachment-accessor features the operator [] that takes a pointer to a vertex and returns a reference to the associated value.


Data can be attached to elements of a subset of an ug::GridSubsetHandler or ug::MultiGridSubsetHandler like this:

...
SubsetHandler sh(g);
...
// attach the integers to all faces in subset 2
sh.attach_to_faces(aInt, 2);
// access the attachment
SubsetHandler::AttachmentAccessor<Face, AInt> aaIntSH2(sh, aInt, 2);
// Assign values:
// Please note that you may only pass faces to the accessor that are contained in subset 2.
for(FaceIterator iter = sh.faces_begin(2); iter != sh.faces_end(2); ++iter)
aaIntSH2[*iter] = 17;



Neighborhood


Given a geometric object, there are several methods to access neighbor elements in a grid. The most powerful methods in this context is the method ug::Grid::associated_elements. It can be used with any combination of geometric base objects. E.g., it can be used to retrieve all faces which are connected to an edge or all faces, which are connected to a volume element. Here is an example, where we retrieve a container with all edges, which are connected to a volume element:

// Let vol be of type Volume* (or of any derived type) and grid of type Grid&
// declare a container in which we'll collect all associated edges of vol
Grid::edge_traits::secure_container edges;
grid.associated_elements(edges, vol);
// one could now iterate over the received edges
for(size_t i = 0; i < edges.size(); ++i){
Edge* e = edges[i];
//...
}

The code works for all combinations of Vertex, Edge, Face and Volume. Note however, that the method does not guarantee, that the order of the elements in the returned container is the same as the order of the reference element, e.g., when collecting sides of a volume. Since some methods rely on the order, a second method exist, which guarantees that the order matches reference elements order: ug::Grid::associated_elements_sorted. The method can basically be used as associated_elements, but has the restriction, that the dimension of the elements in the returned container has to be lower than the dimension of the element in the second argument. Otherwise no order could be defined. Furthermore ug::Grid::associated_elements_sorted may be a little slower than ug::Grid::associated_elements. The latter should thus be preferred, if the order is not important.

While those two methods allow to completely access all neighbors in a grid (possibly with a little work), some conveniance methods exist to, e.g., to retrieve a single side of an element or to retrieve all neighbors of the same geometric object type (e.g. all faces which are adjacent to a given face). All related methods are listed below.

The main methods to access associated elements, as explained above. Note that while those methods can be used to retrieve the vertices of, e.g., a Face, the direct way through Face::vertex or Face::vertices should be preferred if possible.

Returns the geometric object given a couple of vertices

Returns the i-th side of a geometric object (use e.g. Face::num_sides to retrieve the number of sides of that object).

Furthermore methods exist to collect, e.g., all faces which are adjacent to a given face (same for vertices, edges and volumes):



Tools


There are some classes that help tremendously when implementing algorithms: the Selector and the SubsetHandler.