Newer
Older

Thomas Witkowski
committed
//
// Software License for AMDiS
//
// Copyright (c) 2010 Dresden University of Technology
// All rights reserved.
// Authors: Simon Vey, Thomas Witkowski et al.
//
// This file is part of AMDiS
//
// See also license.opensource.txt in the distribution.
#include "CoarseningManager3d.h"
#include "Mesh.h"
#include "AdaptStationary.h"
#include "AdaptInstationary.h"
#include "Traverse.h"
#include "MacroElement.h"
#include "RCNeighbourList.h"
#include "FixVec.h"
#include "DOFIndexed.h"

Thomas Witkowski
committed
#include "Debug.h"

Thomas Witkowski
committed
void CoarseningManager3d::coarsenFunction(ElInfo *elInfo)

Thomas Witkowski
committed
FUNCNAME("CoarseningManager3d::coarsenFunction()");

Thomas Witkowski
committed
dynamic_cast<Tetrahedron*>(const_cast<Element*>(elInfo->getElement()));

Thomas Witkowski
committed
// If element must not be coarsend, return.
if (el->getMark() >= 0)

Thomas Witkowski
committed
return;

Thomas Witkowski
committed
// Single leaves don't get coarsened.
if (el->isLeaf())

Thomas Witkowski
committed
return;
if (el->getChild(0)->getMark() >= 0 || el->getChild(1)->getMark() >= 0) {

Thomas Witkowski
committed
// One of the children must not be coarsend, so return.
}
if (!(el->getChild(0)->isLeaf()) || !(el->getChild(1)->isLeaf())) {

Thomas Witkowski
committed
// One of the children is not a leaf element. Try again later on.
DegreeOfFreedom *edge[2];
int n_neigh, bound = 0;
/****************************************************************************/
/* get a list for storing all elements at the coarsening edge and fill it */
/****************************************************************************/
RCNeighbourList coarsenList(mesh->getMaxEdgeNeigh());
coarsenList.setCoarseningManager(this);
/****************************************************************************/
/* give the refinement edge the right orientation */
/****************************************************************************/

Thomas Witkowski
committed
if (el->getDof(0, 0) < el->getDof(1, 0)) {
edge[0] = const_cast<DegreeOfFreedom*>(el->getDof(0));
edge[1] = const_cast<DegreeOfFreedom*>(el->getDof(1));

Thomas Witkowski
committed
edge[1] = const_cast<DegreeOfFreedom*>(el->getDof(0));
edge[0] = const_cast<DegreeOfFreedom*>(el->getDof(1));
coarsenList.setElement(0, el, true);
coarsenList.setOppVertex(0, 0, 0);

Thomas Witkowski
committed
coarsenList.setElType(0, elInfo->getType());

Thomas Witkowski
committed
if (getCoarsenPatch(elInfo, edge, 0, coarsenList, &n_neigh)) {
getCoarsenPatch(elInfo, edge, 1, coarsenList, &n_neigh);

Thomas Witkowski
committed
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#if HAVE_PARALLEL_DOMAIN_AMDIS
Element *otherEl = NULL;
int otherEdge = -1;
FixRefinementPatch::getOtherEl(stack, &otherEl, otherEdge);
// === If the refinement edge must be fixed, add also the other part of this ===
// === edge to the refinement patch. ===
if (otherEl) {
// TODO: Remove these two lines and make something more meaningful!!
el->setMark(0);
return;
TraverseStack stack2;
ElInfo *elInfo2 =
stack2.traverseFirstOneMacro(mesh, otherEl->getIndex(), -1,
Mesh::CALL_EVERY_EL_PREORDER |
Mesh::FILL_NEIGH |
Mesh::FILL_BOUND);
bool foundEdge = false;
while (elInfo2) {
Element *el2 = elInfo2->getElement();
for (int i = 0; i < 6; i++) {
DofEdge edge2 = elInfo2->getElement()->getEdge(i);
if (edge2.first == *(edge[0]) && edge2.second == *(edge[1]) && !el2->isLeaf()) {
if (!el2->getChild(0)->isLeaf() || !el2->getChild(1)->isLeaf()) {
int edgeNo0 = el->getEdgeOfChild(0, i, elInfo2->getType());
int edgeNo1 = el->getEdgeOfChild(1, i, elInfo2->getType());
bool refineChildFirst =
!(i > 0 &&
(edgeNo0 >= 0 && !el2->getChild(0)->isLeaf()) ||
(edgeNo1 >= 0 && !el2->getChild(1)->isLeaf()));
if (refineChildFirst) {
// TODO: WAS SOLL ICH NUR MACHEN???
el->setMark(0);
return;
}
} else {
coarsenList.setElType(n_neigh, elInfo2->getType());
coarsenList.setElement(n_neigh, elInfo2->getElement(), true);
n_neigh++;
foundEdge = true;
TraverseStack *tmpStack = stack;
stack = &stack2;
if (getCoarsenPatch(elInfo2, edge, 0, coarsenList, &n_neigh)) {
getCoarsenPatch(elInfo2, edge, 1, coarsenList, &n_neigh);
bound = true;
}
stack = tmpStack;
break;
}
}
}
elInfo2 = stack2.traverseNext(elInfo2);
}
TEST_EXIT_DBG(foundEdge)("Should not happen!\n");
}
#endif
coarsenList.fillNeighbourRelations(n_neigh, bound);
/****************************************************************************/
/* check wether we can coarsen the patch or not */
/****************************************************************************/
// ==========================================================================
// === check for periodic boundary ==========================================
// ==========================================================================
if (coarsenList.doCoarsePatch(n_neigh)) {
int n_neigh_periodic;
DegreeOfFreedom *next_edge[2];
RCNeighbourList periodicList;
coarsenList.periodicSplit(edge, next_edge,

Thomas Witkowski
committed
&n_neigh, &n_neigh_periodic,
periodicList);
coarsenPatch(periodicList, n_neigh_periodic, bound);
edge[0] = next_edge[0];
edge[1] = next_edge[1];
}
}
}
/*****************************************************************************/
/* coarsenTetrahedron: coarses a single element of the coarsening patch; */
/* dofs in the interior of the element are removed and dofs in the faces of */
/* the element are removed if neighbour has been coarsend or if the face */
/* is part of the domains boundary */
/*****************************************************************************/
void CoarseningManager3d::coarsenTetrahedron(RCNeighbourList &coarsenList,
dynamic_cast<Tetrahedron*>(const_cast<Element*>(coarsenList.getElement(index)));
child[0] = dynamic_cast<Tetrahedron*>(const_cast<Element*>(el->getChild(0)));
child[1] = dynamic_cast<Tetrahedron*>(const_cast<Element*>(el->getChild(1)));

Thomas Witkowski
committed
int el_type = coarsenList.getType(index);
/****************************************************************************/
/* Information about patch neighbours is still valid! But edge and face */
/* dof's in a common face of patch neighbours have to be removed */
/****************************************************************************/

Thomas Witkowski
committed
for (int dir = 0; dir < 2; dir++) {
Tetrahedron *neigh =
dynamic_cast<Tetrahedron*>(const_cast<Element*>(coarsenList.getNeighbourElement(index, dir)));
if (!neigh || neigh->isLeaf()) {
/****************************************************************************/
/* boundary face or neigh has been coarsend: free the dof's in the face */
/****************************************************************************/
if (mesh->getNumberOfDofs(EDGE)) {

Thomas Witkowski
committed
int node = mesh->getNode(EDGE) + Tetrahedron::nChildEdge[el_type][0][dir];
mesh->freeDof(const_cast<int*>(child[0]->getDof(node)), EDGE);
if (mesh->getNumberOfDofs(FACE)) {

Thomas Witkowski
committed
int node = mesh->getNode(FACE) + Tetrahedron::nChildFace[el_type][0][dir];
mesh->freeDof(const_cast<int*>(child[0]->getDof(node)), FACE);
node = mesh->getNode(FACE) + Tetrahedron::nChildFace[el_type][1][dir];
mesh->freeDof(const_cast<int*>(child[1]->getDof(node)), FACE);
}
}
}
/****************************************************************************/
/* finally remove the interior dof's: in the common face of child[0] and */
/* child[1] and at the two barycenter */
/****************************************************************************/
if (mesh->getNumberOfDofs(FACE)) {

Thomas Witkowski
committed
int node = mesh->getNode(FACE);
mesh->freeDof(const_cast<int*>(child[0]->getDof(node)), FACE);
if (mesh->getNumberOfDofs(CENTER)) {

Thomas Witkowski
committed
int node = mesh->getNode(CENTER);
for (int i = 0; i < 2; i++)
mesh->freeDof(const_cast<int*>(child[i]->getDof(node)), CENTER);
}
/****************************************************************************/
/* get new data on parent and transfer data from children to parent */
/****************************************************************************/
el->coarsenElementData(child[0], child[1], el_type);
el->setFirstChild(NULL);
el->setSecondChild(NULL);
mesh->freeElement(child[0]);
mesh->freeElement(child[1]);
el->incrementMark();
mesh->incrementNumberOfLeaves(-1);
mesh->incrementNumberOfElements(-2);
}
/****************************************************************************/
/* get_coarse_patch: gets the patch for coarsening starting on element */

Thomas Witkowski
committed
/* elInfo->el in direction of neighbour [3-dir]; returns 1 if a boundary */
/* reached and 0 if we come back to the starting element. */
/* */
/* if NEIGH_IN_EL we only can find the complete coarsening patch if the */
/* can be coarsend; otherwise neighbour information is not valid for */
/* parents; in such situation we stop looping around the edge and return 0 */
/* */
/* if !NEIGH_IN_EL we complete the loop also in the case of a incompatible */
/* coarsening patch since then all marks of patch elements are reset by */
/* do_coarse_patch() and this minimizes calls of traverse_neighbour(); */
/* if we reach a boundary while looping around the edge we loop back to */
/* the starting element before we return */
/****************************************************************************/

Thomas Witkowski
committed
bool CoarseningManager3d::getCoarsenPatch(ElInfo *elInfo,
RCNeighbourList &coarsenList,

Thomas Witkowski
committed
FUNCNAME("CoarseningManager3d::getCoarsenPatch()");
static unsigned char next_el[6][2] = {{3,2},
{1,3},
{1,2},
{0,3},
{0,2},
{0,1}};

Thomas Witkowski
committed
Tetrahedron *el =
dynamic_cast<Tetrahedron*>(const_cast<Element*>(elInfo->getElement()));
Tetrahedron *neigh =
dynamic_cast<Tetrahedron*>(const_cast<Element*>(elInfo->getNeighbour(3 - dir)));

Thomas Witkowski
committed
int opp_v = elInfo->getOppVertex(3 - dir);
ElInfo *neigh_info = stack->traverseNeighbour3d(elInfo, 3 - dir);
TEST_EXIT_DBG(neigh == neigh_info->getElement())
("neigh %d and neigh_info->el %d are not identical\n",
neigh->getIndex(), neigh_info->getElement()->getIndex());
/****************************************************************************/
/* we have to go back to the starting element via opp_v values */
/* correct information is produce by get_neigh_on_patch() */
/****************************************************************************/
coarsenList.setOppVertex(*n_neigh, 0, opp_v);
coarsenList.setElement(*n_neigh, neigh);
coarsenList.setElType(*n_neigh, neigh_info->getType());
int nVertices = mesh->getGeo(VERTEX);
// === Find the coarsening edge on the current neighbour element. ===
int i, j, k;
// === First, try to identify the edge DOFs directly. ===
for (j = 0; j < nVertices; j++)
if (neigh->getDof(j) == edge[0])
break;
for (k = 0; k < nVertices; k++)
if (neigh->getDof(k) == edge[1])
break;
// === If one of the edge DOFs was not found, try to make use of periodic ===
// === DOF associations. First, use the direct associations between DOFs. ===
// === If this will not work, continue with testing on indirect ===
// === associations. ===
if (j >= nVertices) {
for (j = 0; j < nVertices; j++)
if (mesh->associated(neigh->getDof(j, 0), edge[0][0]))
break;
if (j >= nVertices)
for (j = 0; j < nVertices; j++)
if (mesh->indirectlyAssociated(neigh->getDof(j, 0), edge[0][0]))
break;
TEST_EXIT_DBG(j < nVertices)
("Process element %d: DOF %d not found on element %d with nodes (%d %d %d %d)\n",
el->getIndex(), edge[0][0], neigh->getIndex(), neigh->getDof(0, 0),
neigh->getDof(1, 0), neigh->getDof(2, 0), neigh->getDof(3, 0));
}
if (k >= nVertices) {
for (k = 0; k < nVertices; k++)
if (mesh->associated(neigh->getDof(k, 0), edge[1][0]))
break;
if (k >= nVertices)
for (k = 0; k < nVertices; k++)
if (mesh->indirectlyAssociated(neigh->getDof(k, 0), edge[1][0]))
break;
TEST_EXIT_DBG(k < nVertices)
("Process element %d: DOF %d not found on element %d with nodes (%d %d %d %d)\n",
el->getIndex(), edge[1][0], neigh->getIndex(), neigh->getDof(0, 0),

Thomas Witkowski
committed
neigh->getDof(1, 0), neigh->getDof(2, 0), neigh->getDof(3, 0));
int edgeNo = Tetrahedron::edgeOfDofs[j][k];
coarsenList.setCoarsePatch(*n_neigh, edgeNo == 0);
// === Get the direction of the next neighbour. ===
if (next_el[edgeNo][0] != opp_v)
i = next_el[edgeNo][0];
i = next_el[edgeNo][1];
++*n_neigh;
opp_v = neigh_info->getOppVertex(i);
neigh =
dynamic_cast<Tetrahedron*>(const_cast<Element*>(neigh_info->getNeighbour(i)));
neigh_info = stack->traverseNeighbour3d(neigh_info, i);
TEST_EXIT_DBG(neigh == neigh_info->getElement())
("neigh %d and neigh_info->el %d are not identical\n",
neigh->getIndex(), neigh_info->getElement()->getIndex());
/****************************************************************************/
/* we have to go back to the starting element via opp_v values */
/* correct information is produce by get_neigh_on_patch() */
/****************************************************************************/
coarsenList.setOppVertex(*n_neigh, 0, opp_v);
coarsenList.setElement(*n_neigh, neigh);
coarsenList.setElType(*n_neigh, neigh_info->getType());
}
if (neigh == el)
return false;
/****************************************************************************/
/* the domain's boundary is reached; loop back to the starting el */
/****************************************************************************/
int i = *n_neigh - 1;
opp_v = coarsenList.getOppVertex(i, 0);
TEST_EXIT_DBG(neigh_info->getNeighbour(opp_v) && i > 0)
("while looping back domains boundary was reached or i == 0\n");
opp_v = coarsenList.getOppVertex(i--, 0);
neigh_info = stack->traverseNeighbour3d(neigh_info, opp_v);
} while (neigh_info->getElement() != el);
return true;
}
/****************************************************************************/
/* coarse_patch: first rebuild the dofs on the parents then do restriction */
/* of data (if possible) and finally coarsen the patch elements */
/****************************************************************************/
void CoarseningManager3d::coarsenPatch(RCNeighbourList &coarsenList,
FUNCNAME("CoarseningManager3d::coarsenPatch()");
Tetrahedron *el =
dynamic_cast<Tetrahedron*>(const_cast<Element*>(coarsenList.getElement(0)));
DegreeOfFreedom *dof = NULL;
TEST_EXIT_DBG(el)("No element!\n");
TEST_EXIT_DBG(el->getChild(0))("No child in element!\n");
if (mesh->getNumberOfDofs(EDGE)) {
// === Get dof for coarsening edge. ===
int node = mesh->getNode(EDGE);
if (!(dof = const_cast<int*>(el->getDof(node))))

Thomas Witkowski
committed
dof = mesh->getDof(EDGE);
if (mesh->getNumberOfDofs(EDGE) ||
mesh->getNumberOfDofs(FACE) ||
mesh->getNumberOfDofs(CENTER)) {
for (int i = 0; i < n_neigh; i++)
coarsenList.addDOFParent(i, dof);
// === Restrict dof vectors to the parents on the patch. ===
int nrAdmin = mesh->getNumberOfDOFAdmin();
for (int iadmin = 0; iadmin < nrAdmin; iadmin++) {
std::list<DOFIndexedBase*>::iterator it;
DOFAdmin* admin = const_cast<DOFAdmin*>(&mesh->getDofAdmin(iadmin));
std::list<DOFIndexedBase*>::iterator end = admin->endDOFIndexed();
for (it = admin->beginDOFIndexed(); it != end; ++it)
(*it)->coarseRestrict(coarsenList, n_neigh);
// === And now start to coarsen the patch: remove dof's of the coarsening edge. ===
mesh->freeDof(const_cast<int*>(el->getChild(0)->getDof(3)), VERTEX);
mesh->incrementNumberOfVertices(-1);
if (mesh->getNumberOfDofs(EDGE)) {
int node = mesh->getNode(EDGE) + 2;
mesh->freeDof(const_cast<int*>(el->getChild(0)->getDof(node)), EDGE);
mesh->freeDof(const_cast<int*>(el->getChild(1)->getDof(node)), EDGE);
if (coarsenList.getElement(0)->isNewCoordSet())
coarsenList.getElement(0)->eraseNewCoord();
for (int i = 0; i < n_neigh; i++) {
coarsenList.getElement(i)->setNewCoord(NULL);
coarsenTetrahedron(coarsenList, i);
}
// === If the coarsening edge is an interior edge there are n_neigh + 1 edges ===
// === and 2 * n_neigh + 1 faces removed; if it is a boundary edge it is one ===
// === more edge and one more face. ===
if (bound) {
mesh->incrementNumberOfEdges(-(n_neigh + 2));
mesh->incrementNumberOfFaces(-(2 * n_neigh + 1));
} else {
mesh->incrementNumberOfEdges(-(n_neigh + 1));
mesh->incrementNumberOfFaces(-(2 * n_neigh));