#include "CoarseningManager2d.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" namespace AMDiS { /****************************************************************************/ /* coarseTriangle: coarses a single element of the coarsening patch; dofs */ /* in the interior of the element are removed; dofs for higher order */ /* at the boundary or the coarsening patch still belong to */ /* the parent. Do not remove them form the mesh!!! */ /****************************************************************************/ void CoarseningManager2d::coarsenTriangle(Triangle *el) { FUNCNAME("CoarseningManager2d::coarseTriangle()"); Triangle *child[2]; child[0] = dynamic_cast<Triangle*>(const_cast<Element*>(el->getChild(0))); child[1] = dynamic_cast<Triangle*>(const_cast<Element*>(el->getChild(1))); TEST_EXIT_DBG(child[0]->getMark() < 0 && child[1]->getMark() < 0) ("element %d with children[%d,%d] must not be coarsend!\n", el->getIndex(), child[0]->getIndex(), child[1]->getIndex()); if (mesh->getNumberOfDOFs(EDGE)) { /****************************************************************************/ /* remove dof from common edge of child[0] and child[1] */ /****************************************************************************/ mesh->freeDOF(const_cast<int*>(child[0]->getDOF(4)), EDGE); } if (mesh->getNumberOfDOFs(CENTER)) { /****************************************************************************/ /* remove dof from the barycenters of child[0] and child[1] */ /****************************************************************************/ int node = mesh->getNode(CENTER); mesh->freeDOF(const_cast<int*>(child[0]->getDOF(node)), CENTER); mesh->freeDOF(const_cast<int*>(child[1]->getDOF(node)), CENTER); } el->coarsenElementData(child[0], child[1]); el->setFirstChild(NULL); el->setSecondChild(NULL); mesh->freeElement(child[0]); mesh->freeElement(child[1]); el->incrementMark(); mesh->incrementNumberOfLeaves(-1); mesh->incrementNumberOfElements(-2); mesh->incrementNumberOfEdges(-1); } /****************************************************************************/ /* coarsenPatch: first rebuild the dofs on the parents then do restriction */ /* of data (if possible) and finally coarsen the patch elements */ /****************************************************************************/ void CoarseningManager2d::coarsenPatch(RCNeighbourList *coarsenList, int n_neigh, int bound) { Triangle *el = dynamic_cast<Triangle*>(const_cast<Element*>(coarsenList->getElement(0))); Triangle *neigh = dynamic_cast<Triangle*>(const_cast<Element*>(coarsenList->getElement(1))); DegreeOfFreedom *dof[3]; dof[0] = const_cast<int*>(el->getChild(0)->getDOF(2)); if (mesh->getNumberOfDOFs(EDGE)) { dof[1] = const_cast<int*>(el->getChild(0)->getDOF(3)); dof[2] = const_cast<int*>(el->getChild(1)->getDOF(4)); } else { dof[1] = dof[2] = 0; } int node = mesh->getNode(EDGE); if (mesh->getNumberOfDOFs(EDGE)) { /****************************************************************************/ /* get new dof on el at the midpoint of the coarsening edge */ /****************************************************************************/ if (!el->getDOF(node + 2)) { el->setDOF(node + 2, mesh->getDOF(EDGE)); if (neigh) { neigh->setDOF(node + 2, const_cast<int*>(el->getDOF(node+2))); } } } if (mesh->getNumberOfDOFs(EDGE) || mesh->getNumberOfDOFs(CENTER)) { coarsenList->addDOFParents(n_neigh); } /****************************************************************************/ /* 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); } } coarsenTriangle(el); if (neigh) coarsenTriangle(neigh); /****************************************************************************/ /* now, remove those dofs in the coarcening edge */ /****************************************************************************/ mesh->freeDOF(dof[0], VERTEX); if (mesh->getNumberOfDOFs(EDGE)) { mesh->freeDOF(dof[1], EDGE); mesh->freeDOF(dof[2], EDGE); } mesh->incrementNumberOfVertices(-1); mesh->incrementNumberOfEdges(-1); } int CoarseningManager2d::coarsenFunction(ElInfo *el_info) { Triangle *el = dynamic_cast<Triangle*>(const_cast<Element*>(el_info->getElement())); DegreeOfFreedom *edge[2]; int n_neigh, bound = 0; RCNeighbourList coarse_list(2); coarse_list.setCoarseningManager(this); if (el->getMark() >= 0) return 0; // el must not be coarsend, return if (!(el->getChild(0))) return 0; // single leaves don't get coarsened if (el->getChild(0)->getMark() >= 0 || el->getChild(1)->getMark() >= 0) { /****************************************************************************/ /* one of the children must not be coarsend; return :-( */ /****************************************************************************/ el->setMark(0); return 0; } if (!el->getChild(0)->isLeaf() || !el->getChild(1)->isLeaf()) { /****************************************************************************/ /* one of the children is not a leaf element; try again later on */ /****************************************************************************/ doMore = true; return 0; } /****************************************************************************/ /* give the refinement edge the right orientation */ /****************************************************************************/ if (el->getDOF(0,0) < el->getDOF(1,0)) { edge[0] = const_cast<int*>(el->getDOF(0)); edge[1] = const_cast<int*>(el->getDOF(1)); } else { edge[1] = const_cast<int*>(el->getDOF(0)); edge[0] = const_cast<int*>(el->getDOF(1)); } coarse_list.setElement(0, el, true); n_neigh = 1; if (coarse_list.setElement(1, el_info->getNeighbour(2))) { n_neigh = 2; coarse_list.setCoarsePatch(1, el_info->getOppVertex(2) == 2); } /****************************************************************************/ /* check wether we can coarsen the patch or not */ /****************************************************************************/ // ========================================================================== // === check for periodic boundary ========================================== // ========================================================================== if (coarse_list.doCoarsePatch(n_neigh)) { int n_neigh_periodic; DegreeOfFreedom *next_edge[2]; RCNeighbourList *periodicList; while (edge[0] != NULL) { periodicList = coarse_list.periodicSplit(edge, next_edge, &n_neigh, &n_neigh_periodic); TEST_EXIT_DBG(periodicList)("periodicList = NULL\n"); coarsenPatch(periodicList, n_neigh_periodic, bound); edge[0] = next_edge[0]; edge[1] = next_edge[1]; } } return 0; } }