// // 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 "RefinementManager.h" #include "Mesh.h" #include "Traverse.h" #include "ElInfo.h" #include "DOFAdmin.h" #include "AdaptStationary.h" #include "AdaptInstationary.h" #include "FixVec.h" #include "RCNeighbourList.h" #include "ProblemStatBase.h" #include "DOFIndexed.h" #include "Projection.h" #include "DOFVector.h" #include "PeriodicBC.h" #include "VertexVector.h" namespace AMDiS { void RefinementManager3d::bisectTetrahedron(RCNeighbourList* ref_list, int index, DegreeOfFreedom* dof[3], DegreeOfFreedom *edge[2]) { Tetrahedron *el = dynamic_cast(const_cast(ref_list->getElement(index))); Tetrahedron *child[2]; int el_type = ref_list->getType(index); child[0] = dynamic_cast(mesh->createNewElement(el)); child[1] = dynamic_cast(mesh->createNewElement(el)); int mark = max(0, el->getMark() - 1); child[0]->setMark(mark); child[1]->setMark(mark); el->setMark(0); /****************************************************************************/ /* transfer hidden data from parent to children */ /****************************************************************************/ el->refineElementData(child[0], child[1], el_type); el->setFirstChild(child[0]); el->setSecondChild(child[1]); if (child[0]->getMark() > 0) doMoreRecursiveRefine = true; int n_vertices = mesh->getGeo(VERTEX); child[0]->setDof(n_vertices - 1, dof[0]); child[1]->setDof(n_vertices - 1, dof[0]); for (int i = 0; i < n_vertices - 1; i++) { child[0]-> setDof(i, const_cast(el->getDof(Tetrahedron::childVertex[el_type][0][i]))); child[1]-> setDof(i, const_cast(el->getDof(Tetrahedron::childVertex[el_type][1][i]))); } /****************************************************************************/ /* there is one more leaf element and two more hierachical elements */ /****************************************************************************/ mesh->incrementNumberOfLeaves(1); mesh->incrementNumberOfElements(2); /****************************************************************************/ /* first set those dof pointers for higher order without neighbour */ /* information */ /****************************************************************************/ if (mesh->getNumberOfDofs(EDGE)) { int node = mesh->getNode(EDGE); /****************************************************************************/ /* set pointers to those dof's that are handed on from the parant */ /****************************************************************************/ child[0]-> setDof(node, const_cast(el->getDof(node + Tetrahedron::childEdge[el_type][0][0]))); child[1]-> setDof(node, const_cast(el->getDof(node + Tetrahedron::childEdge[el_type][1][0]))); child[0]-> setDof(node + 1, const_cast(el->getDof(node + Tetrahedron::childEdge[el_type][0][1]))); child[1]-> setDof(node + 1, const_cast(el->getDof(node + Tetrahedron::childEdge[el_type][1][1]))); child[0]-> setDof(node + 3, const_cast(el->getDof(node + Tetrahedron::childEdge[el_type][0][3]))); child[1]-> setDof(node + 3, const_cast(el->getDof(node + Tetrahedron::childEdge[el_type][1][3]))); /****************************************************************************/ /* adjust pointers to the dof's in the refinement edge */ /****************************************************************************/ if (el->getDof(0) == edge[0]) { child[0]->setDof(node + 2, dof[1]); child[1]->setDof(node + 2, dof[2]); } else { child[0]->setDof(node + 2, dof[2]); child[1]->setDof(node + 2, dof[1]); } } if (mesh->getNumberOfDofs(FACE)) { int node = mesh->getNode(FACE); /****************************************************************************/ /* set pointers to those dof's that are handed on from the parant */ /****************************************************************************/ child[0]->setDof(node + 3, const_cast(el->getDof(node + 1))); child[1]->setDof(node + 3, const_cast(el->getDof(node + 0))); /****************************************************************************/ /* get new dof for the common face of child0 and child1 */ /****************************************************************************/ DegreeOfFreedom *newDOF = mesh->getDof(FACE); child[0]->setDof(node, static_cast(newDOF)); child[1]->setDof(node, static_cast(newDOF)); } if (mesh->getNumberOfDofs(CENTER)) { int node = mesh->getNode(CENTER); child[0]->setDof(node, const_cast(mesh->getDof(CENTER))); child[1]->setDof(node, const_cast(mesh->getDof(CENTER))); } if (mesh->getNumberOfDofs(EDGE) || mesh->getNumberOfDofs(FACE)) fillPatchConnectivity(ref_list, index); } void RefinementManager3d::fillPatchConnectivity(RCNeighbourList* ref_list, int index) { FUNCNAME("RefinementManager3d::fillPatchConnectivity"); Element *el = ref_list->getElement(index), *neigh; int el_type = ref_list->getType(index); int n_type = 0; int dir, adjc, i, j, i_neigh, j_neigh; int node0, node1, oppVertex = 0; for (dir = 0; dir < 2; dir++) { neigh = ref_list->getNeighbourElement(index, dir); if (neigh) { n_type = ref_list->getType(ref_list->getNeighbourNr(index, dir)); oppVertex = ref_list->getOppVertex(index, dir); } if (!neigh || neigh->isLeaf()) { /****************************************************************************/ /* get new dof's in the midedge of the face of el and for the two midpoints*/ /* of the sub-faces. If face is an interior face those pointers have to be */ /* adjusted by the neighbour element also (see below) */ /****************************************************************************/ if (mesh->getNumberOfDofs(EDGE)) { node0 = node1 = mesh->getNode(EDGE); node0 += Tetrahedron::nChildEdge[el_type][0][dir]; node1 += Tetrahedron::nChildEdge[el_type][1][dir]; DegreeOfFreedom *newDOF = mesh->getDof(EDGE); (const_cast(el->getFirstChild()))->setDof(node0, newDOF); (const_cast(el->getSecondChild()))->setDof(node1, newDOF); } if (mesh->getNumberOfDofs(FACE)) { node0 = mesh->getNode(FACE) + Tetrahedron::nChildFace[el_type][0][dir]; (const_cast(el->getFirstChild()))->setDof(node0, mesh->getDof(FACE)); node1 = mesh->getNode(FACE) + Tetrahedron::nChildFace[el_type][1][dir]; (const_cast(el->getSecondChild()))->setDof(node1, mesh->getDof(FACE)); } } else { /* if (!neigh || !neigh->child[0]) */ /****************************************************************************/ /* interior face and neighbour has been refined, look for position at the */ /* refinement edge */ /****************************************************************************/ if (el->getDof(0) == neigh->getDof(0)) { /****************************************************************************/ /* same position at refinement edge */ /****************************************************************************/ adjc = 0; } else { /****************************************************************************/ /* different position at refinement edge */ /****************************************************************************/ adjc = 1; } for (i = 0; i < 2; i++) { j = Tetrahedron::adjacentChild[adjc][i]; i_neigh = Tetrahedron::nChildFace[el_type][i][dir]; j_neigh = Tetrahedron::nChildFace[n_type][j][oppVertex - 2]; /****************************************************************************/ /* adjust dof pointer in the edge in the common face of el and neigh and */ /* the dof pointer in the sub-face child_i-child_j (allocated by neigh!) */ /****************************************************************************/ if (mesh->getNumberOfDofs(EDGE)) { node0 = mesh->getNode(EDGE) + Tetrahedron::nChildEdge[el_type][i][dir]; node1 = mesh->getNode(EDGE) + Tetrahedron::nChildEdge[n_type][j][oppVertex - 2]; TEST_EXIT_DBG(neigh->getChild(j)->getDof(node1)) ("no dof on neighbour %d at node %d\n", neigh->getChild(j)->getIndex(), node1); (const_cast(el->getChild(i)))-> setDof(node0, const_cast(neigh->getChild(j)->getDof(node1))); } if (mesh->getNumberOfDofs(FACE)) { node0 = mesh->getNode(FACE) + i_neigh; node1 = mesh->getNode(FACE) + j_neigh; TEST_EXIT_DBG(neigh->getChild(j)->getDof(node1)) ("No DOF on neighbour %d at node %d!\n", neigh->getChild(j)->getIndex(), node1); (const_cast(el->getChild(i)))-> setDof(node0, const_cast(neigh->getChild(j)->getDof(node1))); } } /* for (i = 0; i < 2; i++) */ } /* else of if (!neigh || !neigh->child[0]) */ } /* for (dir = 0; dir < 2; dir++) */ } int RefinementManager3d::newCoordsFct(ElInfo *el_info) { Element *el = el_info->getElement(); DegreeOfFreedom *edge[2]; ElInfo *elinfo = el_info; int dow = Global::getGeo(WORLD); Projection *projector = el_info->getProjection(0); if (!projector || projector->getType() != VOLUME_PROJECTION) projector = el_info->getProjection(4); if (el->getFirstChild() && projector && (!el->isNewCoordSet())) { WorldVector *new_coord = new WorldVector; for (int j = 0; j < dow; j++) (*new_coord)[j] = (el_info->getCoord(0)[j] + el_info->getCoord(1)[j]) * 0.5; projector->project(*new_coord); el->setNewCoord(new_coord); /****************************************************************************/ /* now, information should be passed on to patch neighbours... */ /* get the refinement patch */ /****************************************************************************/ refList->setElement(0, el); refList->setElType(0, el_info->getType()); int n_neigh = 1; for (int i = 0; i < 2; i++) edge[i] = const_cast(el_info->getElement()->getDof(i)); if (getRefinePatch(&elinfo, edge, 0, refList, &n_neigh)) { // Domain's boundary was reached while looping around the refinement edge. getRefinePatch(&elinfo, edge, 1, refList, &n_neigh); } for (int i = 1; i < n_neigh; i++) { /* start with 1, as list[0]=el */ TEST(!refList->getElement(i)->isNewCoordSet()) ("non-nil new_coord in el %d ref_list[%d] el %d (n_neigh=%d)\n", el->getIndex(), i, refList->getElement(i)->getIndex(), n_neigh); refList->getElement(i)->setNewCoord(el->getNewCoord()); } } return 0; } void RefinementManager3d::setNewCoords(int macroEl) { if (refList) delete refList; refList = new RCNeighbourList(mesh->getMaxEdgeNeigh()); ElInfo *elInfo; if (macroEl == -1) elInfo = stack->traverseFirst(mesh, -1, Mesh::CALL_EVERY_EL_PREORDER | Mesh::FILL_BOUND | Mesh::FILL_COORDS | Mesh::FILL_NEIGH); else elInfo = stack->traverseFirstOneMacro(mesh, macroEl, -1, Mesh::CALL_EVERY_EL_PREORDER | Mesh::FILL_BOUND | Mesh::FILL_COORDS | Mesh::FILL_NEIGH); while (elInfo) { newCoordsFct(elInfo); elInfo = stack->traverseNext(elInfo); } } DegreeOfFreedom RefinementManager3d::refinePatch(DegreeOfFreedom *edge[2], RCNeighbourList* refineList, int n_neigh, bool bound) { Tetrahedron *el = dynamic_cast(const_cast(refineList->getElement(0))); /* first element in the list */ DegreeOfFreedom *dof[3] = {NULL, NULL, NULL}; /****************************************************************************/ /* get new dof's in the refinement edge */ /****************************************************************************/ dof[0] = mesh->getDof(VERTEX); mesh->incrementNumberOfVertices(1); if (mesh->getNumberOfDofs(EDGE)) { dof[1] = mesh->getDof(EDGE); dof[2] = mesh->getDof(EDGE); } for (int i = 0; i < n_neigh; i++) bisectTetrahedron(refineList, i, dof, edge); /****************************************************************************/ /* if there are functions to interpolate data to the finer grid, do so */ /****************************************************************************/ int iadmin; int nrAdmin = mesh->getNumberOfDOFAdmin(); for (iadmin = 0; iadmin < nrAdmin; iadmin++) { std::list::iterator it; DOFAdmin* admin = const_cast(&mesh->getDofAdmin(iadmin)); std::list::iterator end = admin->endDOFIndexed(); for (it = admin->beginDOFIndexed(); it != end; it++) (*it)->refineInterpol(*refineList, n_neigh); } if (!mesh->queryCoarseDOFs()) { /****************************************************************************/ /* if there should be no dof information on interior leaf elements remove */ /* dofs from edges, faces and the centers of parents */ /****************************************************************************/ if (mesh->getNumberOfDofs(EDGE)) { /****************************************************************************/ /* remove dof of the midpoint of the common refinement edge */ /****************************************************************************/ el = dynamic_cast(const_cast(refineList->getElement(0))); mesh->freeDof(const_cast(el->getDof(mesh->getNode(EDGE))), EDGE); } if (mesh->getNumberOfDofs(EDGE) || mesh->getNumberOfDofs(FACE) || mesh->getNumberOfDofs(CENTER)) { for (int i = 0; i < n_neigh; i++) refineList->removeDOFParent(i); } } /****************************************************************************/ /* update the number of edges and faces; depends whether refinement edge */ /* is a boundary edge or not */ /****************************************************************************/ if (bound) { mesh->incrementNumberOfEdges(n_neigh + 2); mesh->incrementNumberOfFaces(2 * n_neigh + 1); } else { mesh->incrementNumberOfEdges(n_neigh + 1); mesh->incrementNumberOfFaces(2 * n_neigh); } return dof[0][0]; } int RefinementManager3d::getRefinePatch(ElInfo **el_info, DegreeOfFreedom *edge[2], int direction, RCNeighbourList* refineList, int *n_neigh) { FUNCNAME("RefinementManager3d::getRefinePatch()"); int localNeighbour = 3 - direction; Tetrahedron *el = dynamic_cast(const_cast((*el_info)->getElement())); if ((*el_info)->getNeighbour(localNeighbour) == NULL) return 1; int oppVertex = (*el_info)->getOppVertex(localNeighbour); int testIndex = (*el_info)->getNeighbour(localNeighbour)->getIndex(); ElInfo *neighInfo = stack->traverseNeighbour3d((*el_info), localNeighbour); int neighElType = neighInfo->getType(); TEST_EXIT_DBG(neighInfo->getElement()->getIndex() == testIndex) ("Should not happen!\n"); Tetrahedron *neigh = dynamic_cast(const_cast(neighInfo->getElement())); int vertices = mesh->getGeo(VERTEX); while (neigh != el) { // === Determine the common edge of the element and its neighbour. === int edgeDof0, edgeDof1; for (edgeDof0 = 0; edgeDof0 < vertices; edgeDof0++) if (neigh->getDof(edgeDof0) == edge[0]) break; for (edgeDof1 = 0; edgeDof1 < vertices; edgeDof1++) if (neigh->getDof(edgeDof1) == edge[1]) break; if (edgeDof0 > 3 || edgeDof1 > 3) { for (edgeDof0 = 0; edgeDof0 < vertices; edgeDof0++) if (mesh->associated(neigh->getDof(edgeDof0, 0), edge[0][0])) break; for (edgeDof1 = 0; edgeDof1 < vertices; edgeDof1++) if (mesh->associated(neigh->getDof(edgeDof1, 0), edge[1][0])) break; if (edgeDof0 > 3 || edgeDof1 > 3) { for (edgeDof0 = 0; edgeDof0 < vertices; edgeDof0++) if (mesh->indirectlyAssociated(neigh->getDof(edgeDof0, 0), edge[0][0])) break; for (edgeDof1 = 0; edgeDof1 < vertices; edgeDof1++) if (mesh->indirectlyAssociated(neigh->getDof(edgeDof1, 0), edge[1][0])) break; TEST_EXIT_DBG(edgeDof0 < vertices && edgeDof1 < vertices) ("dof %d or dof %d not found on element %d with nodes (%d %d %d %d)\n", edge[0][0], edge[1][0], neigh->getIndex(), neigh->getDof(0,0), neigh->getDof(1, 0), neigh->getDof(2, 0), neigh->getDof(3, 0)); } } TEST_EXIT_DBG(edgeDof0 < vertices && edgeDof1 < vertices) ("dof %d or dof %d not found on element %d with nodes (%d %d %d %d)\n", edge[0][0], edge[1][0], neigh->getIndex(), neigh->getDof(0, 0), neigh->getDof(1, 0), neigh->getDof(2, 0), neigh->getDof(3, 0)); int edgeNo = Tetrahedron::edgeOfDofs[edgeDof0][edgeDof1]; if (edgeNo) { // Only 0 can be a compatible commen refinement edge. Thus, neigh has not // a compatible refinement edge. Refine it first. neigh->setMark(max(neigh->getMark(), 1)); neighInfo = refineFunction(neighInfo); // === Now, go to a child at the edge and determine the opposite vertex === // === for this child; continue the looping around the edge with this === // === element. === neighInfo = stack->traverseNext(neighInfo); neighElType = neighInfo->getType(); bool reverseMode = stack->getTraverseFlag().isSet(Mesh::CALL_REVERSE_MODE); switch (edgeNo) { case 1: if (reverseMode) { neighInfo = stack->traverseNext(neighInfo); neighElType = neighInfo->getType(); } oppVertex = (oppVertex == 1 ? 3 : 2); break; case 2: if (reverseMode) { neighInfo = stack->traverseNext(neighInfo); neighElType = neighInfo->getType(); } oppVertex = (oppVertex == 2 ? 1 : 3); break; case 3: if (!reverseMode) { neighInfo = stack->traverseNext(neighInfo); neighElType = neighInfo->getType(); } if (neighElType != 1) oppVertex = (oppVertex == 0 ? 3 : 2); else oppVertex = (oppVertex == 0 ? 3 : 1); break; case 4: if (!reverseMode) { neighInfo = stack->traverseNext(neighInfo); neighElType = neighInfo->getType(); } if (neighElType != 1) oppVertex = (oppVertex == 0 ? 3 : 1); else oppVertex = (oppVertex == 0 ? 3 : 2); break; case 5: if (neighElType != 1) { if (!reverseMode) { neighInfo = stack->traverseNext(neighInfo); neighElType = neighInfo->getType(); } } oppVertex = 3; break; } neigh = dynamic_cast(const_cast(neighInfo->getElement())); } else { // Neigh is compatible devisible. Put neigh to the list of patch elements // and go to next neighbour. TEST_EXIT_DBG(*n_neigh < mesh->getMaxEdgeNeigh()) ("too many neighbours %d in refine patch\n", *n_neigh); refineList->setElement(*n_neigh, neigh); refineList->setElType(*n_neigh, neighElType); // We have to go back to the starting element via oppVertex values. refineList->setOppVertex(*n_neigh, 0, oppVertex); (*n_neigh)++; int i = (oppVertex != 3 ? 3 : 2); if (neighInfo->getNeighbour(i)) { oppVertex = neighInfo->getOppVertex(i); int testIndex = neighInfo->getNeighbour(i)->getIndex(); neighInfo = stack->traverseNeighbour3d(neighInfo, i); TEST_EXIT_DBG(neighInfo->getElement()->getIndex() == testIndex) ("Should not happen!\n"); neighElType = neighInfo->getType(); neigh = dynamic_cast(const_cast(neighInfo->getElement())); } else { break; } } } if (neigh == el) { (*el_info) = neighInfo; return 0; } // The domain's boundary is reached. Loop back to the starting el. int i = *n_neigh - 1; oppVertex = refineList->getOppVertex(i, 0); do { TEST_EXIT_DBG(neighInfo->getNeighbour(oppVertex) && i > 0) ("While looping back domains boundary was reached or i == 0\n"); oppVertex = refineList->getOppVertex(i--, 0); int testIndex = neighInfo->getNeighbour(oppVertex)->getIndex(); neighInfo = stack->traverseNeighbour3d(neighInfo, oppVertex); int edgeDof0, edgeDof1; for (edgeDof0 = 0; edgeDof0 < vertices; edgeDof0++) if (neigh->getDof(edgeDof0) == edge[0]) break; for (edgeDof1 = 0; edgeDof1 < vertices; edgeDof1++) if (neigh->getDof(edgeDof1) == edge[1]) break; TEST_EXIT_DBG(neighInfo->getElement()->getIndex() == testIndex) ("Should not happen!\n"); } while (neighInfo->getElement() != el); (*el_info) = neighInfo; return 1; } ElInfo* RefinementManager3d::refineFunction(ElInfo* el_info) { FUNCNAME("RefinementManager3d::refineFunction()"); if (el_info->getElement()->getMark() <= 0) return el_info; int bound = false; DegreeOfFreedom *edge[2]; // === Get memory for a list of all elements at the refinement edge. === RCNeighbourList *ref_list = new RCNeighbourList(mesh->getMaxEdgeNeigh()); ref_list->setElType(0, el_info->getType()); ref_list->setElement(0, el_info->getElement()); int n_neigh = 1; if (el_info->getProjection(0) && el_info->getProjection(0)->getType() == VOLUME_PROJECTION) newCoords = true; // === Give the refinement edge the right orientation. === if (el_info->getElement()->getDof(0, 0) < el_info->getElement()->getDof(1, 0)) { edge[0] = const_cast(el_info->getElement()->getDof(0)); edge[1] = const_cast(el_info->getElement()->getDof(1)); } else { edge[1] = const_cast(el_info->getElement()->getDof(0)); edge[0] = const_cast(el_info->getElement()->getDof(1)); } // === Traverse and refine the refinement patch. ==== if (getRefinePatch(&el_info, edge, 0, ref_list, &n_neigh)) { // Domain's boundary was reached while looping around the refinement edge getRefinePatch(&el_info, edge, 1, ref_list, &n_neigh); bound = true; } // fill neighbour information inside the patch in the refinement list ref_list->getNeighOnPatch(n_neigh, bound); // ============ Check for periodic boundary ============ DegreeOfFreedom *next_edge[2]; DegreeOfFreedom *first_edge[2] = {edge[0], edge[1]}; DegreeOfFreedom *last_edge[2] = {NULL, NULL}; int n_neigh_periodic; DegreeOfFreedom newDOF = -1; DegreeOfFreedom lastNewDOF = -1; DegreeOfFreedom firstNewDOF = -1; RCNeighbourList *periodicList; std::map::iterator it; std::map::iterator end = mesh->getPeriodicAssociations().end(); while (edge[0] != NULL) { periodicList = ref_list->periodicSplit(edge, next_edge, &n_neigh, &n_neigh_periodic); TEST_EXIT_DBG(periodicList)("periodicList = NULL\n"); newDOF = refinePatch(edge, periodicList, n_neigh_periodic, bound); if (firstNewDOF == -1) firstNewDOF = newDOF; if (lastNewDOF != -1) { for (it = mesh->getPeriodicAssociations().begin(); it != end; ++it) { if (it->second) { if (((*(it->second))[edge[0][0]] == last_edge[0][0] && (*(it->second))[edge[1][0]] == last_edge[1][0]) || ((*(it->second))[edge[0][0]] == last_edge[1][0] && (*(it->second))[edge[1][0]] == last_edge[0][0])) { (*(it->second))[lastNewDOF] = newDOF; (*(it->second))[newDOF] = lastNewDOF; } } } } lastNewDOF = newDOF; last_edge[0] = edge[0]; last_edge[1] = edge[1]; edge[0] = next_edge[0]; edge[1] = next_edge[1]; } if (lastNewDOF != firstNewDOF) { for (it = mesh->getPeriodicAssociations().begin(); it != end; ++it) { if (it->second) { if (((*(it->second))[first_edge[0][0]] == last_edge[0][0] && (*(it->second))[first_edge[1][0]] == last_edge[1][0]) || ((*(it->second))[first_edge[0][0]] == last_edge[1][0] && (*(it->second))[first_edge[1][0]] == last_edge[0][0])) { (*(it->second))[lastNewDOF] = firstNewDOF; (*(it->second))[firstNewDOF] = lastNewDOF; } } } } stack->update(); delete ref_list; return el_info; } }